plural-form.js (5205B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // Disable eslint warnings to preserve original code style. 6 /* eslint-disable */ 7 8 /** 9 * This module provides the PluralForm object which contains a method to figure 10 * out which plural form of a word to use for a given number based on the 11 * current localization. 12 */ 13 14 const PluralForm = { 15 init() 16 { 17 delete this.numForms; 18 delete this.get; 19 20 let [numForms, pluralFunc] = this.getPluralRule(); 21 this.numForms = () => numForms; 22 this.get = (aNum, aWords) => { 23 // Figure out which index to use for the semi-colon separated words 24 let index = pluralFunc(aNum ? Number(aNum) : 0); 25 let words = aWords ? aWords.split(/;/) : [""]; 26 27 // Explicitly check bounds to avoid strict warnings 28 let ret = index < words.length ? words[index] : undefined; 29 30 // Check for array out of bounds or empty strings 31 if ((ret == undefined) || (ret == "")) { 32 console.warn(`plural-form.js: Index #${index} of '${aWords}' for value ${aNum} is invalid;\n`); 33 34 // Default to the first entry (which might be empty, but not undefined) 35 ret = words[0]; 36 } 37 38 return ret; 39 }; 40 }, 41 42 /** 43 * Get the correct plural form of a word based on the number 44 * 45 * @param aNum 46 * The number to decide which plural form to use 47 * @param aWords 48 * A semi-colon (;) separated string of words to pick the plural form 49 * @return The appropriate plural form of the word 50 */ 51 get get() 52 { 53 this.init(); 54 return this.get; 55 }, 56 57 /** 58 * Get the number of forms for the current plural rule 59 * 60 * @return The number of forms 61 */ 62 get numForms() 63 { 64 this.init(); 65 return this.numForms; 66 }, 67 68 /** 69 * Selects the number of plural categories and the function for selecting between them. 70 * 71 * The default is to use the same plural rules as English, which has "one" and "other" categories. 72 * This is only used for a small number of devtools messages that have a custom format; 73 * Fluent plurals in general rely on Unicode Common Locale Data Repository data. 74 * 75 * @return The available plural function that gives the appropriate index 76 * based on the plural rule number specified. The first element is the number 77 * of plural forms and the second is the function to figure out the index. 78 */ 79 getPluralRule() 80 { 81 let appLocale = Services.locale.appLocalesAsLangTags[0]; 82 83 // See searchfox.org/firefox-main/rev/f6385e6644d5d4343d33b692810275c434122199/intl/docs/locale.rst#463-471 84 // Swap ja-JP-mac (legacy locale in gecko, but invalid) with the valid ja-JP-macos 85 if (appLocale === "ja-JP-mac") { 86 appLocale = "ja-JP-macos"; 87 } 88 89 const locale = new Intl.Locale(appLocale); 90 switch (locale.language) { 91 case "bo": 92 case "id": 93 case "ja": 94 case "km": 95 case "ko": 96 case "lo": 97 case "meh": 98 case "ms": 99 case "my": 100 case "th": 101 case "vi": 102 case "wo": 103 case "zh": 104 return [1, (n) => 0]; 105 case "bn": 106 case "fa": 107 case "fr": 108 case "gu": 109 case "hi": 110 case "oc": 111 case "pa": 112 return [2, (n) => n>1?1:0]; 113 case "ltg": 114 case "lv": 115 return [3, (n) => n%10==1&&n%100!=11?1:n%10==0?0:2]; 116 case "gd": 117 return [4, (n) => n==1||n==11?0:n==2||n==12?1:n>0&&n<20?2:3]; 118 case "ro": 119 return [3, (n) => n==1?0:n==0||n%100>0&&n%100<20?1:2]; 120 case "lt": 121 return [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?2:1]; 122 case "be": 123 case "ru": 124 case "uk": 125 return [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2]; 126 case "cs": 127 case "sk": 128 return [3, (n) => n==1?0:n>=2&&n<=4?1:2]; 129 case "pl": 130 case "szl": 131 return [3, (n) => n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2]; 132 case "dsb": 133 case "hsb": 134 case "sl": 135 return [4, (n) => n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3]; 136 case "ga": 137 return [5, (n) => n==1?0:n==2?1:n>=3&&n<=6?2:n>=7&&n<=10?3:4]; 138 case "ar": 139 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]; 140 case "is": 141 case "mk": 142 return [4, (n) => n==1?0:n==0||n%100>0&&n%100<=10?1:n%100>10&&n%100<20?2:3]; 143 case "br": 144 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]; 145 case "cy": 146 return [6, (n) => n==0?0:n==1?1:n==2?2:n==3?3:n==6?4:5]; 147 case "bs": 148 case "hr": 149 case "sr": 150 return [3, (n) => n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2]; 151 default: 152 return [2, (n) => n!=1?1:0]; 153 } 154 } 155 }; 156 157 exports.PluralForm = PluralForm; 158 exports.get = PluralForm.get; 159 160 /* eslint-enable */