fix(common): always use 'other' case for locales with no plural rules (#16990)

Locales with no rules were using the wrong plural rule instead of the default.
This commit is contained in:
Olivier Combe 2017-05-30 19:46:36 +02:00 committed by Victor Berchet
parent 18bf77204e
commit 535d9da6b6
3 changed files with 38 additions and 56 deletions

View File

@ -172,42 +172,6 @@ export function getPluralCase(locale: string, nLike: number | string): Plural {
case 'xog':
if (n === 1) return Plural.One;
return Plural.Other;
case 'agq':
case 'bas':
case 'cu':
case 'dav':
case 'dje':
case 'dua':
case 'dyo':
case 'ebu':
case 'ewo':
case 'guz':
case 'kam':
case 'khq':
case 'ki':
case 'kln':
case 'kok':
case 'ksf':
case 'lrc':
case 'lu':
case 'luo':
case 'luy':
case 'mer':
case 'mfe':
case 'mgh':
case 'mua':
case 'mzn':
case 'nmg':
case 'nus':
case 'qu':
case 'rn':
case 'rw':
case 'sbp':
case 'twq':
case 'vai':
case 'yav':
case 'yue':
case 'zgh':
case 'ak':
case 'ln':
case 'mg':
@ -428,6 +392,9 @@ export function getPluralCase(locale: string, nLike: number | string): Plural {
if (n === Math.floor(n) && n >= 0 && n <= 1 || n === Math.floor(n) && n >= 11 && n <= 99)
return Plural.One;
return Plural.Other;
// When there is no specification, the default is always "other"
// Spec: http://cldr.unicode.org/index/cldr-spec/plural-rules
// > other (required—general plural form — also used if the language only has a single form)
default:
return Plural.Other;
}

View File

@ -119,6 +119,16 @@ export function main() {
expect(l10n.getPluralCategory(24)).toEqual('few');
expect(l10n.getPluralCategory(25)).toEqual('other');
});
it('should return the default value for a locale with no rule', () => {
const l10n = new NgLocaleLocalization('zgh');
expect(l10n.getPluralCategory(0)).toEqual('other');
expect(l10n.getPluralCategory(1)).toEqual('other');
expect(l10n.getPluralCategory(3)).toEqual('other');
expect(l10n.getPluralCategory(5)).toEqual('other');
expect(l10n.getPluralCategory(10)).toEqual('other');
});
});
describe('getPluralCategory', () => {
@ -157,4 +167,4 @@ export function main() {
});
});
});
}
}

View File

@ -14,6 +14,7 @@ const ruleToLang = {};
const variants = [];
const localeToVariant = {};
const DEFAULT_RULE = `function anonymous(n\n/**/) {\nreturn"other"\n}`;
const EMPTY_RULE = `function anonymous(n\n/**/) {\n\n}`;
locales.forEach(locale => {
const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
@ -32,16 +33,15 @@ locales.forEach(locale => {
ruleToLang[rule].push(lang);
});
var nextVariantCode = 'a'.charCodeAt(0);
let nextVariantCode = 'a'.charCodeAt(0);
variants.forEach(locale => {
const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
if (!rule) {
return;
}
var mapTo = null;
let mapTo = null;
if (ruleToLang[rule]) {
mapTo = ruleToLang[rule][0];
@ -65,27 +65,25 @@ function generateCode() {
return `
// This is generated code DO NOT MODIFY
// see angular2/script/cldr/gen_plural_rules.js
// see angular/script/cldr/gen_plural_rules.js
enum Plural {
/** @experimental */
export enum Plural {
Zero,
One,
Two,
Few,
Many,
Other
Other,
}
function getPluralCase(locale: string, n: number|string): Plural {
` + generateVars() +
generateRules() + `
}`;
}
function generateRules() {
const codeParts = [`
const lang = locale.split('_')[0].toLowerCase();
const lang = locale.split('-')[0].toLowerCase();
switch (lang) {`];
@ -95,8 +93,11 @@ switch (lang) {`];
codeParts.push(` ${rule}`);
});
codeParts.push(` default:
return Plural.Other;
codeParts.push(` // When there is no specification, the default is always other
// see http://cldr.unicode.org/index/cldr-spec/plural-rules
// "other (required—general plural form — also used if the language only has a single form)"
default:
return Plural.Other;
}`);
return codeParts.join('\n');
@ -104,17 +105,22 @@ switch (lang) {`];
function generateVars(){
return `
function getPluralCase(locale: string, nLike: number | string): Plural {
/**
* Returns the plural case based on the locale
*
* @experimental
*/
export function getPluralCase(locale: string, nLike: number | string): Plural {
// TODO(vicb): lazy compute
if (typeof nLike === 'string') {
nLike = parseInt(<string>nLike, 10);
}
const n: number = nLike as number;
const nDecimal = n.toString().replace(/^[^.]*\\.?/, "");
const nDecimal = n.toString().replace(/^[^.]*\\.?/, '');
const i = Math.floor(Math.abs(n));
const v = nDecimal.length;
const f = parseInt(nDecimal, 10);
const t = parseInt(n.toString().replace(/^[^.]*\\.?|0+$/g,""), 10) || 0;
const t = parseInt(n.toString().replace(/^[^.]*\\.?|0+$/g,''), 10) || 0;
`;
}
@ -126,12 +132,11 @@ function checkMapping() {
}
}
/**
* If the language rule do not match an existing language rule, flag it as variant and handle it at the end
*/
function getVariantLang(locale, rule) {
var lang = locale.split('_')[0];
let lang = locale.split('_')[0];
if (!langToRule[lang]) {
langToRule[lang] = rule;
@ -147,7 +152,7 @@ function getVariantLang(locale, rule) {
}
function normalizeRule(fn) {
if (fn === DEFAULT_RULE) return;
if (fn === DEFAULT_RULE || fn === EMPTY_RULE) return;
return fn
.replace(toRegExp('function anonymous(n\n/**/) {\n'), '')
@ -171,4 +176,4 @@ function normalizeRule(fn) {
function toRegExp(s) {
return new RegExp(s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'), 'g');
}
}