Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | this.EXPORTED_SYMBOLS = [ "PluralForm" ]; |
michael@0 | 6 | |
michael@0 | 7 | /** |
michael@0 | 8 | * This module provides the PluralForm object which contains a method to figure |
michael@0 | 9 | * out which plural form of a word to use for a given number based on the |
michael@0 | 10 | * current localization. There is also a makeGetter method that creates a get |
michael@0 | 11 | * function for the desired plural rule. This is useful for extensions that |
michael@0 | 12 | * specify their own plural rule instead of relying on the browser default. |
michael@0 | 13 | * (I.e., the extension hasn't been localized to the browser's locale.) |
michael@0 | 14 | * |
michael@0 | 15 | * See: http://developer.mozilla.org/en/docs/Localization_and_Plurals |
michael@0 | 16 | * |
michael@0 | 17 | * List of methods: |
michael@0 | 18 | * |
michael@0 | 19 | * string pluralForm |
michael@0 | 20 | * get(int aNum, string aWords) |
michael@0 | 21 | * |
michael@0 | 22 | * int numForms |
michael@0 | 23 | * numForms() |
michael@0 | 24 | * |
michael@0 | 25 | * [string pluralForm get(int aNum, string aWords), int numForms numForms()] |
michael@0 | 26 | * makeGetter(int aRuleNum) |
michael@0 | 27 | * Note: Basically, makeGetter returns 2 functions that do "get" and "numForm" |
michael@0 | 28 | */ |
michael@0 | 29 | |
michael@0 | 30 | const Cc = Components.classes; |
michael@0 | 31 | const Ci = Components.interfaces; |
michael@0 | 32 | |
michael@0 | 33 | const kIntlProperties = "chrome://global/locale/intl.properties"; |
michael@0 | 34 | |
michael@0 | 35 | // These are the available plural functions that give the appropriate index |
michael@0 | 36 | // based on the plural rule number specified. The first element is the number |
michael@0 | 37 | // of plural forms and the second is the function to figure out the index. |
michael@0 | 38 | let gFunctions = [ |
michael@0 | 39 | // 0: Chinese |
michael@0 | 40 | [1, function(n) 0], |
michael@0 | 41 | // 1: English |
michael@0 | 42 | [2, function(n) n!=1?1:0], |
michael@0 | 43 | // 2: French |
michael@0 | 44 | [2, function(n) n>1?1:0], |
michael@0 | 45 | // 3: Latvian |
michael@0 | 46 | [3, function(n) n%10==1&&n%100!=11?1:n!=0?2:0], |
michael@0 | 47 | // 4: Scottish Gaelic |
michael@0 | 48 | [4, function(n) n==1||n==11?0:n==2||n==12?1:n>0&&n<20?2:3], |
michael@0 | 49 | // 5: Romanian |
michael@0 | 50 | [3, function(n) n==1?0:n==0||n%100>0&&n%100<20?1:2], |
michael@0 | 51 | // 6: Lithuanian |
michael@0 | 52 | [3, function(n) n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?2:1], |
michael@0 | 53 | // 7: Russian |
michael@0 | 54 | [3, function(n) n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2], |
michael@0 | 55 | // 8: Slovak |
michael@0 | 56 | [3, function(n) n==1?0:n>=2&&n<=4?1:2], |
michael@0 | 57 | // 9: Polish |
michael@0 | 58 | [3, function(n) n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2], |
michael@0 | 59 | // 10: Slovenian |
michael@0 | 60 | [4, function(n) n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3], |
michael@0 | 61 | // 11: Irish Gaeilge |
michael@0 | 62 | [5, function(n) n==1?0:n==2?1:n>=3&&n<=6?2:n>=7&&n<=10?3:4], |
michael@0 | 63 | // 12: Arabic |
michael@0 | 64 | [6, function(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], |
michael@0 | 65 | // 13: Maltese |
michael@0 | 66 | [4, function(n) n==1?0:n==0||n%100>0&&n%100<=10?1:n%100>10&&n%100<20?2:3], |
michael@0 | 67 | // 14: Macedonian |
michael@0 | 68 | [3, function(n) n%10==1?0:n%10==2?1:2], |
michael@0 | 69 | // 15: Icelandic |
michael@0 | 70 | [2, function(n) n%10==1&&n%100!=11?0:1], |
michael@0 | 71 | // 16: Breton |
michael@0 | 72 | [5, function(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], |
michael@0 | 73 | ]; |
michael@0 | 74 | |
michael@0 | 75 | this.PluralForm = { |
michael@0 | 76 | /** |
michael@0 | 77 | * Get the correct plural form of a word based on the number |
michael@0 | 78 | * |
michael@0 | 79 | * @param aNum |
michael@0 | 80 | * The number to decide which plural form to use |
michael@0 | 81 | * @param aWords |
michael@0 | 82 | * A semi-colon (;) separated string of words to pick the plural form |
michael@0 | 83 | * @return The appropriate plural form of the word |
michael@0 | 84 | */ |
michael@0 | 85 | get get() |
michael@0 | 86 | { |
michael@0 | 87 | // This method will lazily load to avoid perf when it is first needed and |
michael@0 | 88 | // creates getPluralForm function. The function it creates is based on the |
michael@0 | 89 | // value of pluralRule specified in the intl stringbundle. |
michael@0 | 90 | // See: http://developer.mozilla.org/en/docs/Localization_and_Plurals |
michael@0 | 91 | |
michael@0 | 92 | // Delete the getters to be overwritten |
michael@0 | 93 | delete PluralForm.numForms; |
michael@0 | 94 | delete PluralForm.get; |
michael@0 | 95 | |
michael@0 | 96 | // Get the plural rule number from the intl stringbundle |
michael@0 | 97 | let ruleNum = Number(Cc["@mozilla.org/intl/stringbundle;1"]. |
michael@0 | 98 | getService(Ci.nsIStringBundleService).createBundle(kIntlProperties). |
michael@0 | 99 | GetStringFromName("pluralRule")); |
michael@0 | 100 | |
michael@0 | 101 | // Make the plural form get function and set it as the default get |
michael@0 | 102 | [PluralForm.get, PluralForm.numForms] = PluralForm.makeGetter(ruleNum); |
michael@0 | 103 | return PluralForm.get; |
michael@0 | 104 | }, |
michael@0 | 105 | |
michael@0 | 106 | /** |
michael@0 | 107 | * Create a pair of plural form functions for the given plural rule number. |
michael@0 | 108 | * |
michael@0 | 109 | * @param aRuleNum |
michael@0 | 110 | * The plural rule number to create functions |
michael@0 | 111 | * @return A pair: [function that gets the right plural form, |
michael@0 | 112 | * function that returns the number of plural forms] |
michael@0 | 113 | */ |
michael@0 | 114 | makeGetter: function(aRuleNum) |
michael@0 | 115 | { |
michael@0 | 116 | // Default to "all plural" if the value is out of bounds or invalid |
michael@0 | 117 | if (aRuleNum < 0 || aRuleNum >= gFunctions.length || isNaN(aRuleNum)) { |
michael@0 | 118 | log(["Invalid rule number: ", aRuleNum, " -- defaulting to 0"]); |
michael@0 | 119 | aRuleNum = 0; |
michael@0 | 120 | } |
michael@0 | 121 | |
michael@0 | 122 | // Get the desired pluralRule function |
michael@0 | 123 | let [numForms, pluralFunc] = gFunctions[aRuleNum]; |
michael@0 | 124 | |
michael@0 | 125 | // Return functions that give 1) the number of forms and 2) gets the right |
michael@0 | 126 | // plural form |
michael@0 | 127 | return [function(aNum, aWords) { |
michael@0 | 128 | // Figure out which index to use for the semi-colon separated words |
michael@0 | 129 | let index = pluralFunc(aNum ? Number(aNum) : 0); |
michael@0 | 130 | let words = aWords ? aWords.split(/;/) : [""]; |
michael@0 | 131 | |
michael@0 | 132 | // Explicitly check bounds to avoid strict warnings |
michael@0 | 133 | let ret = index < words.length ? words[index] : undefined; |
michael@0 | 134 | |
michael@0 | 135 | // Check for array out of bounds or empty strings |
michael@0 | 136 | if ((ret == undefined) || (ret == "")) { |
michael@0 | 137 | // Report the caller to help figure out who is causing badness |
michael@0 | 138 | let caller = PluralForm.get.caller ? PluralForm.get.caller.name : "top"; |
michael@0 | 139 | |
michael@0 | 140 | // Display a message in the error console |
michael@0 | 141 | log(["Index #", index, " of '", aWords, "' for value ", aNum, |
michael@0 | 142 | " is invalid -- plural rule #", aRuleNum, "; called by ", caller]); |
michael@0 | 143 | |
michael@0 | 144 | // Default to the first entry (which might be empty, but not undefined) |
michael@0 | 145 | ret = words[0]; |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | return ret; |
michael@0 | 149 | }, function() numForms]; |
michael@0 | 150 | }, |
michael@0 | 151 | |
michael@0 | 152 | /** |
michael@0 | 153 | * Get the number of forms for the current plural rule |
michael@0 | 154 | * |
michael@0 | 155 | * @return The number of forms |
michael@0 | 156 | */ |
michael@0 | 157 | get numForms() |
michael@0 | 158 | { |
michael@0 | 159 | // We lazily load numForms, so trigger the init logic with get() |
michael@0 | 160 | PluralForm.get(); |
michael@0 | 161 | return PluralForm.numForms; |
michael@0 | 162 | }, |
michael@0 | 163 | }; |
michael@0 | 164 | |
michael@0 | 165 | /** |
michael@0 | 166 | * Private helper function to log errors to the error console and command line |
michael@0 | 167 | * |
michael@0 | 168 | * @param aMsg |
michael@0 | 169 | * Error message to log or an array of strings to concat |
michael@0 | 170 | */ |
michael@0 | 171 | function log(aMsg) |
michael@0 | 172 | { |
michael@0 | 173 | let msg = "PluralForm.jsm: " + (aMsg.join ? aMsg.join("") : aMsg); |
michael@0 | 174 | Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService). |
michael@0 | 175 | logStringMessage(msg); |
michael@0 | 176 | dump(msg + "\n"); |
michael@0 | 177 | } |