tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */