Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Commit

Permalink
fixes #221: normalize spacing around currency codes
Browse files Browse the repository at this point in the history
  • Loading branch information
caridy committed Nov 17, 2016
1 parent af235a6 commit 854902f
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 3 deletions.
42 changes: 39 additions & 3 deletions src/11.numberformat.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,42 @@ function PartitionNumberPattern(numberFormat, x) {
ild = data.symbols[nums] || data.symbols.latn,
pattern;

// web-compat issue #221
function preprocessCurrencyCode(currencyCode, pattern, beginIndex, endIndex) {
/**
* http://cldr.unicode.org/translation/number-patterns
* This method solves a particular issues related to this note from the link above:
*
* ¤ This will be replaced by a currency symbol, such as $ or USD. Note: by default a space is automatically
* added between letters in a currency symbol and adjacent numbers. So you don't need to add a space between
* them if your language writes "$12" but "USD 12".
*
* Specifically, this polyfill doesn't support currency names (it is not part of the data we produce from CLDR), in
* which case we fallback to using the currency code. The same applies if the currency symbol is not available. This
* left us with two skeletons that require some preprocessing. The problem is that there are locales that do not have
* a symbol, and they already assume an space is needed between the ¤ and the value. On top of that, there are locales
* in which the symbol goes before or after the value. This function takes all that into consideration and tries to
* produce the most accurate currency code, value and non-breaking space combination by analysing the skeleton.
*
* Empirical rules:
* - If the skeleton already have the non-breaking space, we do nothing because it is a locale without a currency symbol
* - If the pattern ends on the last character, the space could be a suffix of the {currency} token, this condition is
* more reliable than testing the first character because sometimes there is a minus sign.
*/
const NON_BREAKING_SPACE = '\xa0'; // Non-breakable space is char 0xa0 (160 dec)
if (endIndex === pattern.length && beginIndex > 0) {
const prevCharCode = pattern.charCodeAt(beginIndex - 1);
if (prevCharCode !== NON_BREAKING_SPACE) {
return NON_BREAKING_SPACE + currencyCode;
}
} else if (pattern.length > endIndex + 1) {
if (pattern.charCodeAt(endIndex + 1) !== NON_BREAKING_SPACE) {
return currencyCode + NON_BREAKING_SPACE;
}
}
return currencyCode;
}

// 1. If x is not NaN and x < 0, then:
if (!isNaN(x) && x < 0) {
// a. Let x be -x.
Expand Down Expand Up @@ -685,17 +721,17 @@ function PartitionNumberPattern(numberFormat, x) {
// iii. If numberFormat.[[currencyDisplay]] is "code", then
if (internal['[[currencyDisplay]]'] === "code") {
// 1. Let cd be currency.
cd = currency;
cd = preprocessCurrencyCode(currency, pattern, beginIndex, endIndex);
}
// iv. Else if numberFormat.[[currencyDisplay]] is "symbol", then
else if (internal['[[currencyDisplay]]'] === "symbol") {
// 1. Let cd be an ILD string representing currency in short form. If the implementation does not have such a representation of currency, use currency itself.
cd = data.currencies[currency] || currency;
cd = data.currencies[currency] || preprocessCurrencyCode(currency, pattern, beginIndex, endIndex);
}
// v. Else if numberFormat.[[currencyDisplay]] is "name", then
else if (internal['[[currencyDisplay]]'] === "name") {
// 1. Let cd be an ILD string representing currency in long form. If the implementation does not have such a representation of currency, then use currency itself.
cd = currency;
cd = preprocessCurrencyCode(currency, pattern, beginIndex, endIndex);
}
// vi. Add new part record { [[type]]: "currency", [[value]]: cd } as a new element of the list result.
arrPush.call(result, { '[[type]]': 'currency', '[[value]]': cd });
Expand Down
30 changes: 30 additions & 0 deletions tests/sanity.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,33 @@ assert(new IntlPolyfill.DateTimeFormat('en-us', {
assert(new IntlPolyfill.DateTimeFormat('en-GB', {
hour: 'numeric'
}).format(new Date(2016, 0, 1, 6)), '6', 'single second should be 2-digit');

// issue #221
assert(new IntlPolyfill.NumberFormat('es-MX', {
style: 'currency',
currency: 'PYG',
}).format(12345), 'PYG\xa012,345', 'space after currency code when in fallback mode');
assert(new IntlPolyfill.NumberFormat('en-US', {
style: 'currency',
currencyDisplay: 'code',
currency: 'USD',
}).format(12345), 'USD\xa012,345.00', 'space after currency code when in fallback mode');
assert(new IntlPolyfill.NumberFormat('en-US', {
style: 'currency',
currencyDisplay: 'name',
currency: 'USD',
}).format(12345), 'USD\xa012,345.00', 'space after currency name when in fallback mode');
assert(new IntlPolyfill.NumberFormat('cs', {
style: 'currency',
currency: 'CSK',
}).format(12345), '12\xa0345,00\xa0Kčs', 'existing space before currency symbol should be preserved for locales with extended symbol');
assert(new IntlPolyfill.NumberFormat('cs', {
style: 'currency',
currency: 'CSK',
currencyDisplay: 'code',
}).format(12345), '12\xa0345,00\xa0CSK', 'existing space before currency code should be preserved for locales with extended symbol');
assert(new IntlPolyfill.NumberFormat('bn', {
style: 'currency',
currency: 'BDT',
currencyDisplay: 'name',
}).format(12345), '১২,৩৪৫.০০\xa0BDT', 'existing space before currency symbol should be preserved for locales without symbol');

0 comments on commit 854902f

Please sign in to comment.