Skip to content

Commit dbcf2fd

Browse files
authored
fix issue with locale formatting (#1106)
1 parent 019da2f commit dbcf2fd

File tree

2 files changed

+67
-17
lines changed

2 files changed

+67
-17
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { afterEach, describe, expect, it } from 'vitest'
2+
import { formatTAmount } from './format'
3+
4+
const originalNavigatorDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'navigator')
5+
6+
function mockNavigatorLanguage(language: string): void {
7+
Object.defineProperty(globalThis, 'navigator', {
8+
configurable: true,
9+
value: { language }
10+
})
11+
}
12+
13+
afterEach(() => {
14+
if (originalNavigatorDescriptor) {
15+
Object.defineProperty(globalThis, 'navigator', originalNavigatorDescriptor)
16+
return
17+
}
18+
19+
Reflect.deleteProperty(globalThis, 'navigator')
20+
})
21+
22+
describe('formatTAmount', () => {
23+
it('keeps compact USD output in en-US style even when the browser locale differs', () => {
24+
mockNavigatorLanguage('nl-NL')
25+
26+
expect(
27+
formatTAmount({
28+
value: 1_350_000,
29+
decimals: 0,
30+
symbol: 'USD',
31+
options: {
32+
shouldCompactValue: true,
33+
minimumFractionDigits: 0,
34+
maximumFractionDigits: 2
35+
}
36+
})
37+
).toBe('$1.35M')
38+
})
39+
40+
it('keeps non-compact USD output in en-US style even when the browser locale differs', () => {
41+
mockNavigatorLanguage('nl-NL')
42+
43+
expect(
44+
formatTAmount({
45+
value: 1234.5,
46+
decimals: 0,
47+
symbol: 'USD',
48+
options: {
49+
shouldCompactValue: false,
50+
minimumFractionDigits: 2,
51+
maximumFractionDigits: 2
52+
}
53+
})
54+
).toBe('$1,234.50')
55+
})
56+
})

src/components/shared/utils/format.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ type TFormatCurrencyWithPrecision = {
177177
amount: number
178178
maxFractionDigits: number
179179
intlOptions: Intl.NumberFormatOptions
180-
locale: string
180+
locales: string[]
181181
symbol: string
182182
}
183183

@@ -256,10 +256,10 @@ function formatCurrencyWithPrecision({
256256
amount,
257257
maxFractionDigits,
258258
intlOptions,
259-
locale,
259+
locales,
260260
symbol
261261
}: TFormatCurrencyWithPrecision): string {
262-
return new Intl.NumberFormat([locale, 'en-US'], {
262+
return new Intl.NumberFormat(locales, {
263263
...intlOptions,
264264
maximumFractionDigits: Math.max(maxFractionDigits, intlOptions.maximumFractionDigits || maxFractionDigits)
265265
})
@@ -277,13 +277,7 @@ export function formatLocalAmount(amount: number, decimals: number, symbol: stri
277277
** - If smbol is percent, then we will display as `12 %` or `12%` (US)
278278
** - If symbol is any other token, we will display as `123,79 USDC` or `USDC 123.79` (US)
279279
**********************************************************************************************/
280-
let locale = 'en-US'
281-
if (typeof navigator !== 'undefined') {
282-
locale = navigator.language || 'fr-FR'
283-
}
284-
const locales = []
285-
locales.push('en-US')
286-
locales.push(locale)
280+
const locales = resolveLocales()
287281

288282
const { shouldDisplaySymbol, shouldCompactValue, ...rest } = options
289283
const intlOptions: Intl.NumberFormatOptions = rest
@@ -298,7 +292,7 @@ export function formatLocalAmount(amount: number, decimals: number, symbol: stri
298292
}
299293

300294
if (isPercent && amount > 5 && shouldCompactValue) {
301-
return `> ${new Intl.NumberFormat([locale, 'en-US'], intlOptions).format(5).replace('EUR', symbol)}`
295+
return `> ${new Intl.NumberFormat(locales, intlOptions).format(5).replace('EUR', symbol)}`
302296
}
303297

304298
/**********************************************************************************************
@@ -307,7 +301,7 @@ export function formatLocalAmount(amount: number, decimals: number, symbol: stri
307301
** - 267839372 would be `267,84 M` or `267.84M` (US)
308302
**********************************************************************************************/
309303
if (amount > 10_000 && shouldCompactValue) {
310-
return new Intl.NumberFormat([locale, 'en-US'], {
304+
return new Intl.NumberFormat(locales, {
311305
...intlOptions,
312306
notation: 'compact',
313307
compactDisplay: 'short'
@@ -327,7 +321,7 @@ export function formatLocalAmount(amount: number, decimals: number, symbol: stri
327321
amount,
328322
maxFractionDigits: 2,
329323
intlOptions,
330-
locale,
324+
locales,
331325
symbol
332326
})
333327
}
@@ -345,7 +339,7 @@ export function formatLocalAmount(amount: number, decimals: number, symbol: stri
345339
amount,
346340
maxFractionDigits: 8,
347341
intlOptions,
348-
locale,
342+
locales,
349343
symbol
350344
})
351345
}
@@ -354,19 +348,19 @@ export function formatLocalAmount(amount: number, decimals: number, symbol: stri
354348
amount,
355349
maxFractionDigits: 12,
356350
intlOptions,
357-
locale,
351+
locales,
358352
symbol
359353
})
360354
}
361355
return formatCurrencyWithPrecision({
362356
amount,
363357
maxFractionDigits: decimals,
364358
intlOptions,
365-
locale,
359+
locales,
366360
symbol
367361
})
368362
}
369-
return new Intl.NumberFormat([locale, 'en-US'], intlOptions).format(amount).replace('EUR', symbol)
363+
return new Intl.NumberFormat(locales, intlOptions).format(amount).replace('EUR', symbol)
370364
}
371365

372366
export function formatTAmount(props: TAmount): string {

0 commit comments

Comments
 (0)