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:
parent
18bf77204e
commit
535d9da6b6
@ -172,42 +172,6 @@ export function getPluralCase(locale: string, nLike: number | string): Plural {
|
|||||||
case 'xog':
|
case 'xog':
|
||||||
if (n === 1) return Plural.One;
|
if (n === 1) return Plural.One;
|
||||||
return Plural.Other;
|
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 'ak':
|
||||||
case 'ln':
|
case 'ln':
|
||||||
case 'mg':
|
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)
|
if (n === Math.floor(n) && n >= 0 && n <= 1 || n === Math.floor(n) && n >= 11 && n <= 99)
|
||||||
return Plural.One;
|
return Plural.One;
|
||||||
return Plural.Other;
|
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:
|
default:
|
||||||
return Plural.Other;
|
return Plural.Other;
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,16 @@ export function main() {
|
|||||||
expect(l10n.getPluralCategory(24)).toEqual('few');
|
expect(l10n.getPluralCategory(24)).toEqual('few');
|
||||||
expect(l10n.getPluralCategory(25)).toEqual('other');
|
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', () => {
|
describe('getPluralCategory', () => {
|
||||||
@ -157,4 +167,4 @@ export function main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ const ruleToLang = {};
|
|||||||
const variants = [];
|
const variants = [];
|
||||||
const localeToVariant = {};
|
const localeToVariant = {};
|
||||||
const DEFAULT_RULE = `function anonymous(n\n/**/) {\nreturn"other"\n}`;
|
const DEFAULT_RULE = `function anonymous(n\n/**/) {\nreturn"other"\n}`;
|
||||||
|
const EMPTY_RULE = `function anonymous(n\n/**/) {\n\n}`;
|
||||||
|
|
||||||
locales.forEach(locale => {
|
locales.forEach(locale => {
|
||||||
const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
|
const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
|
||||||
@ -32,16 +33,15 @@ locales.forEach(locale => {
|
|||||||
ruleToLang[rule].push(lang);
|
ruleToLang[rule].push(lang);
|
||||||
});
|
});
|
||||||
|
|
||||||
var nextVariantCode = 'a'.charCodeAt(0);
|
let nextVariantCode = 'a'.charCodeAt(0);
|
||||||
|
|
||||||
variants.forEach(locale => {
|
variants.forEach(locale => {
|
||||||
const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
|
const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
|
||||||
|
|
||||||
if (!rule) {
|
if (!rule) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapTo = null;
|
let mapTo = null;
|
||||||
|
|
||||||
if (ruleToLang[rule]) {
|
if (ruleToLang[rule]) {
|
||||||
mapTo = ruleToLang[rule][0];
|
mapTo = ruleToLang[rule][0];
|
||||||
@ -65,27 +65,25 @@ function generateCode() {
|
|||||||
|
|
||||||
return `
|
return `
|
||||||
// This is generated code DO NOT MODIFY
|
// 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,
|
Zero,
|
||||||
One,
|
One,
|
||||||
Two,
|
Two,
|
||||||
Few,
|
Few,
|
||||||
Many,
|
Many,
|
||||||
Other
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPluralCase(locale: string, n: number|string): Plural {
|
|
||||||
` + generateVars() +
|
` + generateVars() +
|
||||||
generateRules() + `
|
generateRules() + `
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function generateRules() {
|
function generateRules() {
|
||||||
const codeParts = [`
|
const codeParts = [`
|
||||||
const lang = locale.split('_')[0].toLowerCase();
|
const lang = locale.split('-')[0].toLowerCase();
|
||||||
|
|
||||||
switch (lang) {`];
|
switch (lang) {`];
|
||||||
|
|
||||||
@ -95,8 +93,11 @@ switch (lang) {`];
|
|||||||
codeParts.push(` ${rule}`);
|
codeParts.push(` ${rule}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
codeParts.push(` default:
|
codeParts.push(` // When there is no specification, the default is always other
|
||||||
return Plural.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');
|
return codeParts.join('\n');
|
||||||
@ -104,17 +105,22 @@ switch (lang) {`];
|
|||||||
|
|
||||||
function generateVars(){
|
function generateVars(){
|
||||||
return `
|
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
|
// TODO(vicb): lazy compute
|
||||||
if (typeof nLike === 'string') {
|
if (typeof nLike === 'string') {
|
||||||
nLike = parseInt(<string>nLike, 10);
|
nLike = parseInt(<string>nLike, 10);
|
||||||
}
|
}
|
||||||
const n: number = nLike as number;
|
const n: number = nLike as number;
|
||||||
const nDecimal = n.toString().replace(/^[^.]*\\.?/, "");
|
const nDecimal = n.toString().replace(/^[^.]*\\.?/, '');
|
||||||
const i = Math.floor(Math.abs(n));
|
const i = Math.floor(Math.abs(n));
|
||||||
const v = nDecimal.length;
|
const v = nDecimal.length;
|
||||||
const f = parseInt(nDecimal, 10);
|
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
|
* 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) {
|
function getVariantLang(locale, rule) {
|
||||||
var lang = locale.split('_')[0];
|
let lang = locale.split('_')[0];
|
||||||
|
|
||||||
if (!langToRule[lang]) {
|
if (!langToRule[lang]) {
|
||||||
langToRule[lang] = rule;
|
langToRule[lang] = rule;
|
||||||
@ -147,7 +152,7 @@ function getVariantLang(locale, rule) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeRule(fn) {
|
function normalizeRule(fn) {
|
||||||
if (fn === DEFAULT_RULE) return;
|
if (fn === DEFAULT_RULE || fn === EMPTY_RULE) return;
|
||||||
|
|
||||||
return fn
|
return fn
|
||||||
.replace(toRegExp('function anonymous(n\n/**/) {\n'), '')
|
.replace(toRegExp('function anonymous(n\n/**/) {\n'), '')
|
||||||
@ -171,4 +176,4 @@ function normalizeRule(fn) {
|
|||||||
|
|
||||||
function toRegExp(s) {
|
function toRegExp(s) {
|
||||||
return new RegExp(s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'), 'g');
|
return new RegExp(s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'), 'g');
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user