refactor(common): refactor i18n code to ease tree shaking (#18907)
PR Close #18907
This commit is contained in:
parent
4c45347635
commit
832876d0a1
|
@ -13,8 +13,8 @@
|
||||||
*/
|
*/
|
||||||
export * from './location/index';
|
export * from './location/index';
|
||||||
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
export {NgLocaleLocalization, NgLocalization} from './i18n/localization';
|
||||||
export {Plural, LOCALE_DATA} from './i18n/locale_data';
|
export {registerLocaleData} from './i18n/locale_data';
|
||||||
export {findLocaleData, registerLocaleData, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol} from './i18n/locale_data_api';
|
||||||
export {CURRENCIES} from './i18n/currencies';
|
export {CURRENCIES} from './i18n/currencies';
|
||||||
export {parseCookieValue as ɵparseCookieValue} from './cookie';
|
export {parseCookieValue as ɵparseCookieValue} from './cookie';
|
||||||
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
|
export {CommonModule, DeprecatedI18NPipesModule} from './common_module';
|
||||||
|
|
|
@ -6,17 +6,55 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @experimental */
|
|
||||||
export enum Plural {
|
|
||||||
Zero,
|
|
||||||
One,
|
|
||||||
Two,
|
|
||||||
Few,
|
|
||||||
Many,
|
|
||||||
Other,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @experimental i18n support is experimental.
|
* @experimental i18n support is experimental.
|
||||||
*/
|
*/
|
||||||
export const LOCALE_DATA: {[localeId: string]: any} = {};
|
export const LOCALE_DATA: {[localeId: string]: any} = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register global data to be used internally by Angular. See the
|
||||||
|
* {@linkDocs guide/i18n#i18n-pipes "I18n guide"} to know how to import additional locale data.
|
||||||
|
*
|
||||||
|
* @experimental i18n support is experimental.
|
||||||
|
*/
|
||||||
|
export function registerLocaleData(data: any, extraData?: any) {
|
||||||
|
const localeId = data[LocaleDataIndex.LocaleId].toLowerCase();
|
||||||
|
LOCALE_DATA[localeId] = data;
|
||||||
|
if (extraData) {
|
||||||
|
LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of each type of locale data from the locale data array
|
||||||
|
*/
|
||||||
|
export const enum LocaleDataIndex {
|
||||||
|
LocaleId = 0,
|
||||||
|
DayPeriodsFormat,
|
||||||
|
DayPeriodsStandalone,
|
||||||
|
DaysFormat,
|
||||||
|
DaysStandalone,
|
||||||
|
MonthsFormat,
|
||||||
|
MonthsStandalone,
|
||||||
|
Eras,
|
||||||
|
FirstDayOfWeek,
|
||||||
|
WeekendRange,
|
||||||
|
DateFormat,
|
||||||
|
TimeFormat,
|
||||||
|
DateTimeFormat,
|
||||||
|
NumberSymbols,
|
||||||
|
NumberFormats,
|
||||||
|
CurrencySymbol,
|
||||||
|
CurrencyName,
|
||||||
|
PluralCase,
|
||||||
|
ExtraData
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of each type of locale data from the extra locale data array
|
||||||
|
*/
|
||||||
|
export const enum ExtraLocaleDataIndex {
|
||||||
|
ExtraDayPeriodFormats = 0,
|
||||||
|
ExtraDayPeriodStandalone,
|
||||||
|
ExtraDayPeriodsRules
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import {CURRENCIES} from './currencies';
|
import {CURRENCIES} from './currencies';
|
||||||
import localeEn from './locale_en';
|
import localeEn from './locale_en';
|
||||||
import {LOCALE_DATA, Plural} from './locale_data';
|
import {LOCALE_DATA, LocaleDataIndex, ExtraLocaleDataIndex} from './locale_data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The different format styles that can be used to represent numbers.
|
* The different format styles that can be used to represent numbers.
|
||||||
|
@ -23,6 +23,16 @@ export enum NumberFormatStyle {
|
||||||
Scientific
|
Scientific
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @experimental */
|
||||||
|
export enum Plural {
|
||||||
|
Zero = 0,
|
||||||
|
One = 1,
|
||||||
|
Two = 2,
|
||||||
|
Few = 3,
|
||||||
|
Many = 4,
|
||||||
|
Other = 5,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some languages use two different forms of strings (standalone and format) depending on the
|
* Some languages use two different forms of strings (standalone and format) depending on the
|
||||||
* context.
|
* context.
|
||||||
|
@ -130,40 +140,6 @@ export enum WeekDay {
|
||||||
Saturday
|
Saturday
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this enum to find the index of each type of locale data from the locale data array
|
|
||||||
*/
|
|
||||||
enum LocaleDataIndex {
|
|
||||||
LocaleId = 0,
|
|
||||||
DayPeriodsFormat,
|
|
||||||
DayPeriodsStandalone,
|
|
||||||
DaysFormat,
|
|
||||||
DaysStandalone,
|
|
||||||
MonthsFormat,
|
|
||||||
MonthsStandalone,
|
|
||||||
Eras,
|
|
||||||
FirstDayOfWeek,
|
|
||||||
WeekendRange,
|
|
||||||
DateFormat,
|
|
||||||
TimeFormat,
|
|
||||||
DateTimeFormat,
|
|
||||||
NumberSymbols,
|
|
||||||
NumberFormats,
|
|
||||||
CurrencySymbol,
|
|
||||||
CurrencyName,
|
|
||||||
PluralCase,
|
|
||||||
ExtraData
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this enum to find the index of each type of locale data from the extra locale data array
|
|
||||||
*/
|
|
||||||
enum ExtraLocaleDataIndex {
|
|
||||||
ExtraDayPeriodFormats = 0,
|
|
||||||
ExtraDayPeriodStandalone,
|
|
||||||
ExtraDayPeriodsRules
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The locale id for the chosen locale (e.g `en-GB`).
|
* The locale id for the chosen locale (e.g `en-GB`).
|
||||||
*
|
*
|
||||||
|
@ -537,6 +513,7 @@ export function findLocaleData(locale: string): any {
|
||||||
// let's try to find a parent locale
|
// let's try to find a parent locale
|
||||||
const parentLocale = normalizedLocale.split('-')[0];
|
const parentLocale = normalizedLocale.split('-')[0];
|
||||||
match = LOCALE_DATA[parentLocale];
|
match = LOCALE_DATA[parentLocale];
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
@ -545,8 +522,7 @@ export function findLocaleData(locale: string): any {
|
||||||
return localeEn;
|
return localeEn;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(`Missing locale data for the locale "${locale}".`);
|
||||||
`Missing locale data for the locale "${locale}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -560,17 +536,3 @@ export function findCurrencySymbol(code: string, format: 'wide' | 'narrow') {
|
||||||
const symbol = currency[0] || code;
|
const symbol = currency[0] || code;
|
||||||
return format === 'wide' ? symbol : currency[1] || symbol;
|
return format === 'wide' ? symbol : currency[1] || symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register global data to be used internally by Angular. See the
|
|
||||||
* {@linkDocs guide/i18n#i18n-pipes "I18n guide"} to know how to import additional locale data.
|
|
||||||
*
|
|
||||||
* @experimental i18n support is experimental.
|
|
||||||
*/
|
|
||||||
export function registerLocaleData(data: any, extraData?: any) {
|
|
||||||
const localeId = data[LocaleDataIndex.LocaleId].toLowerCase();
|
|
||||||
LOCALE_DATA[localeId] = data;
|
|
||||||
if (extraData) {
|
|
||||||
LOCALE_DATA[localeId][LocaleDataIndex.ExtraData] = extraData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
||||||
import {Plural} from './locale_data';
|
import {Plural, getLocalePluralCase} from './locale_data_api';
|
||||||
import {getLocalePluralCase} from './locale_data_api';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @experimental
|
* @experimental
|
||||||
|
|
|
@ -10,7 +10,8 @@ import localeCaESVALENCIA from '../../i18n_data/locale_ca-ES-VALENCIA';
|
||||||
import localeEn from '../../i18n_data/locale_en';
|
import localeEn from '../../i18n_data/locale_en';
|
||||||
import localeFr from '../../i18n_data/locale_fr';
|
import localeFr from '../../i18n_data/locale_fr';
|
||||||
import localeFrCA from '../../i18n_data/locale_fr-CA';
|
import localeFrCA from '../../i18n_data/locale_fr-CA';
|
||||||
import {registerLocaleData, findLocaleData} from '../../src/i18n/locale_data_api';
|
import {findLocaleData} from '../../src/i18n/locale_data_api';
|
||||||
|
import {registerLocaleData} from '../../src/i18n/locale_data';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('locale data api', () => {
|
describe('locale data api', () => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import localeFr from '../../i18n_data/locale_fr';
|
||||||
import {LOCALE_ID} from '@angular/core';
|
import {LOCALE_ID} from '@angular/core';
|
||||||
import {TestBed, inject} from '@angular/core/testing';
|
import {TestBed, inject} from '@angular/core/testing';
|
||||||
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../../src/i18n/localization';
|
import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '../../src/i18n/localization';
|
||||||
import {registerLocaleData} from '../../src/i18n/locale_data_api';
|
import {registerLocaleData} from '../../src/i18n/locale_data';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('l10n', () => {
|
describe('l10n', () => {
|
||||||
|
|
|
@ -56,7 +56,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('transform with custom locales', () => {
|
describe('transform with custom locales', () => {
|
||||||
it('should return the correct format for es-US in IE11', () => {
|
it('should return the correct format for es-US', () => {
|
||||||
const pipe = new DecimalPipe('es-US');
|
const pipe = new DecimalPipe('es-US');
|
||||||
expect(pipe.transform('9999999.99', '1.2-2')).toEqual('9,999,999.99');
|
expect(pipe.transform('9999999.99', '1.2-2')).toEqual('9,999,999.99');
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,7 +58,7 @@ module.exports = (gulp, done) => {
|
||||||
|
|
||||||
console.log(`${index + 1}/${LOCALES.length}`);
|
console.log(`${index + 1}/${LOCALES.length}`);
|
||||||
console.log(`\t${I18N_DATA_FOLDER}/locale_${locale}.ts`);
|
console.log(`\t${I18N_DATA_FOLDER}/locale_${locale}.ts`);
|
||||||
fs.writeFileSync(`${RELATIVE_I18N_DATA_FOLDER}/locale_${locale}.ts`, generateLocale(locale, localeData, '@angular/common'));
|
fs.writeFileSync(`${RELATIVE_I18N_DATA_FOLDER}/locale_${locale}.ts`, generateLocale(locale, localeData));
|
||||||
console.log(`\t${I18N_DATA_EXTRA_FOLDER}/locale_${locale}.ts`);
|
console.log(`\t${I18N_DATA_EXTRA_FOLDER}/locale_${locale}.ts`);
|
||||||
fs.writeFileSync(`${RELATIVE_I18N_DATA_EXTRA_FOLDER}/locale_${locale}.ts`, generateLocaleExtra(locale, localeData));
|
fs.writeFileSync(`${RELATIVE_I18N_DATA_EXTRA_FOLDER}/locale_${locale}.ts`, generateLocaleExtra(locale, localeData));
|
||||||
});
|
});
|
||||||
|
@ -66,7 +66,7 @@ module.exports = (gulp, done) => {
|
||||||
|
|
||||||
// additional "en" file that will be included in common
|
// additional "en" file that will be included in common
|
||||||
console.log(`Writing file ${I18N_FOLDER}/locale_en.ts`);
|
console.log(`Writing file ${I18N_FOLDER}/locale_en.ts`);
|
||||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/locale_en.ts`, generateLocale('en', new cldrJs('en'), './locale_data'));
|
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/locale_en.ts`, generateLocale('en', new cldrJs('en')));
|
||||||
|
|
||||||
console.log(`Writing file ${I18N_FOLDER}/currencies.ts`);
|
console.log(`Writing file ${I18N_FOLDER}/currencies.ts`);
|
||||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/currencies.ts`, generateCurrencies());
|
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/currencies.ts`, generateCurrencies());
|
||||||
|
@ -87,7 +87,7 @@ module.exports = (gulp, done) => {
|
||||||
/**
|
/**
|
||||||
* Generate file that contains basic locale data
|
* Generate file that contains basic locale data
|
||||||
*/
|
*/
|
||||||
function generateLocale(locale, localeData, ngLocalePath) {
|
function generateLocale(locale, localeData) {
|
||||||
// [ localeId, dateTime, number, currency, pluralCase ]
|
// [ localeId, dateTime, number, currency, pluralCase ]
|
||||||
let data = stringify([
|
let data = stringify([
|
||||||
locale,
|
locale,
|
||||||
|
@ -103,8 +103,6 @@ function generateLocale(locale, localeData, ngLocalePath) {
|
||||||
data = data.substring(0, data.lastIndexOf(']')) + `, ${getPluralFunction(locale)}]`;
|
data = data.substring(0, data.lastIndexOf(']')) + `, ${getPluralFunction(locale)}]`;
|
||||||
|
|
||||||
return `${HEADER}
|
return `${HEADER}
|
||||||
import {Plural} from '${ngLocalePath}';
|
|
||||||
|
|
||||||
export default ${data};
|
export default ${data};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -450,24 +448,28 @@ function toRegExp(s) {
|
||||||
*/
|
*/
|
||||||
function getPluralFunction(locale) {
|
function getPluralFunction(locale) {
|
||||||
let fn = cldr.extractPluralRuleFunction(locale).toString();
|
let fn = cldr.extractPluralRuleFunction(locale).toString();
|
||||||
|
|
||||||
if (fn === EMPTY_RULE) {
|
if (fn === EMPTY_RULE) {
|
||||||
fn = DEFAULT_RULE;
|
fn = DEFAULT_RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn
|
fn = fn
|
||||||
.replace(
|
.replace(
|
||||||
toRegExp('function anonymous(n\n/**/) {\n'),
|
toRegExp('function anonymous(n\n/**/) {\n'),
|
||||||
'function(n: number): Plural {\n ')
|
'function(n: number): number {\n ')
|
||||||
.replace(toRegExp('var'), 'let')
|
.replace(toRegExp('var'), 'let')
|
||||||
.replace(toRegExp('if(typeof n==="string")n=parseInt(n,10);'), '')
|
.replace(toRegExp('if(typeof n==="string")n=parseInt(n,10);'), '')
|
||||||
.replace(toRegExp('"zero"'), ' Plural.Zero')
|
|
||||||
.replace(toRegExp('"one"'), ' Plural.One')
|
|
||||||
.replace(toRegExp('"two"'), ' Plural.Two')
|
|
||||||
.replace(toRegExp('"few"'), ' Plural.Few')
|
|
||||||
.replace(toRegExp('"many"'), ' Plural.Many')
|
|
||||||
.replace(toRegExp('"other"'), ' Plural.Other')
|
|
||||||
.replace(toRegExp('\n}'), ';\n}');
|
.replace(toRegExp('\n}'), ';\n}');
|
||||||
return normalizePluralRule();
|
|
||||||
|
// The replacement values must match the `Plural` enum from common.
|
||||||
|
// We do not use the enum directly to avoid depending on that package.
|
||||||
|
return fn
|
||||||
|
.replace(toRegExp('"zero"'), ' 0')
|
||||||
|
.replace(toRegExp('"one"'), ' 1')
|
||||||
|
.replace(toRegExp('"two"'), ' 2')
|
||||||
|
.replace(toRegExp('"few"'), ' 3')
|
||||||
|
.replace(toRegExp('"many"'), ' 4')
|
||||||
|
.replace(toRegExp('"other"'), ' 5');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -484,13 +486,6 @@ function stringify(obj) {
|
||||||
return util.inspect(obj, {depth: null, maxArrayLength: null})
|
return util.inspect(obj, {depth: null, maxArrayLength: null})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform a string to camelCase
|
|
||||||
*/
|
|
||||||
function toCamelCase(str) {
|
|
||||||
return str.replace(/-+([a-z0-9A-Z])/g, (...m) => m[1].toUpperCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To create smaller locale files, we remove duplicated data.
|
* To create smaller locale files, we remove duplicated data.
|
||||||
* To be make this work we need to store similar data in arrays, if some value in an array
|
* To be make this work we need to store similar data in arrays, if some value in an array
|
||||||
|
|
|
@ -69,9 +69,6 @@ export declare class DeprecatedPercentPipe implements PipeTransform {
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare const DOCUMENT: InjectionToken<Document>;
|
export declare const DOCUMENT: InjectionToken<Document>;
|
||||||
|
|
||||||
/** @experimental */
|
|
||||||
export declare function findLocaleData(locale: string): any;
|
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare enum FormatWidth {
|
export declare enum FormatWidth {
|
||||||
Short = 0,
|
Short = 0,
|
||||||
|
@ -182,11 +179,6 @@ export declare class JsonPipe implements PipeTransform {
|
||||||
transform(value: any): string;
|
transform(value: any): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @experimental */
|
|
||||||
export declare const LOCALE_DATA: {
|
|
||||||
[localeId: string]: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class Location {
|
export declare class Location {
|
||||||
constructor(platformStrategy: LocationStrategy);
|
constructor(platformStrategy: LocationStrategy);
|
||||||
|
|
Loading…
Reference in New Issue