Skip to content

Commit 5a5e783

Browse files
author
Michael Jordan
committed
Refactor to use a static map of locale, group and decimal separator info
1 parent f31ff9d commit 5a5e783

File tree

1 file changed

+160
-56
lines changed

1 file changed

+160
-56
lines changed

packages/@react-stately/numberfield/src/useNumberFieldState.ts

Lines changed: 160 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,149 @@ import {NumberFieldProps} from '@react-types/numberfield';
1616
import {NumberFormatter, NumberParser} from '@internationalized/number';
1717
import {useCallback, useMemo, useState} from 'react';
1818

19-
let supportedLocales: string[] = [
20-
'ar-AE', // Arabic (United Arab Emirates)
21-
'bg-BG', // Bulgarian (Bulgaria)
22-
'zh-CN', // Chinese (Simplified)
23-
'zh-TW', // Chinese (Traditional)
24-
'hr-HR', // Croatian (Croatia)
25-
'cs-CZ', // Czech (Czech Republic)
26-
'da-DK', // Danish (Denmark)
27-
'nl-NL', // Dutch (Netherlands)
28-
'en-GB', // English (Great Britain)
29-
'en-US', // English (United States)
30-
'et-EE', // Estonian (Estonia)
31-
'fi-FI', // Finnish (Finland)
32-
'fr-CA', // French (Canada)
33-
'fr-FR', // French (France)
34-
'de-DE', // German (Germany)
35-
'el-GR', // Greek (Greece)
36-
'he-IL', // Hebrew (Israel)
37-
'hu-HU', // Hungarian (Hungary)
38-
'it-IT', // Italian (Italy)
39-
'ja-JP', // Japanese (Japan)
40-
'ko-KR', // Korean (Korea)
41-
'lv-LV', // Latvian (Latvia)
42-
'lt-LT', // Lithuanian (Lithuania)
43-
'no-NO', // Norwegian (Norway)
44-
'pl-PL', // Polish (Poland)
45-
'pt-BR', // Portuguese (Brazil)
46-
'ro-RO', // Romanian (Romania)
47-
'ru-RU', // Russian (Russia)
48-
'sr-RS', // Serbian (Serbia)
49-
'sk-SK', // Slovakian (Slovakia)
50-
'sl-SI', // Slovenian (Slovenia)
51-
'es-ES', // Spanish (Spain)
52-
'sv-SE', // Swedish (Sweden)
53-
'tr-TR', // Turkish (Turkey)
54-
'uk-UA' // Ukrainian (Ukraine)
55-
];
19+
20+
let supportedLocales = new Map<string, {groupSeparator: string, decimalSeparator: string}>([
21+
[
22+
'ar-AE', // Arabic (United Arab Emirates)
23+
{groupSeparator: ',', decimalSeparator: '.'}
24+
],
25+
[
26+
'bg-BG', // Bulgarian (Bulgaria)
27+
{groupSeparator: '', decimalSeparator: ','}
28+
],
29+
[
30+
'zh-CN', // Chinese (Simplified)
31+
{groupSeparator: ',', decimalSeparator: '.'}
32+
],
33+
[
34+
'zh-TW', // Chinese (Traditional)
35+
{groupSeparator: ',', decimalSeparator: '.'}
36+
],
37+
[
38+
'hr-HR', // Croatian (Croatia)
39+
{groupSeparator: '.', decimalSeparator: ','}
40+
],
41+
[
42+
'cs-CZ', // Czech (Czech Republic)
43+
{groupSeparator: ' ', decimalSeparator: ','}
44+
],
45+
[
46+
'da-DK', // Danish (Denmark)
47+
{groupSeparator: '.', decimalSeparator: ','}
48+
],
49+
[
50+
'nl-NL', // Dutch (Netherlands)
51+
{groupSeparator: '.', decimalSeparator: ','}
52+
],
53+
[
54+
'en-GB', // English (Great Britain)
55+
{groupSeparator: ',', decimalSeparator: '.'}
56+
],
57+
[
58+
'en-US', // English (United States)
59+
{groupSeparator: ',', decimalSeparator: '.'}
60+
],
61+
[
62+
'et-EE', // Estonian (Estonia)
63+
{groupSeparator: '', decimalSeparator: ','}
64+
],
65+
[
66+
'fi-FI', // Finnish (Finland)
67+
{groupSeparator: ' ', decimalSeparator: ','}
68+
],
69+
[
70+
'fr-CA', // French (Canada)
71+
{groupSeparator: ' ', decimalSeparator: ','}
72+
],
73+
[
74+
'fr-FR', // French (France)
75+
{groupSeparator: ' ', decimalSeparator: ','}
76+
],
77+
[
78+
'de-DE', // German (Germany)
79+
{groupSeparator: '.', decimalSeparator: ','}
80+
],
81+
[
82+
'el-GR', // Greek (Greece)
83+
{groupSeparator: '.', decimalSeparator: ','}
84+
],
85+
[
86+
'he-IL', // Hebrew (Israel)
87+
{groupSeparator: ',', decimalSeparator: '.'}
88+
],
89+
[
90+
'hu-HU', // Hungarian (Hungary)
91+
{groupSeparator: ' ', decimalSeparator: ','}
92+
],
93+
[
94+
'it-IT', // Italian (Italy)
95+
{groupSeparator: '.', decimalSeparator: ','}
96+
],
97+
[
98+
'ja-JP', // Japanese (Japan)
99+
{groupSeparator: ',', decimalSeparator: '.'}
100+
],
101+
[
102+
'ko-KR', // Korean (Korea)
103+
{groupSeparator: ',', decimalSeparator: '.'}
104+
],
105+
[
106+
'lv-LV', // Latvian (Latvia)
107+
{groupSeparator: '', decimalSeparator: ','}
108+
],
109+
[
110+
'lt-LT', // Lithuanian (Lithuania)
111+
{groupSeparator: ' ', decimalSeparator: ','}
112+
],
113+
[
114+
'no-NO', // Norwegian (Norway)
115+
{groupSeparator: ' ', decimalSeparator: ','}
116+
],
117+
[
118+
'pl-PL', // Polish (Poland)
119+
{groupSeparator: '', decimalSeparator: ','}
120+
],
121+
[
122+
'pt-BR', // Portuguese (Brazil)
123+
{groupSeparator: '.', decimalSeparator: ','}
124+
],
125+
[
126+
'ro-RO', // Romanian (Romania)
127+
{groupSeparator: '.', decimalSeparator: ','}
128+
],
129+
[
130+
'ru-RU', // Russian (Russia)
131+
{groupSeparator: ' ', decimalSeparator: ','}
132+
],
133+
[
134+
'sr-RS', // Serbian (Serbia)
135+
{groupSeparator: '.', decimalSeparator: ','}
136+
],
137+
[
138+
'sk-SK', // Slovakian (Slovakia)
139+
{groupSeparator: ' ', decimalSeparator: ','}
140+
],
141+
[
142+
'sl-SI', // Slovenian (Slovenia)
143+
{groupSeparator: '.', decimalSeparator: ','}
144+
],
145+
[
146+
'es-ES', // Spanish (Spain)
147+
{groupSeparator: '', decimalSeparator: ','}
148+
],
149+
[
150+
'sv-SE', // Swedish (Sweden)
151+
{groupSeparator: ' ', decimalSeparator: ','}
152+
],
153+
[
154+
'tr-TR', // Turkish (Turkey)
155+
{groupSeparator: '.', decimalSeparator: ','}
156+
],
157+
[
158+
'uk-UA', // Ukrainian (Ukraine)
159+
{groupSeparator: ' ', decimalSeparator: ','}
160+
]
161+
]);
56162

