summaryrefslogtreecommitdiffstats
path: root/toolkit/jetpack/sdk/l10n.js
blob: db5a9d7b632a85d5829af80ea651a4b7edec2579 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* 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/. */
"use strict";

module.metadata = {
  "stability": "stable"
};

const json = require("./l10n/json/core");
const { get: getKey } = require("./l10n/core");
const properties = require("./l10n/properties/core");
const { getRulesForLocale } = require("./l10n/plural-rules");

// Retrieve the plural mapping function
var pluralMappingFunction = getRulesForLocale(json.language()) ||
                            getRulesForLocale("en");

exports.get = function get(k) {
  // For now, we only accept a "string" as first argument
  // TODO: handle plural forms in gettext pattern
  if (typeof k !== "string")
    throw new Error("First argument of localization method should be a string");
  let n = arguments[1];

  // Get translation from big hashmap or default to hard coded string:
  let localized = getKey(k, n) || k;

  // # Simplest usecase:
  //   // String hard coded in source code:
  //   _("Hello world")
  //   // Identifier of a key stored in properties file
  //   _("helloString")
  if (arguments.length <= 1)
    return localized;

  let args = Array.slice(arguments);
  let placeholders = [null, ...args.slice(typeof(n) === "number" ? 2 : 1)];

  if (typeof localized == "object" && "other" in localized) {
    // # Plural form:
    //   // Strings hard coded in source code:
    //   _(["One download", "%d downloads"], 10);
    //   // Identifier of a key stored in properties file
    //   _("downloadNumber", 0);
    let n = arguments[1];

    // First handle simple universal forms that may not be mandatory
    // for each language, (i.e. not different than 'other' form,
    // but still usefull for better phrasing)
    // For example 0 in english is the same form than 'other'
    // but we accept 'zero' form if specified in localization file
    if (n === 0 && "zero" in localized)
      localized = localized["zero"];
    else if (n === 1 && "one" in localized)
      localized = localized["one"];
    else if (n === 2 && "two" in localized)
      localized = localized["two"];
    else {
      let pluralForm = pluralMappingFunction(n);
      if (pluralForm in localized)
        localized = localized[pluralForm];
      else // Fallback in case of error: missing plural form
        localized = localized["other"];
    }

    // Simulate a string with one placeholder:
    args = [null, n];
  }

  // # String with placeholders:
  //   // Strings hard coded in source code:
  //   _("Hello %s", username)
  //   // Identifier of a key stored in properties file
  //   _("helloString", username)
  // * We supports `%1s`, `%2s`, ... pattern in order to change arguments order
  // in translation.
  // * In case of plural form, we has `%d` instead of `%s`.
  let offset = 1;
  if (placeholders.length > 1) {
    args = placeholders;
  }

  localized = localized.replace(/%(\d*)[sd]/g, (v, n) => {
    let rv = args[n != "" ? n : offset];
    offset++;
    return rv;
  });

  return localized;
}