fix(localize): allow multiple characters for currency symbols

This commit is contained in:
qa46hx 2019-09-27 14:47:36 +02:00
parent 9e39c6c19c
commit 20b77a40b1
4 changed files with 67 additions and 47 deletions

View file

@ -26,16 +26,12 @@ export function formatNumberToParts(number, options) {
} }
let formattedParts = []; let formattedParts = [];
const formattedNumber = Intl.NumberFormat(computedLocale, options).format(parsedNumber); const formattedNumber = Intl.NumberFormat(computedLocale, options).format(parsedNumber);
const regexSymbol = /[A-Z.,\s0-9]/; const regexCurrency = /[.,\s0-9]/;
const regexCode = /[A-Z]/; const regexMinusSign = /[-]/; // U+002D, Hyphen-Minus, -
// U+002D, Hyphen-Minus, -
const regexMinusSign = /[-]/;
const regexNum = /[0-9]/; const regexNum = /[0-9]/;
const regexSeparator = /[.,]/; const regexSeparator = /[.,]/;
const regexSpace = /[\s]/; const regexSpace = /[\s]/;
let currencyCode = ''; let currency = '';
let numberPart = ''; let numberPart = '';
let fraction = false; let fraction = false;
for (let i = 0; i < formattedNumber.length; i += 1) { for (let i = 0; i < formattedNumber.length; i += 1) {
@ -47,34 +43,17 @@ export function formatNumberToParts(number, options) {
if (regexNum.test(formattedNumber[i])) { if (regexNum.test(formattedNumber[i])) {
numberPart += formattedNumber[i]; numberPart += formattedNumber[i];
} }
// detect currency symbol
if (!regexSymbol.test(formattedNumber[i]) && !regexMinusSign.test(formattedNumber[i])) { // detect currency (symbol or code)
// Write number grouping if (!regexCurrency.test(formattedNumber[i]) && !regexMinusSign.test(formattedNumber[i])) {
if (numberPart && !fraction) { currency += formattedNumber[i];
formattedParts.push({ type: 'integer', value: numberPart });
numberPart = '';
} else if (numberPart) {
formattedParts.push({ type: 'fraction', value: numberPart });
numberPart = '';
}
formattedParts.push({ type: 'currency', value: formattedNumber[i] });
} }
// detect currency code // push when another character then currency or end of loop
if (regexCode.test(formattedNumber[i])) { if ((regexCurrency.test(formattedNumber[i]) || formattedNumber.length === i + 1) && currency) {
currencyCode += formattedNumber[i]; formattedParts.push({ type: 'currency', value: currency });
// Write number grouping currency = '';
if (numberPart && !fraction) {
formattedParts.push({ type: 'integer', value: numberPart });
numberPart = '';
} else if (numberPart) {
formattedParts.push({ type: 'fraction', value: numberPart });
numberPart = '';
}
if (currencyCode.length === 3) {
formattedParts.push({ type: 'currency', value: currencyCode });
currencyCode = '';
}
} }
// detect dot and comma separators // detect dot and comma separators
if (regexSeparator.test(formattedNumber[i])) { if (regexSeparator.test(formattedNumber[i])) {
// Write number grouping // Write number grouping

View file

@ -27,7 +27,7 @@ export function normalizeIntl(formattedParts, options, _locale) {
normalize = forceSpaceInsteadOfZeroForGroup(normalize); normalize = forceSpaceInsteadOfZeroForGroup(normalize);
} }
// Force space between currency code and number // Force space between currency code and number
if (_locale === 'en-GB' || _locale === 'en-US' || _locale === 'en-AU') { if (_locale === 'en-GB' || _locale === 'en-US' || _locale === 'en-AU' || _locale === 'en-PH') {
normalize = forceSpaceBetweenCurrencyCodeAndNumber(normalize, options); normalize = forceSpaceBetweenCurrencyCodeAndNumber(normalize, options);
} }
// Force missing Japanese Yen symbol // Force missing Japanese Yen symbol

View file

@ -24,7 +24,7 @@ describe('formatNumber', () => {
it('can display currency as symbol', () => { it('can display currency as symbol', () => {
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€123,456.79'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€123,456.79');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('$123,456.79'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('US$123,456.79');
}); });
it('uses minus U+2212 (and not dash) to indicate negative numbers ', () => { it('uses minus U+2212 (and not dash) to indicate negative numbers ', () => {
@ -187,8 +187,8 @@ describe('formatNumber', () => {
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79'); expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457'); expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€123,456.79'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€123,456.79');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('$123,456.79'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('US$123,456.79');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('¥123,457'); expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('JP¥123,457');
}); });
}); });
@ -223,8 +223,8 @@ describe('formatNumber', () => {
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79'); expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('USD 123,456.79');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457'); expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('JPY 123,457');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€123,456.79'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€123,456.79');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('$123,456.79'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('US$123,456.79');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('¥123,457'); expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('JP¥123,457');
}); });
}); });
@ -235,8 +235,8 @@ describe('formatNumber', () => {
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD'); expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY'); expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€ 123.456,79'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€ 123.456,79');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('$ 123.456,79'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('US$ 123.456,79');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('¥ 123.457'); expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('JP¥ 123.457');
}); });
}); });
@ -247,8 +247,8 @@ describe('formatNumber', () => {
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD'); expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123.456,79 USD');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY'); expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123.457 JPY');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€ 123.456,79'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('€ 123.456,79');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('$ 123.456,79'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('US$ 123.456,79');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('¥ 123.457'); expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('JP¥ 123.457');
}); });
}); });
@ -259,19 +259,19 @@ describe('formatNumber', () => {
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD'); expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY'); expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('123 456,79 €'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('123 456,79 €');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('123 456,79 $'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('123 456,79 $US');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('123 457 ¥'); expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('123 457 ¥');
}); });
}); });
describe('fr-BE', () => { describe('fr-BE', () => {
it('supports basics', () => { it('supports basics', () => {
localize.locale = 'fr-FR'; localize.locale = 'fr-BE';
expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR'); expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR');
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD'); expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY'); expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('123 456,79 €'); expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('123 456,79 €');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('123 456,79 $'); expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('123 456,79 $US');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('123 457 ¥'); expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('123 457 ¥');
}); });
}); });
@ -293,5 +293,19 @@ describe('formatNumber', () => {
expect(formatNumber(1234.567, currencyCode('EUR'))).to.equal('1 234,57 EUR'); expect(formatNumber(1234.567, currencyCode('EUR'))).to.equal('1 234,57 EUR');
}); });
}); });
describe('cs-CZ', () => {
it('supports basics', () => {
localize.locale = 'cs-CZ';
expect(formatNumber(123456.789, currencyCode('EUR'))).to.equal('123 456,79 EUR');
expect(formatNumber(123456.789, currencyCode('USD'))).to.equal('123 456,79 USD');
expect(formatNumber(123456.789, currencyCode('JPY'))).to.equal('123 457 JPY');
expect(formatNumber(123456.789, currencyCode('CZK'))).to.equal('123 456,79 CZK');
expect(formatNumber(123456.789, currencySymbol('EUR'))).to.equal('123 456,79 €');
expect(formatNumber(123456.789, currencySymbol('USD'))).to.equal('123 456,79 US$');
expect(formatNumber(123456.789, currencySymbol('JPY'))).to.equal('123 457 JP¥');
expect(formatNumber(123456.789, currencySymbol('CZK'))).to.equal('123 456,79 Kč');
});
});
}); });
}); });

