feat(ivy): use i18n locale data to determine the plural form of ICU expressions (#29249)

Plural ICU expressions depend on the locale (different languages have different plural forms). Until now the locale was hard coded as `en-US`.
For compatibility reasons, if you use ivy with AOT and bootstrap your app with `bootstrapModule` then the `LOCALE_ID` token will be set automatically for ivy, which is then used to get the correct plural form.
If you use JIT, you need to define the `LOCALE_ID` provider on the module that you bootstrap.
For `TestBed` you can use either `configureTestingModule` or `overrideProvider` to define that provider.
If you don't use the compat mode and start your app with `renderComponent` you need to call `ɵsetLocaleId` manually to define the `LOCALE_ID` before bootstrap. We expect this to change once we start adding the new i18n APIs, so don't rely on this function (there's a reason why it's a private export).
PR Close #29249
This commit is contained in:
Olivier Combe
2019-05-17 16:13:31 +02:00
committed by Matias Niemelä
parent f5b0c8a323
commit 5e0f982961
26 changed files with 288 additions and 450 deletions

View File

@ -6,10 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
/**
* @publicApi
*/
export const LOCALE_DATA: {[localeId: string]: any} = {};
import {ɵLOCALE_DATA as LOCALE_DATA, ɵLocaleDataIndex as LocaleDataIndex} from '@angular/core';
/**
* Register global data to be used internally by Angular. See the
@ -33,32 +30,6 @@ export function registerLocaleData(data: any, localeId?: string | any, 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,
Currencies,
PluralCase,
ExtraData
}
/**
* Index of each type of locale data from the extra locale data array
*/

View File

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import localeEn from './locale_en';
import {LOCALE_DATA, LocaleDataIndex, ExtraLocaleDataIndex, CurrencyIndex} from './locale_data';
import {ɵLocaleDataIndex as LocaleDataIndex, ɵfindLocaleData as findLocaleData, ɵgetLocalePluralCase} from '@angular/core';
import {CURRENCIES_EN, CurrenciesSymbols} from './currencies';
import {CurrencyIndex, ExtraLocaleDataIndex} from './locale_data';
/**
* Format styles that can be used to represent numbers.
@ -31,7 +31,8 @@ export enum NumberFormatStyle {
* @see `NgPluralCase`
* @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n)
*
* @publicApi */
* @publicApi
*/
export enum Plural {
Zero = 0,
One = 1,
@ -485,19 +486,11 @@ function getLocaleCurrencies(locale: string): {[code: string]: CurrenciesSymbols
}
/**
* Retrieves the plural function used by ICU expressions to determine the plural case to use
* for a given locale.
* @param locale A locale code for the locale format rules to use.
* @returns The plural function for the locale.
* @see `NgPlural`
* @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n)
*
* @alias core/ɵgetLocalePluralCase
* @publicApi
*/
export function getLocalePluralCase(locale: string): (value: number) => Plural {
const data = findLocaleData(locale);
return data[LocaleDataIndex.PluralCase];
}
export const getLocalePluralCase: (locale: string) => ((value: number) => Plural) =
ɵgetLocalePluralCase;
function checkFullData(data: any) {
if (!data[LocaleDataIndex.ExtraData]) {
@ -609,37 +602,7 @@ function extractTime(time: string): Time {
return {hours: +h, minutes: +m};
}
/**
* Finds the locale data for a given locale.
*
* @param locale The locale code.
* @returns The locale data.
* @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n)
*
* @publicApi
*/
export function findLocaleData(locale: string): any {
const normalizedLocale = locale.toLowerCase().replace(/_/g, '-');
let match = LOCALE_DATA[normalizedLocale];
if (match) {
return match;
}
// let's try to find a parent locale
const parentLocale = normalizedLocale.split('-')[0];
match = LOCALE_DATA[parentLocale];
if (match) {
return match;
}
if (parentLocale === 'en') {
return localeEn;
}
throw new Error(`Missing locale data for the locale "${locale}".`);
}
/**
* Retrieves the currency symbol for a given currency code.

View File

@ -1,41 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
const u = undefined;
function plural(n: number): number {
let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length;
if (i === 1 && v === 0) return 1;
return 5;
}
export default [
'en', [['a', 'p'], ['AM', 'PM'], u], [['AM', 'PM'], u, u],
[
['S', 'M', 'T', 'W', 'T', 'F', 'S'], ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
],
u,
[
['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
[
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
'October', 'November', 'December'
]
],
u, [['B', 'A'], ['BC', 'AD'], ['Before Christ', 'Anno Domini']], 0, [6, 0],
['M/d/yy', 'MMM d, y', 'MMMM d, y', 'EEEE, MMMM d, y'],
['h:mm a', 'h:mm:ss a', 'h:mm:ss a z', 'h:mm:ss a zzzz'], ['{1}, {0}', u, '{1} \'at\' {0}', u],
['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'],
['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], '$', 'US Dollar', {}, plural
];