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:

committed by
Alex Rickabaugh

parent
6a1441f727
commit
6a8cca7975
38
packages/core/src/i18n/locale_data.ts
Normal file
38
packages/core/src/i18n/locale_data.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @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 const is used to store the locale data registered with `registerLocaleData`
|
||||
*/
|
||||
export const LOCALE_DATA: {[localeId: string]: any} = {};
|
||||
|
||||
/**
|
||||
* Index of each type of locale data from the locale data array
|
||||
*/
|
||||
export enum LocaleDataIndex {
|
||||
LocaleId = 0,
|
||||
DayPeriodsFormat,
|
||||
DayPeriodsStandalone,
|
||||
DaysFormat,
|
||||
DaysStandalone,
|
||||
MonthsFormat,
|
||||
MonthsStandalone,
|
||||
Eras,
|
||||
FirstDayOfWeek,
|
||||
WeekendRange,
|
||||
DateFormat,
|
||||
TimeFormat,
|
||||
DateTimeFormat,
|
||||
NumberSymbols,
|
||||
NumberFormats,
|
||||
CurrencySymbol,
|
||||
CurrencyName,
|
||||
Currencies,
|
||||
PluralCase,
|
||||
ExtraData
|
||||
}
|
53
packages/core/src/i18n/locale_data_api.ts
Normal file
53
packages/core/src/i18n/locale_data_api.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import {LOCALE_DATA, LocaleDataIndex} from './locale_data';
|
||||
import localeEn from './locale_en';
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
export function getLocalePluralCase(locale: string): (value: number) => number {
|
||||
const data = findLocaleData(locale);
|
||||
return data[LocaleDataIndex.PluralCase];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
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}".`);
|
||||
}
|
41
packages/core/src/i18n/locale_en.ts
Normal file
41
packages/core/src/i18n/locale_en.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @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
|
||||
];
|
31
packages/core/src/i18n/localization.ts
Normal file
31
packages/core/src/i18n/localization.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import {getLocalePluralCase} from './locale_data_api';
|
||||
|
||||
/**
|
||||
* Returns the plural case based on the locale
|
||||
*/
|
||||
export function getPluralCase(value: any, locale: string): string {
|
||||
const plural = getLocalePluralCase(locale)(value);
|
||||
|
||||
switch (plural) {
|
||||
case 0:
|
||||
return 'zero';
|
||||
case 1:
|
||||
return 'one';
|
||||
case 2:
|
||||
return 'two';
|
||||
case 3:
|
||||
return 'few';
|
||||
case 4:
|
||||
return 'many';
|
||||
default:
|
||||
return 'other';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user