View file

@ -17,7 +17,34 @@ const stringifyParts = parts => parts.map(part => part.value).join('');
describe('formatNumberToParts', () => { describe('formatNumberToParts', () => {
afterEach(localizeTearDown); afterEach(localizeTearDown);
describe("style: 'currency'", () => { describe("style: 'currency symbol'", () => {
const specs = [
['en-GB', 'EUR', 1234.5, [c('€'), i('1'), g(','), i('234'), d('.'), f('50')]],
['en-GB', 'USD', 1234.5, [c('US$'), i('1'), g(','), i('234'), d('.'), f('50')]],
['nl-NL', 'EUR', 1234.5, [c('€'), l(' '), i('1'), g('.'), i('234'), d(','), f('50')]],
['nl-NL', 'USD', 1234.5, [c('US$'), l(' '), i('1'), g('.'), i('234'), d(','), f('50')]],
['nl-BE', 'EUR', 1234.5, [c('€'), l(' '), i('1'), g('.'), i('234'), d(','), f('50')]],
['nl-BE', 'USD', 1234.5, [c('US$'), l(' '), i('1'), g('.'), i('234'), d(','), f('50')]],
['fr-FR', 'EUR', 1234.5, [i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('€')]],
['fr-FR', 'USD', 1234.5, [i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('$US')]],
['fr-BE', 'EUR', 1234.5, [i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('€')]],
['fr-BE', 'USD', 1234.5, [i('1'), g(' '), i('234'), d(','), f('50'), l(' '), c('$US')]],
];
specs.forEach(([locale, currency, amount, expectedResult]) => {
it(`formats ${locale} ${currency} ${amount} as "${stringifyParts(expectedResult)}"`, () => {
localize.locale = locale;
expect(
formatNumberToParts(amount, {
style: 'currency',
currency,
}),
).to.deep.equal(expectedResult);
});
});
});
describe("style: 'currency code'", () => {
const specs = [ const specs = [
['en-GB', 'EUR', 1234.5, [c('EUR'), l(' '), i('1'), g(','), i('234'), d('.'), f('50')]], ['en-GB', 'EUR', 1234.5, [c('EUR'), l(' '), i('1'), g(','), i('234'), d('.'), f('50')]],
['en-GB', 'EUR', -1234.5, [m, c('EUR'), l(' '), i('1'), g(','), i('234'), d('.'), f('50')]], ['en-GB', 'EUR', -1234.5, [m, c('EUR'), l(' '), i('1'), g(','), i('234'), d('.'), f('50')]],