57163
export interface NumberFieldState extends FormValidationState {
58164
/**
@@ -305,36 +411,34 @@ export function useNumberFieldState(
305411
let validate = (value: string) => numberParser.isValidPartialNumber(value, minValue, maxValue);
306412

307413
let parseValueInAnySupportedLocale = (value: string) => {
308-
let locales = supportedLocales.filter(localeCode => localeCode !== locale);
309-
locales.unshift(locale);
310-
let localeCodes = locales.map(localeCode => {
311-
let numberFormatter = new NumberFormatter(localeCode, formatOptions);
312-
return {
313-
locale: localeCode,
314-
groupSeparator: numberFormatter.formatToParts(1111).find(part => part.type === 'group')?.value,
315-
decimalSeparator: numberFormatter.formatToParts(1.1).find(part => part.type === 'decimal')?.value
316-
};
317-
});
414+
let currentLocaleCode = [...supportedLocales].find(([localeCode]) => localeCode === locale) || ['en-US', {groupSeparator: ',', decimalSeparator: '.'}];
415+
let localesWithDifferentSeparators = [...supportedLocales].filter(([, separators]) => separators.groupSeparator !== currentLocaleCode?.[1].groupSeparator && separators.decimalSeparator !== currentLocaleCode?.[1].decimalSeparator);
416+
let locales = new Map(
417+
[
418+
currentLocaleCode,
419+
...localesWithDifferentSeparators
420+
]
421+
);
318422

319423
let _parsedValue = NaN;
320-
for (let localeCode of localeCodes) {
321-
let _numberParser = new NumberParser(localeCode.locale, formatOptions);
424+
for (let [localeCode, separators] of locales) {
425+
let _numberParser = new NumberParser(localeCode, formatOptions);
322426
if (
323427
(
324-
(localeCode.groupSeparator && value.includes(localeCode.groupSeparator)) ||
325-
(localeCode.decimalSeparator && value.includes(localeCode.decimalSeparator))
428+
value.includes(separators.groupSeparator) ||
429+
value.includes(separators.decimalSeparator)
326430
) &&
327-
value.lastIndexOf(localeCode.groupSeparator ?? '') > value.lastIndexOf(localeCode.decimalSeparator ?? '')
431+
value.lastIndexOf(separators.groupSeparator) > value.lastIndexOf(separators.decimalSeparator)
328432
) {
329-
if (value.lastIndexOf(localeCode.decimalSeparator ?? '') === -1) {
330-
let pv = _numberParser.parse(value.replaceAll(localeCode.groupSeparator ?? '', ''));
331-
if (!isNaN(pv) && parseFloat(value.replaceAll(localeCode.groupSeparator ?? '', '')) === pv) {
433+
if (value.lastIndexOf(separators.decimalSeparator) === -1) {
434+
let pv = _numberParser.parse(value.replaceAll(separators.groupSeparator, ''));
435+
if (!isNaN(pv) && parseFloat(value.replaceAll(separators.groupSeparator, '')) === pv) {
332436
return pv;
333437
}
334438
}
335439
continue;
336440
}
337-
_parsedValue = _numberParser.parse(value.replaceAll(localeCode.groupSeparator ?? '', ''));
441+
_parsedValue = _numberParser.parse(value.replaceAll(separators.groupSeparator, ''));
338442
if (!isNaN(_parsedValue)) {
339443
return _parsedValue;
340444
}

0 commit comments

Comments
 (0)