161 lines
5.1 KiB
JavaScript
161 lines
5.1 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
// Disable eslint warnings to preserve original code style.
|
|
/* eslint-disable */
|
|
|
|
/**
|
|
* This module provides the PluralForm object which contains a method to figure
|
|
* out which plural form of a word to use for a given number based on the
|
|
* current localization.
|
|
*/
|
|
|
|
const PluralForm = {
|
|
init()
|
|
{
|
|
delete this.numForms;
|
|
delete this.get;
|
|
|
|
let [numForms, pluralFunc] = this.getPluralRule();
|
|
this.numForms = () => numForms;
|
|
this.get = (aNum, aWords) => {
|
|
// Figure out which index to use for the semi-colon separated words
|
|
let index = pluralFunc(aNum ? Number(aNum) : 0);
|
|
let words = aWords ? aWords.split(/;/) : [""];
|
|
|
|
// Explicitly check bounds to avoid strict warnings
|
|
let ret = index < words.length ? words[index] : undefined;
|
|
|
|
// Check for array out of bounds or empty strings
|
|
if ((ret == undefined) || (ret == "")) {
|
|
console.warn(`plural-form.js: Index #${index} of '${aWords}' for value ${aNum} is invalid;\n`);
|
|
|
|
// Default to the first entry (which might be empty, but not undefined)
|
|
ret = words[0];
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Get the correct plural form of a word based on the number
|
|
*
|
|
* @param aNum
|
|
* The number to decide which plural form to use
|
|
* @param aWords
|
|
* A semi-colon (;) separated string of words to pick the plural form
|
|
* @return The appropriate plural form of the word
|
|
*/
|
|
get get()
|
|
{
|
|
this.init();
|
|
return this.get;
|
|
},
|
|
|
|
/**
|
|
* Get the number of forms for the current plural rule
|
|
*
|
|
* @return The number of forms
|
|
*/
|
|
get numForms()
|
|
{
|
|
this.init();
|
|
return this.numForms;
|
|
},
|
|
|
|
/**
|
|
* Selects the number of plural categories and the function for selecting between them.
|
|
*
|
|
* The default is to use the same plural rules as English, which has "one" and "other" categories.
|
|
* This is only used for a small number of devtools messages that have a custom format;
|
|
* Fluent plurals in general rely on Unicode Common Locale Data Repository data.
|
|
*
|
|
* @return The available plural function that gives the appropriate index
|
|
* based on the plural rule number specified. The first element is the number
|
|
* of plural forms and the second is the function to figure out the index.
|
|
*/
|
|
getPluralRule()
|
|
{
|
|
let appLocale = Services.locale.appLocalesAsLangTags[0];
|
|
|
|
// See searchfox.org/firefox-main/rev/f6385e6644d5d4343d33b692810275c434122199/intl/docs/locale.rst#463-471
|
|
// Swap ja-JP-mac (legacy locale in gecko, but invalid) with the valid ja-JP-macos
|
|
if (appLocale === "ja-JP-mac") {
|
|
appLocale = "ja-JP-macos";
|
|
}
|
|
|
|
const locale = new Intl.Locale(appLocale);
|
|
switch (locale.language) {
|
|
case "bo":
|
|
case "id":
|
|
case "ja":
|
|
case "km":
|
|
case "ko":
|
|
case "lo":
|
|
case "meh":
|
|
case "ms":
|
|
case "my":
|
|
case "th":
|
|
case "vi":
|
|
case "wo":
|
|
case "zh":
|
|
return [1, (n) => 0];
|
|
case "bn":
|
|
case "fa":
|
|
case "fr":
|
|
case "gu":
|
|
case "hi":
|
|
case "oc":
|
|
case "pa":
|
|
return [2, (n) => n>1?1:0];
|
|
case "ltg":
|
|
case "lv":
|
|
return [3, (n) => n%10==1&&n%100!=11?1:n%10==0?0:2];
|
|
case "gd":
|
|
return [4, (n) => n==1||n==11?0:n==2||n==12?1:n>0&&n<20?2:3];
|
|
case "ro":
|
|
return [3, (n) => n==1?0:n==0||n%100>0&&n%100<20?1:2];
|
|
case "lt":
|
|
return [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?2:1];
|
|
case "be":
|
|
case "ru":
|
|
case "uk":
|
|
return [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2];
|
|
case "cs":
|
|
case "sk":
|
|
return [3, (n) => n==1?0:n>=2&&n<=4?1:2];
|
|
case "pl":
|
|
case "szl":
|
|
return [3, (n) => n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2];
|
|
case "dsb":
|
|
case "hsb":
|
|
case "sl":
|
|
return [4, (n) => n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3];
|
|
case "ga":
|
|
return [5, (n) => n==1?0:n==2?1:n>=3&&n<=6?2:n>=7&&n<=10?3:4];
|
|
case "ar":
|
|
return [6, (n) => n==0?5:n==1?0:n==2?1:n%100>=3&&n%100<=10?2:n%100>=11&&n%100<=99?3:4];
|
|
case "is":
|
|
case "mk":
|
|
return [4, (n) => n==1?0:n==0||n%100>0&&n%100<=10?1:n%100>10&&n%100<20?2:3];
|
|
case "br":
|
|
return [5, (n) => n%10==1&&n%100!=11&&n%100!=71&&n%100!=91?0:n%10==2&&n%100!=12&&n%100!=72&&n%100!=92?1:(n%10==3||n%10==4||n%10==9)&&n%100!=13&&n%100!=14&&n%100!=19&&n%100!=73&&n%100!=74&&n%100!=79&&n%100!=93&&n%100!=94&&n%100!=99?2:n%1000000==0&&n!=0?3:4];
|
|
case "cy":
|
|
return [6, (n) => n==0?0:n==1?1:n==2?2:n==3?3:n==6?4:5];
|
|
case "bs":
|
|
case "hr":
|
|
case "sr":
|
|
return [3, (n) => n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2];
|
|
default:
|
|
return [2, (n) => n!=1?1:0];
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.PluralForm = PluralForm;
|
|
exports.get = PluralForm.get;
|
|
|
|
/* eslint-enable */
|