fix(core): handle pluralize functions that expect a number (#36901)
Previously we were passing a string form of the value to pluralize to the `getLocalePluralCase()` function that is extracted from the locale data. But some locales have functions that rely upon this value being a number not a string. Now we convert the value to a number before passing it to the locale data function. Fixes #36888 PR Close #36901
This commit is contained in:
parent
1c26f40cd4
commit
2ff4b357d7
|
@ -8,26 +8,15 @@
|
||||||
|
|
||||||
import {getLocalePluralCase} from './locale_data_api';
|
import {getLocalePluralCase} from './locale_data_api';
|
||||||
|
|
||||||
|
const pluralMapping = ['zero', 'one', 'two', 'few', 'many'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plural case based on the locale
|
* Returns the plural case based on the locale
|
||||||
*/
|
*/
|
||||||
export function getPluralCase(value: any, locale: string): string {
|
export function getPluralCase(value: string, locale: string): string {
|
||||||
const plural = getLocalePluralCase(locale)(value);
|
const plural = getLocalePluralCase(locale)(parseInt(value, 10));
|
||||||
|
const result = pluralMapping[plural];
|
||||||
switch (plural) {
|
return (result !== undefined) ? result : 'other';
|
||||||
case 0:
|
|
||||||
return 'zero';
|
|
||||||
case 1:
|
|
||||||
return 'one';
|
|
||||||
case 2:
|
|
||||||
return 'two';
|
|
||||||
case 3:
|
|
||||||
return 'few';
|
|
||||||
case 4:
|
|
||||||
return 'many';
|
|
||||||
default:
|
|
||||||
return 'other';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import '@angular/localize/init';
|
import '@angular/localize/init';
|
||||||
|
|
||||||
import {CommonModule, registerLocaleData} from '@angular/common';
|
import {CommonModule, registerLocaleData} from '@angular/common';
|
||||||
|
import localeEs from '@angular/common/locales/es';
|
||||||
import localeRo from '@angular/common/locales/ro';
|
import localeRo from '@angular/common/locales/ro';
|
||||||
import {computeMsgId} from '@angular/compiler';
|
import {computeMsgId} from '@angular/compiler';
|
||||||
import {Component, ContentChild, ContentChildren, Directive, ElementRef, HostBinding, Input, LOCALE_ID, NO_ERRORS_SCHEMA, Pipe, PipeTransform, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
|
import {Component, ContentChild, ContentChildren, Directive, ElementRef, HostBinding, Input, LOCALE_ID, NO_ERRORS_SCHEMA, Pipe, PipeTransform, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
|
||||||
|
@ -770,7 +771,20 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
||||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 5--></div>`);
|
expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 5--></div>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the correct plural form for ICU expressions when using a specific locale', () => {
|
it('should return the correct plural form for ICU expressions when using "ro" locale', () => {
|
||||||
|
// The "ro" locale has a complex plural function that can handle muliple options
|
||||||
|
// (and string inputs)
|
||||||
|
//
|
||||||
|
// function plural(n: number): number {
|
||||||
|
// let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length;
|
||||||
|
// if (i === 1 && v === 0) return 1;
|
||||||
|
// if (!(v === 0) || n === 0 ||
|
||||||
|
// !(n === 1) && n % 100 === Math.floor(n % 100) && n % 100 >= 1 && n % 100 <= 19)
|
||||||
|
// return 3;
|
||||||
|
// return 5;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Compare this to the "es" locale in the next test
|
||||||
loadTranslations({
|
loadTranslations({
|
||||||
[computeMsgId(
|
[computeMsgId(
|
||||||
'{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}')]:
|
'{VAR_PLURAL, plural, =0 {no email} =one {one email} =few {a few emails} =other {lots of emails}}')]:
|
||||||
|
@ -814,6 +828,57 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
||||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
|
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should return the correct plural form for ICU expressions when using "es" locale`, () => {
|
||||||
|
// The "es" locale has a simple plural function that can only handle a few options
|
||||||
|
// (and not string inputs)
|
||||||
|
//
|
||||||
|
// function plural(n: number): number {
|
||||||
|
// if (n === 1) return 1;
|
||||||
|
// return 5;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Compare this to the "ro" locale in the previous test
|
||||||
|
const icuMessage = '{VAR_PLURAL, plural, =0 {no email} =one ' +
|
||||||
|
'{one email} =few {a few emails} =other {lots of emails}}';
|
||||||
|
loadTranslations({[computeMsgId(icuMessage)]: icuMessage});
|
||||||
|
registerLocaleData(localeEs);
|
||||||
|
TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'es'}]});
|
||||||
|
// We could also use `TestBed.overrideProvider(LOCALE_ID, {useValue: 'es'});`
|
||||||
|
const fixture = initWithTemplate(AppComp, `
|
||||||
|
{count, plural,
|
||||||
|
=0 {no email}
|
||||||
|
=one {one email}
|
||||||
|
=few {a few emails}
|
||||||
|
=other {lots of emails}
|
||||||
|
}`);
|
||||||
|
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
|
||||||
|
|
||||||
|
// Change detection cycle, no model changes
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
|
||||||
|
|
||||||
|
fixture.componentInstance.count = 3;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->');
|
||||||
|
|
||||||
|
fixture.componentInstance.count = 1;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 2-->');
|
||||||
|
|
||||||
|
fixture.componentInstance.count = 10;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->');
|
||||||
|
|
||||||
|
fixture.componentInstance.count = 20;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 2-->');
|
||||||
|
|
||||||
|
fixture.componentInstance.count = 0;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 2-->');
|
||||||
|
});
|
||||||
|
|
||||||
it('projection', () => {
|
it('projection', () => {
|
||||||
loadTranslations({
|
loadTranslations({
|
||||||
[computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]:
|
[computeMsgId('{VAR_PLURAL, plural, =1 {one} other {at least {INTERPOLATION} .}}')]:
|
||||||
|
|
Loading…
Reference in New Issue