fix(common): add locale currency values (#21783)
we now use locale currency symbols, since they may be different in each locale (we were only using english data previously) Fixes #20385 PR Close #21783
This commit is contained in:
committed by
Miško Hevery
parent
5fc77c90cb
commit
420cc7afc6
@@ -54,33 +54,36 @@ module.exports = (gulp, done) => {
|
||||
if (!fs.existsSync(RELATIVE_I18N_DATA_EXTRA_FOLDER)) {
|
||||
fs.mkdirSync(RELATIVE_I18N_DATA_EXTRA_FOLDER);
|
||||
}
|
||||
|
||||
console.log(`Writing file ${I18N_FOLDER}/currencies.ts`);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/currencies.ts`, generateCurrenciesFile());
|
||||
|
||||
const baseCurrencies = generateBaseCurrencies(new cldrJs('en'));
|
||||
// additional "en" file that will be included in common
|
||||
console.log(`Writing file ${I18N_FOLDER}/locale_en.ts`);
|
||||
const localeEnFile = generateLocale('en', new cldrJs('en'), baseCurrencies);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/locale_en.ts`, localeEnFile);
|
||||
|
||||
LOCALES.forEach((locale, index) => {
|
||||
const localeData = new cldrJs(locale);
|
||||
|
||||
console.log(`${index + 1}/${LOCALES.length}`);
|
||||
console.log(`\t${I18N_DATA_FOLDER}/${locale}.ts`);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_DATA_FOLDER}/${locale}.ts`, generateLocale(locale, localeData));
|
||||
fs.writeFileSync(`${RELATIVE_I18N_DATA_FOLDER}/${locale}.ts`, locale === 'en'? localeEnFile : generateLocale(locale, localeData, baseCurrencies));
|
||||
console.log(`\t${I18N_DATA_EXTRA_FOLDER}/${locale}.ts`);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_DATA_EXTRA_FOLDER}/${locale}.ts`, generateLocaleExtra(locale, localeData));
|
||||
});
|
||||
console.log(`${LOCALES.length} locale files generated.`);
|
||||
|
||||
// additional "en" file that will be included in common
|
||||
console.log(`Writing file ${I18N_FOLDER}/locale_en.ts`);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/locale_en.ts`, generateLocale('en', new cldrJs('en')));
|
||||
|
||||
console.log(`Writing file ${I18N_FOLDER}/currencies.ts`);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/currencies.ts`, generateCurrencies());
|
||||
|
||||
console.log(`All i18n cldr files have been generated, formatting files..."`);
|
||||
const format = require('gulp-clang-format');
|
||||
const clangFormat = require('clang-format');
|
||||
return gulp
|
||||
.src([
|
||||
`${I18N_DATA_FOLDER}/**/*.ts`,
|
||||
`${I18N_FOLDER}/currencies.ts`,
|
||||
`${I18N_FOLDER}/locale_en.ts`
|
||||
], {base: '.'})
|
||||
`${I18N_DATA_FOLDER}/**/*.ts`,
|
||||
`${I18N_FOLDER}/currencies.ts`,
|
||||
`${I18N_FOLDER}/locale_en.ts`
|
||||
], {base: '.'})
|
||||
.pipe(format.format('file', clangFormat))
|
||||
.pipe(gulp.dest('.'));
|
||||
};
|
||||
@@ -88,16 +91,17 @@ module.exports = (gulp, done) => {
|
||||
/**
|
||||
* Generate file that contains basic locale data
|
||||
*/
|
||||
function generateLocale(locale, localeData) {
|
||||
function generateLocale(locale, localeData, baseCurrencies) {
|
||||
// [ localeId, dateTime, number, currency, pluralCase ]
|
||||
let data = stringify([
|
||||
locale,
|
||||
...getDateTimeTranslations(localeData),
|
||||
...getDateTimeSettings(localeData),
|
||||
...getNumberSettings(localeData),
|
||||
...getCurrencySettings(locale, localeData)
|
||||
])
|
||||
// We remove "undefined" added by spreading arrays when there is no value
|
||||
...getCurrencySettings(locale, localeData),
|
||||
generateLocaleCurrencies(localeData, baseCurrencies)
|
||||
], true)
|
||||
// We remove "undefined" added by spreading arrays when there is no value
|
||||
.replace(/undefined/g, '');
|
||||
|
||||
// adding plural function after, because we don't want it as a string
|
||||
@@ -149,11 +153,12 @@ export default ${stringify(dayPeriodsSupplemental).replace(/undefined/g, '')};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file that contains the list of currencies and their symbols
|
||||
* Generate a list of currencies to be used as a based for other currencies
|
||||
* e.g.: {'ARS': [, '$'], 'AUD': ['A$', '$'], ...}
|
||||
*/
|
||||
function generateCurrencies() {
|
||||
const currenciesData = new cldrJs('en').main('numbers/currencies');
|
||||
const currencies = [];
|
||||
function generateBaseCurrencies(localeData, addDigits) {
|
||||
const currenciesData = localeData.main('numbers/currencies');
|
||||
const currencies = {};
|
||||
Object.keys(currenciesData).forEach(key => {
|
||||
let symbolsArray = [];
|
||||
const symbol = currenciesData[key].symbol;
|
||||
@@ -169,14 +174,52 @@ function generateCurrencies() {
|
||||
}
|
||||
}
|
||||
if (symbolsArray.length > 0) {
|
||||
currencies.push(` '${key}': ${stringify(symbolsArray)},\n`);
|
||||
currencies[key] = symbolsArray;
|
||||
}
|
||||
});
|
||||
return currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* To minimize the file even more, we only output the differences compared to the base currency
|
||||
*/
|
||||
function generateLocaleCurrencies(localeData, baseCurrencies) {
|
||||
const currenciesData = localeData.main('numbers/currencies');
|
||||
const currencies = {};
|
||||
Object.keys(currenciesData).forEach(code => {
|
||||
let symbolsArray = [];
|
||||
const symbol = currenciesData[code].symbol;
|
||||
const symbolNarrow = currenciesData[code]['symbol-alt-narrow'];
|
||||
if (symbol && symbol !== code) {
|
||||
symbolsArray.push(symbol);
|
||||
}
|
||||
if (symbolNarrow && symbolNarrow !== symbol) {
|
||||
if (symbolsArray.length > 0) {
|
||||
symbolsArray.push(symbolNarrow);
|
||||
} else {
|
||||
symbolsArray = [, symbolNarrow];
|
||||
}
|
||||
}
|
||||
|
||||
// if locale data are different, set the value
|
||||
if ((baseCurrencies[code] || []).toString() !== symbolsArray.toString()) {
|
||||
currencies[code] = symbolsArray;
|
||||
}
|
||||
});
|
||||
return currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file that contains the list of currencies and their symbols
|
||||
*/
|
||||
function generateCurrenciesFile() {
|
||||
const baseCurrencies = generateBaseCurrencies(new cldrJs('en'), true);
|
||||
|
||||
return `${HEADER}
|
||||
export type CurrenciesSymbols = [string] | [string | undefined, string];
|
||||
|
||||
/** @internal */
|
||||
export const CURRENCIES: {[code: string]: (string | undefined)[]} = {
|
||||
${currencies.join('')}};
|
||||
export const CURRENCIES_EN: {[code: string]: CurrenciesSymbols} = ${stringify(baseCurrencies, true)};
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
* Like JSON.stringify, but without double quotes around keys, and without null instead of undefined
|
||||
* values
|
||||
* Based on https://github.com/json5/json5/blob/master/lib/json5.js
|
||||
* Use option "quoteKeys" to preserve quotes for keys
|
||||
*/
|
||||
module.exports.stringify = function(obj, replacer, space) {
|
||||
if (replacer && (typeof(replacer) !== 'function' && !isArray(replacer))) {
|
||||
throw new Error('Replacer must be a function or an array');
|
||||
}
|
||||
var getReplacedValueOrUndefined = function(holder, key, isTopLevel) {
|
||||
module.exports.stringify = function(obj, quoteKeys) {
|
||||
var getReplacedValueOrUndefined = function(holder, key) {
|
||||
var value = holder[key];
|
||||
|
||||
// Replace the value with its toJSON value first, if possible
|
||||
@@ -17,21 +15,7 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
value = value.toJSON();
|
||||
}
|
||||
|
||||
// If the user-supplied replacer if a function, call it. If it's an array, check objects' string
|
||||
// keys for
|
||||
// presence in the array (removing the key/value pair from the resulting JSON if the key is
|
||||
// missing).
|
||||
if (typeof(replacer) === 'function') {
|
||||
return replacer.call(holder, key, value);
|
||||
} else if (replacer) {
|
||||
if (isTopLevel || isArray(holder) || replacer.indexOf(key) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
function isWordChar(c) {
|
||||
@@ -80,34 +64,6 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
}
|
||||
}
|
||||
|
||||
function makeIndent(str, num, noNewLine) {
|
||||
if (!str) {
|
||||
return '';
|
||||
}
|
||||
// indentation no more than 10 chars
|
||||
if (str.length > 10) {
|
||||
str = str.substring(0, 10);
|
||||
}
|
||||
|
||||
var indent = noNewLine ? '' : '\n';
|
||||
for (var i = 0; i < num; i++) {
|
||||
indent += str;
|
||||
}
|
||||
|
||||
return indent;
|
||||
}
|
||||
|
||||
var indentStr;
|
||||
if (space) {
|
||||
if (typeof space === 'string') {
|
||||
indentStr = space;
|
||||
} else if (typeof space === 'number' && space >= 0) {
|
||||
indentStr = makeIndent(' ', space, true);
|
||||
} else {
|
||||
// ignore space parameter
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from Crokford's implementation of JSON
|
||||
// See
|
||||
// https://github.com/douglascrockford/JSON-js/blob/e39db4b7e6249f04a195e7dd0840e610cc9e941e/json2.js#L195
|
||||
@@ -123,24 +79,24 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
function escapeString(str) {
|
||||
function escapeString(str, keepQuotes) {
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(str) ? '"' + str.replace(escapable, function(a) {
|
||||
return escapable.test(str) && !keepQuotes ? '"' + str.replace(escapable, function(a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + str + '"';
|
||||
}
|
||||
// End
|
||||
|
||||
function internalStringify(holder, key, isTopLevel) {
|
||||
function internalStringify(holder, key) {
|
||||
var buffer, res;
|
||||
|
||||
// Replace the value, if necessary
|
||||
var obj_part = getReplacedValueOrUndefined(holder, key, isTopLevel);
|
||||
var obj_part = getReplacedValueOrUndefined(holder, key);
|
||||
|
||||
if (obj_part && !isDate(obj_part)) {
|
||||
// unbox objects
|
||||
@@ -169,8 +125,7 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
objStack.push(obj_part);
|
||||
|
||||
for (var i = 0; i < obj_part.length; i++) {
|
||||
res = internalStringify(obj_part, i, false);
|
||||
buffer += makeIndent(indentStr, objStack.length);
|
||||
res = internalStringify(obj_part, i);
|
||||
if (res === null) {
|
||||
buffer += 'null';
|
||||
} else if (typeof res === 'undefined') { // modified to support empty array values
|
||||
@@ -180,14 +135,9 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
}
|
||||
if (i < obj_part.length - 1) {
|
||||
buffer += ',';
|
||||
} else if (indentStr) {
|
||||
buffer += '\n';
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
if (obj_part.length) {
|
||||
buffer += makeIndent(indentStr, objStack.length, true);
|
||||
}
|
||||
buffer += ']';
|
||||
} else {
|
||||
checkForCircular(obj_part);
|
||||
@@ -197,19 +147,16 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
for (var prop in obj_part) {
|
||||
if (obj_part.hasOwnProperty(prop)) {
|
||||
var value = internalStringify(obj_part, prop, false);
|
||||
isTopLevel = false;
|
||||
if (typeof value !== 'undefined' && value !== null) {
|
||||
buffer += makeIndent(indentStr, objStack.length);
|
||||
nonEmpty = true;
|
||||
key = isWord(prop) ? prop : escapeString(prop);
|
||||
buffer += key + ':' + (indentStr ? ' ' : '') + value + ',';
|
||||
key = isWord(prop) && !quoteKeys ? prop : escapeString(prop, quoteKeys);
|
||||
buffer += key + ':' + value + ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
if (nonEmpty) {
|
||||
buffer = buffer.substring(0, buffer.length - 1) +
|
||||
makeIndent(indentStr, objStack.length) + '}';
|
||||
buffer = buffer.substring(0, buffer.length - 1) + '}';
|
||||
} else {
|
||||
buffer = '{}';
|
||||
}
|
||||
@@ -228,5 +175,5 @@ module.exports.stringify = function(obj, replacer, space) {
|
||||
if (obj === undefined) {
|
||||
return getReplacedValueOrUndefined(topLevelHolder, '', true);
|
||||
}
|
||||
return internalStringify(topLevelHolder, '', true);
|
||||
return internalStringify(topLevelHolder, '');
|
||||
};
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ export declare class CommonModule {
|
||||
/** @stable */
|
||||
export declare class CurrencyPipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | boolean, digits?: string, locale?: string): string | null;
|
||||
transform(value: any, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean, digitsInfo?: string, locale?: string): string | null;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
@@ -30,7 +30,7 @@ export declare class DatePipe implements PipeTransform {
|
||||
/** @stable */
|
||||
export declare class DecimalPipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, digits?: string, locale?: string): string | null;
|
||||
transform(value: any, digitsInfo?: string, locale?: string): string | null;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
@@ -79,7 +79,7 @@ export declare enum FormStyle {
|
||||
}
|
||||
|
||||
/** @experimental */
|
||||
export declare function getCurrencySymbol(code: string, format: 'wide' | 'narrow'): string;
|
||||
export declare function getCurrencySymbol(code: string, format: 'wide' | 'narrow', locale?: string): string;
|
||||
|
||||
/** @experimental */
|
||||
export declare function getLocaleCurrencyName(locale: string): string | null;
|
||||
@@ -386,7 +386,7 @@ export declare class PathLocationStrategy extends LocationStrategy {
|
||||
/** @stable */
|
||||
export declare class PercentPipe implements PipeTransform {
|
||||
constructor(_locale: string);
|
||||
transform(value: any, digits?: string, locale?: string): string | null;
|
||||
transform(value: any, digitsInfo?: string, locale?: string): string | null;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
|
||||
Reference in New Issue
Block a user