From 8eb28f45a26023004571e4678577b8182a841dbf Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sat, 5 Aug 2017 21:29:31 -0700 Subject: [PATCH] Bug 1350646: Part 9 - Remove SDK l10n modules. r=Mossop MozReview-Commit-ID: 8CZq3jjxnv0 --HG-- extra : source : 5a45d9e25a007c6ab18bd8da4a41f0fe3b9318c0 --- addon-sdk/moz.build | 11 - addon-sdk/source/lib/sdk/content/l10n-html.js | 132 ------ addon-sdk/source/lib/sdk/l10n.js | 94 ---- addon-sdk/source/lib/sdk/l10n/core.js | 15 - addon-sdk/source/lib/sdk/l10n/html.js | 32 -- addon-sdk/source/lib/sdk/l10n/json/core.js | 36 -- addon-sdk/source/lib/sdk/l10n/loader.js | 70 --- addon-sdk/source/lib/sdk/l10n/locale.js | 85 ---- addon-sdk/source/lib/sdk/l10n/plural-rules.js | 407 ------------------ addon-sdk/source/lib/sdk/l10n/prefs.js | 51 --- .../source/lib/sdk/l10n/properties/core.js | 89 ---- .../lib/sdk/preferences/native-options.js | 178 -------- 12 files changed, 1200 deletions(-) delete mode 100644 addon-sdk/source/lib/sdk/content/l10n-html.js delete mode 100644 addon-sdk/source/lib/sdk/l10n.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/core.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/html.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/json/core.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/loader.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/locale.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/plural-rules.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/prefs.js delete mode 100644 addon-sdk/source/lib/sdk/l10n/properties/core.js delete mode 100644 addon-sdk/source/lib/sdk/preferences/native-options.js diff --git a/addon-sdk/moz.build b/addon-sdk/moz.build index 757f9e3ea3f2..086bf6e096d0 100644 --- a/addon-sdk/moz.build +++ b/addon-sdk/moz.build @@ -43,7 +43,6 @@ modules = [ 'sdk/content/content-worker.js', 'sdk/content/content.js', 'sdk/content/events.js', - 'sdk/content/l10n-html.js', 'sdk/content/loader.js', 'sdk/content/mod.js', 'sdk/content/sandbox.js', @@ -81,15 +80,6 @@ modules = [ 'sdk/io/fs.js', 'sdk/io/stream.js', 'sdk/io/text-streams.js', - 'sdk/l10n.js', - 'sdk/l10n/core.js', - 'sdk/l10n/html.js', - 'sdk/l10n/json/core.js', - 'sdk/l10n/loader.js', - 'sdk/l10n/locale.js', - 'sdk/l10n/plural-rules.js', - 'sdk/l10n/prefs.js', - 'sdk/l10n/properties/core.js', 'sdk/lang/functional.js', 'sdk/lang/functional/concurrent.js', 'sdk/lang/functional/core.js', @@ -107,7 +97,6 @@ modules = [ 'sdk/passwords/utils.js', 'sdk/platform/xpcom.js', 'sdk/preferences/event-target.js', - 'sdk/preferences/native-options.js', 'sdk/preferences/service.js', 'sdk/preferences/utils.js', 'sdk/private-browsing.js', diff --git a/addon-sdk/source/lib/sdk/content/l10n-html.js b/addon-sdk/source/lib/sdk/content/l10n-html.js deleted file mode 100644 index 5287a89cb912..000000000000 --- a/addon-sdk/source/lib/sdk/content/l10n-html.js +++ /dev/null @@ -1,132 +0,0 @@ -/* 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": "unstable" -}; - -const { Ci, Cc, Cu } = require("chrome"); -lazyRequireModule(this, "../l10n/core", "core"); -lazyRequire(this, "../stylesheet/utils", "loadSheet", "removeSheet"); -const { process, frames } = require("../remote/child"); - -var observerService = Cc["@mozilla.org/observer-service;1"] - .getService(Ci.nsIObserverService); -const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm"); -const addObserver = ShimWaiver.getProperty(observerService, "addObserver"); -const removeObserver = ShimWaiver.getProperty(observerService, "removeObserver"); - -const assetsURI = require('../self').data.url(); - -const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}"; - -function translateElementAttributes(element) { - // Translateable attributes - const attrList = ['title', 'accesskey', 'alt', 'label', 'placeholder']; - const ariaAttrMap = { - 'ariaLabel': 'aria-label', - 'ariaValueText': 'aria-valuetext', - 'ariaMozHint': 'aria-moz-hint' - }; - const attrSeparator = '.'; - - // Try to translate each of the attributes - for (let attribute of attrList) { - const data = core.get(element.dataset.l10nId + attrSeparator + attribute); - if (data) - element.setAttribute(attribute, data); - } - - // Look for the aria attribute translations that match fxOS's aliases - for (let attrAlias in ariaAttrMap) { - const data = core.get(element.dataset.l10nId + attrSeparator + attrAlias); - if (data) - element.setAttribute(ariaAttrMap[attrAlias], data); - } -} - -// Taken from Gaia: -// https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470 -function translateElement(element) { - element = element || document; - - // check all translatable children (= w/ a `data-l10n-id' attribute) - var children = element.querySelectorAll('*[data-l10n-id]'); - var elementCount = children.length; - for (var i = 0; i < elementCount; i++) { - var child = children[i]; - - // translate the child - var key = child.dataset.l10nId; - var data = core.get(key); - if (data) - child.textContent = data; - - translateElementAttributes(child); - } -} -exports.translateElement = translateElement; - -function onDocumentReady2Translate(event) { - let document = event.target; - document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate); - - translateElement(document); - - try { - // Finally display document when we finished replacing all text content - if (document.defaultView) - removeSheet(document.defaultView, hideSheetUri, 'user'); - } - catch(e) { - console.exception(e); - } -} - -function onContentWindow(document) { - // Accept only HTML documents - if (!(document instanceof Ci.nsIDOMHTMLDocument)) - return; - - // Bug 769483: data:URI documents instanciated with nsIDOMParser - // have a null `location` attribute at this time - if (!document.location) - return; - - // Accept only document from this addon - if (document.location.href.indexOf(assetsURI) !== 0) - return; - - try { - // First hide content of the document in order to have content blinking - // between untranslated and translated states - loadSheet(document.defaultView, hideSheetUri, 'user'); - } - catch(e) { - console.exception(e); - } - // Wait for DOM tree to be built before applying localization - document.addEventListener("DOMContentLoaded", onDocumentReady2Translate); -} - -// Listen to creation of content documents in order to translate them as soon -// as possible in their loading process -const ON_CONTENT = "document-element-inserted"; -let enabled = false; -function enable() { - if (enabled) - return; - addObserver(onContentWindow, ON_CONTENT, false); - enabled = true; -} -process.port.on("sdk/l10n/html/enable", enable); - -function disable() { - if (!enabled) - return; - removeObserver(onContentWindow, ON_CONTENT); - enabled = false; -} -process.port.on("sdk/l10n/html/disable", disable); diff --git a/addon-sdk/source/lib/sdk/l10n.js b/addon-sdk/source/lib/sdk/l10n.js deleted file mode 100644 index 2e08debb2581..000000000000 --- a/addon-sdk/source/lib/sdk/l10n.js +++ /dev/null @@ -1,94 +0,0 @@ -/* 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" -}; - -lazyRequireModule(this, "./l10n/json/core", "json"); -lazyRequire(this, "./l10n/core", {"get": "getKey"}); -lazyRequireModule(this, "./l10n/properties/core", "properties"); -lazyRequire(this, "./l10n/plural-rules", "getRulesForLocale"); - -const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); - -// Retrieve the plural mapping function -XPCOMUtils.defineLazyGetter(this, "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; -} diff --git a/addon-sdk/source/lib/sdk/l10n/core.js b/addon-sdk/source/lib/sdk/l10n/core.js deleted file mode 100644 index 9947ff13d39a..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/core.js +++ /dev/null @@ -1,15 +0,0 @@ -/* 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"; - -lazyRequireModule(this, "./json/core", "json"); -lazyRequireModule(this, "./properties/core", "properties"); - -const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyGetter(this, "get", - () => json.usingJSON ? json.get : properties.get); - -module.exports = Object.freeze({ - get get() { return get; }, // ... yeah. -}); diff --git a/addon-sdk/source/lib/sdk/l10n/html.js b/addon-sdk/source/lib/sdk/l10n/html.js deleted file mode 100644 index fa2cf9cf07c9..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/html.js +++ /dev/null @@ -1,32 +0,0 @@ -/* 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": "unstable" -}; - -const { processes, remoteRequire } = require("../remote/parent"); -remoteRequire("sdk/content/l10n-html"); - -var enabled = false; -function enable() { - if (!enabled) { - processes.port.emit("sdk/l10n/html/enable"); - enabled = true; - } -} -exports.enable = enable; - -function disable() { - if (enabled) { - processes.port.emit("sdk/l10n/html/disable"); - enabled = false; - } -} -exports.disable = disable; - -processes.forEvery(process => { - process.port.emit(enabled ? "sdk/l10n/html/enable" : "sdk/l10n/html/disable"); -}); diff --git a/addon-sdk/source/lib/sdk/l10n/json/core.js b/addon-sdk/source/lib/sdk/l10n/json/core.js deleted file mode 100644 index af52f956f3d3..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/json/core.js +++ /dev/null @@ -1,36 +0,0 @@ -/* 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": "unstable" -}; - -var usingJSON = false; -var hash = {}, bestMatchingLocale = null; -try { - let data = require("@l10n/data"); - hash = data.hash; - bestMatchingLocale = data.bestMatchingLocale; - usingJSON = true; -} -catch(e) {} - -exports.usingJSON = usingJSON; - -// Returns the translation for a given key, if available. -exports.get = function get(k) { - return k in hash ? hash[k] : null; -} - -// Returns the full length locale code: ja-JP-mac, en-US or fr -exports.locale = function locale() { - return bestMatchingLocale; -} - -// Returns the short locale code: ja, en, fr -exports.language = function language() { - return bestMatchingLocale ? bestMatchingLocale.split("-")[0].toLowerCase() - : "en"; -} diff --git a/addon-sdk/source/lib/sdk/l10n/loader.js b/addon-sdk/source/lib/sdk/l10n/loader.js deleted file mode 100644 index b11d7db54ef4..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/loader.js +++ /dev/null @@ -1,70 +0,0 @@ -/* 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": "unstable" -}; - -const { Cc, Ci } = require("chrome"); -lazyRequire(this, "./locale", "getPreferedLocales", "findClosestLocale"); -lazyRequire(this, "../net/url", "readURI"); -lazyRequire(this, "../core/promise", "resolve"); - -function parseJsonURI(uri) { - return readURI(uri). - then(JSON.parse). - catch(function (error) { - throw Error("Failed to parse locale file:\n" + uri + "\n" + error); - }); -} - -// Returns the array stored in `locales.json` manifest that list available -// locales files -function getAvailableLocales(rootURI) { - let uri = rootURI + "locales.json"; - return parseJsonURI(uri).then(function (manifest) { - return "locales" in manifest && - Array.isArray(manifest.locales) ? - manifest.locales : []; - }); -} - -// Returns URI of the best locales file to use from the XPI -function getBestLocale(rootURI) { - // Read localization manifest file that contains list of available languages - return getAvailableLocales(rootURI).then(function (availableLocales) { - // Retrieve list of prefered locales to use - let preferedLocales = getPreferedLocales(); - - // Compute the most preferable locale to use by using these two lists - return findClosestLocale(availableLocales, preferedLocales); - }); -} - -/** - * Read localization files and returns a promise of data to put in `@l10n/data` - * pseudo module, in order to allow l10n/json/core to fetch it. - */ -exports.load = function load(rootURI) { - // First, search for a locale file: - return getBestLocale(rootURI).then(function (bestMatchingLocale) { - // It may be null if the addon doesn't have any locale file - if (!bestMatchingLocale) - return resolve(null); - - let localeURI = rootURI + "locale/" + bestMatchingLocale + ".json"; - - // Locale files only contains one big JSON object that is used as - // an hashtable of: "key to translate" => "translated key" - // TODO: We are likely to change this in order to be able to overload - // a specific key translation. For a specific package, module or line? - return parseJsonURI(localeURI).then(function (json) { - return { - hash: json, - bestMatchingLocale: bestMatchingLocale - }; - }); - }); -} diff --git a/addon-sdk/source/lib/sdk/l10n/locale.js b/addon-sdk/source/lib/sdk/l10n/locale.js deleted file mode 100644 index 2d358538e280..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/locale.js +++ /dev/null @@ -1,85 +0,0 @@ -/* 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": "unstable" -}; - -const prefs = require("../preferences/service"); -const { Cu, Cc, Ci } = require("chrome"); -const { Services } = Cu.import("resource://gre/modules/Services.jsm"); - -function getPreferedLocales(caseSensitve) { - const locales = Services.locale.getRequestedLocales(); - - // This API expects to always append en-US fallback, so for compatibility - // reasons, we're going to inject it here. - // See bug 1373061 for details. - if (!locales.includes('en-US')) { - locales.push('en-US'); - } - return locales; -} -exports.getPreferedLocales = getPreferedLocales; - -/** - * Selects the closest matching locale from a list of locales. - * - * @param aLocales - * An array of available locales - * @param aMatchLocales - * An array of prefered locales, ordered by priority. Most wanted first. - * Locales have to be in lowercase. - * If null, uses getPreferedLocales() results - * @return the best match for the currently selected locale - * - * Stolen from http://dxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm - */ -exports.findClosestLocale = function findClosestLocale(aLocales, aMatchLocales) { - aMatchLocales = aMatchLocales || getPreferedLocales(); - - // Holds the best matching localized resource - let bestmatch = null; - // The number of locale parts it matched with - let bestmatchcount = 0; - // The number of locale parts in the match - let bestpartcount = 0; - - for (let locale of aMatchLocales) { - let lparts = locale.split("-"); - for (let localized of aLocales) { - let found = localized.toLowerCase(); - // Exact match is returned immediately - if (locale == found) - return localized; - - let fparts = found.split("-"); - /* If we have found a possible match and this one isn't any longer - then we dont need to check further. */ - if (bestmatch && fparts.length < bestmatchcount) - continue; - - // Count the number of parts that match - let maxmatchcount = Math.min(fparts.length, lparts.length); - let matchcount = 0; - while (matchcount < maxmatchcount && - fparts[matchcount] == lparts[matchcount]) - matchcount++; - - /* If we matched more than the last best match or matched the same and - this locale is less specific than the last best match. */ - if (matchcount > bestmatchcount || - (matchcount == bestmatchcount && fparts.length < bestpartcount)) { - bestmatch = localized; - bestmatchcount = matchcount; - bestpartcount = fparts.length; - } - } - // If we found a valid match for this locale return it - if (bestmatch) - return bestmatch; - } - return null; -} diff --git a/addon-sdk/source/lib/sdk/l10n/plural-rules.js b/addon-sdk/source/lib/sdk/l10n/plural-rules.js deleted file mode 100644 index a3ef48a5efcf..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/plural-rules.js +++ /dev/null @@ -1,407 +0,0 @@ -/* 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/. */ - -// This file is automatically generated with /python-lib/plural-rules-generator.py -// Fetching data from: http://unicode.org/repos/cldr/trunk/common/supplemental/plurals.xml - -// Mapping of short locale name == to == > rule index in following list - -module.metadata = { - "stability": "unstable" -}; - -const LOCALES_TO_RULES = { - "af": 3, - "ak": 4, - "am": 4, - "ar": 1, - "asa": 3, - "az": 0, - "be": 11, - "bem": 3, - "bez": 3, - "bg": 3, - "bh": 4, - "bm": 0, - "bn": 3, - "bo": 0, - "br": 20, - "brx": 3, - "bs": 11, - "ca": 3, - "cgg": 3, - "chr": 3, - "cs": 12, - "cy": 17, - "da": 3, - "de": 3, - "dv": 3, - "dz": 0, - "ee": 3, - "el": 3, - "en": 3, - "eo": 3, - "es": 3, - "et": 3, - "eu": 3, - "fa": 0, - "ff": 5, - "fi": 3, - "fil": 4, - "fo": 3, - "fr": 5, - "fur": 3, - "fy": 3, - "ga": 8, - "gd": 24, - "gl": 3, - "gsw": 3, - "gu": 3, - "guw": 4, - "gv": 23, - "ha": 3, - "haw": 3, - "he": 2, - "hi": 4, - "hr": 11, - "hu": 0, - "id": 0, - "ig": 0, - "ii": 0, - "is": 3, - "it": 3, - "iu": 7, - "ja": 0, - "jmc": 3, - "jv": 0, - "ka": 0, - "kab": 5, - "kaj": 3, - "kcg": 3, - "kde": 0, - "kea": 0, - "kk": 3, - "kl": 3, - "km": 0, - "kn": 0, - "ko": 0, - "ksb": 3, - "ksh": 21, - "ku": 3, - "kw": 7, - "lag": 18, - "lb": 3, - "lg": 3, - "ln": 4, - "lo": 0, - "lt": 10, - "lv": 6, - "mas": 3, - "mg": 4, - "mk": 16, - "ml": 3, - "mn": 3, - "mo": 9, - "mr": 3, - "ms": 0, - "mt": 15, - "my": 0, - "nah": 3, - "naq": 7, - "nb": 3, - "nd": 3, - "ne": 3, - "nl": 3, - "nn": 3, - "no": 3, - "nr": 3, - "nso": 4, - "ny": 3, - "nyn": 3, - "om": 3, - "or": 3, - "pa": 3, - "pap": 3, - "pl": 13, - "ps": 3, - "pt": 3, - "rm": 3, - "ro": 9, - "rof": 3, - "ru": 11, - "rwk": 3, - "sah": 0, - "saq": 3, - "se": 7, - "seh": 3, - "ses": 0, - "sg": 0, - "sh": 11, - "shi": 19, - "sk": 12, - "sl": 14, - "sma": 7, - "smi": 7, - "smj": 7, - "smn": 7, - "sms": 7, - "sn": 3, - "so": 3, - "sq": 3, - "sr": 11, - "ss": 3, - "ssy": 3, - "st": 3, - "sv": 3, - "sw": 3, - "syr": 3, - "ta": 3, - "te": 3, - "teo": 3, - "th": 0, - "ti": 4, - "tig": 3, - "tk": 3, - "tl": 4, - "tn": 3, - "to": 0, - "tr": 0, - "ts": 3, - "tzm": 22, - "uk": 11, - "ur": 3, - "ve": 3, - "vi": 0, - "vun": 3, - "wa": 4, - "wae": 3, - "wo": 0, - "xh": 3, - "xog": 3, - "yo": 0, - "zh": 0, - "zu": 3 -}; - -// Utility functions for plural rules methods -function isIn(n, list) { - return list.indexOf(n) !== -1; -} -function isBetween(n, start, end) { - return start <= n && n <= end; -} - -// List of all plural rules methods, that maps an integer to the plural form name to use -const RULES = { - "0": function (n) { - - return "other" - }, - "1": function (n) { - if ((isBetween((n % 100), 3, 10))) - return "few"; - if (n == 0) - return "zero"; - if ((isBetween((n % 100), 11, 99))) - return "many"; - if (n == 2) - return "two"; - if (n == 1) - return "one"; - return "other" - }, - "2": function (n) { - if (n != 0 && (n % 10) == 0) - return "many"; - if (n == 2) - return "two"; - if (n == 1) - return "one"; - return "other" - }, - "3": function (n) { - if (n == 1) - return "one"; - return "other" - }, - "4": function (n) { - if ((isBetween(n, 0, 1))) - return "one"; - return "other" - }, - "5": function (n) { - if ((isBetween(n, 0, 2)) && n != 2) - return "one"; - return "other" - }, - "6": function (n) { - if (n == 0) - return "zero"; - if ((n % 10) == 1 && (n % 100) != 11) - return "one"; - return "other" - }, - "7": function (n) { - if (n == 2) - return "two"; - if (n == 1) - return "one"; - return "other" - }, - "8": function (n) { - if ((isBetween(n, 3, 6))) - return "few"; - if ((isBetween(n, 7, 10))) - return "many"; - if (n == 2) - return "two"; - if (n == 1) - return "one"; - return "other" - }, - "9": function (n) { - if (n == 0 || n != 1 && (isBetween((n % 100), 1, 19))) - return "few"; - if (n == 1) - return "one"; - return "other" - }, - "10": function (n) { - if ((isBetween((n % 10), 2, 9)) && !(isBetween((n % 100), 11, 19))) - return "few"; - if ((n % 10) == 1 && !(isBetween((n % 100), 11, 19))) - return "one"; - return "other" - }, - "11": function (n) { - if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14))) - return "few"; - if ((n % 10) == 0 || (isBetween((n % 10), 5, 9)) || (isBetween((n % 100), 11, 14))) - return "many"; - if ((n % 10) == 1 && (n % 100) != 11) - return "one"; - return "other" - }, - "12": function (n) { - if ((isBetween(n, 2, 4))) - return "few"; - if (n == 1) - return "one"; - return "other" - }, - "13": function (n) { - if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14))) - return "few"; - if (n != 1 && (isBetween((n % 10), 0, 1)) || (isBetween((n % 10), 5, 9)) || (isBetween((n % 100), 12, 14))) - return "many"; - if (n == 1) - return "one"; - return "other" - }, - "14": function (n) { - if ((isBetween((n % 100), 3, 4))) - return "few"; - if ((n % 100) == 2) - return "two"; - if ((n % 100) == 1) - return "one"; - return "other" - }, - "15": function (n) { - if (n == 0 || (isBetween((n % 100), 2, 10))) - return "few"; - if ((isBetween((n % 100), 11, 19))) - return "many"; - if (n == 1) - return "one"; - return "other" - }, - "16": function (n) { - if ((n % 10) == 1 && n != 11) - return "one"; - return "other" - }, - "17": function (n) { - if (n == 3) - return "few"; - if (n == 0) - return "zero"; - if (n == 6) - return "many"; - if (n == 2) - return "two"; - if (n == 1) - return "one"; - return "other" - }, - "18": function (n) { - if (n == 0) - return "zero"; - if ((isBetween(n, 0, 2)) && n != 0 && n != 2) - return "one"; - return "other" - }, - "19": function (n) { - if ((isBetween(n, 2, 10))) - return "few"; - if ((isBetween(n, 0, 1))) - return "one"; - return "other" - }, - "20": function (n) { - if ((isBetween((n % 10), 3, 4) || ((n % 10) == 9)) && !(isBetween((n % 100), 10, 19) || isBetween((n % 100), 70, 79) || isBetween((n % 100), 90, 99))) - return "few"; - if ((n % 1000000) == 0 && n != 0) - return "many"; - if ((n % 10) == 2 && !isIn((n % 100), [12, 72, 92])) - return "two"; - if ((n % 10) == 1 && !isIn((n % 100), [11, 71, 91])) - return "one"; - return "other" - }, - "21": function (n) { - if (n == 0) - return "zero"; - if (n == 1) - return "one"; - return "other" - }, - "22": function (n) { - if ((isBetween(n, 0, 1)) || (isBetween(n, 11, 99))) - return "one"; - return "other" - }, - "23": function (n) { - if ((isBetween((n % 10), 1, 2)) || (n % 20) == 0) - return "one"; - return "other" - }, - "24": function (n) { - if ((isBetween(n, 3, 10) || isBetween(n, 13, 19))) - return "few"; - if (isIn(n, [2, 12])) - return "two"; - if (isIn(n, [1, 11])) - return "one"; - return "other" - }, -}; - -/** - * Return a function that gives the plural form name for a given integer - * for the specified `locale` - * let fun = getRulesForLocale('en'); - * fun(1) -> 'one' - * fun(0) -> 'other' - * fun(1000) -> 'other' - */ -exports.getRulesForLocale = function getRulesForLocale(locale) { - let index = LOCALES_TO_RULES[locale]; - if (!(index in RULES)) { - console.warn('Plural form unknown for locale "' + locale + '"'); - return function () { return "other"; }; - } - return RULES[index]; -} - diff --git a/addon-sdk/source/lib/sdk/l10n/prefs.js b/addon-sdk/source/lib/sdk/l10n/prefs.js deleted file mode 100644 index 5f5d381722c9..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/prefs.js +++ /dev/null @@ -1,51 +0,0 @@ -/* 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"; - -lazyRequire(this, "../system/events", "on"); -lazyRequireModule(this, "./core", "core"); -const { id: jetpackId } = require('../self'); - -const OPTIONS_DISPLAYED = "addon-options-displayed"; - -function enable() { - on(OPTIONS_DISPLAYED, onOptionsDisplayed); -} -exports.enable = enable; - -function onOptionsDisplayed({ subject: document, data: addonId }) { - if (addonId !== jetpackId) - return; - localizeInlineOptions(document); -} - -function localizeInlineOptions(document) { - let query = 'setting[data-jetpack-id="' + jetpackId + '"][pref-name], ' + - 'button[data-jetpack-id="' + jetpackId + '"][pref-name]'; - let nodes = document.querySelectorAll(query); - for (let node of nodes) { - let name = node.getAttribute("pref-name"); - if (node.tagName == "setting") { - let desc = core.get(name + "_description"); - if (desc) - node.setAttribute("desc", desc); - let title = core.get(name + "_title"); - if (title) - node.setAttribute("title", title); - - for (let item of node.querySelectorAll("menuitem, radio")) { - let key = name + "_options." + item.getAttribute("label"); - let label = core.get(key); - if (label) - item.setAttribute("label", label); - } - } - else if (node.tagName == "button") { - let label = core.get(name + "_label"); - if (label) - node.setAttribute("label", label); - } - } -} -exports.localizeInlineOptions = localizeInlineOptions; diff --git a/addon-sdk/source/lib/sdk/l10n/properties/core.js b/addon-sdk/source/lib/sdk/l10n/properties/core.js deleted file mode 100644 index 920a55570dd7..000000000000 --- a/addon-sdk/source/lib/sdk/l10n/properties/core.js +++ /dev/null @@ -1,89 +0,0 @@ -/* 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"; - -const { Cu } = require("chrome"); -lazyRequire(this, '../../url/utils', 'newURI'); -lazyRequire(this, "../plural-rules", 'getRulesForLocale'); -lazyRequire(this, '../locale', 'getPreferedLocales'); -const { rootURI } = require("@loader/options"); -const { Services } = require("resource://gre/modules/Services.jsm"); -const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); - -const baseURI = rootURI + "locale/"; - -XPCOMUtils.defineLazyGetter(this, "preferedLocales", () => getPreferedLocales(true)); - -// Make sure we don't get stale data after an update -// (See Bug 1300735 for rationale). -Services.strings.flushBundles(); - -function getLocaleURL(locale) { - // if the locale is a valid chrome URI, return it - try { - let uri = newURI(locale); - if (uri.scheme == 'chrome') - return uri.spec; - } - catch(_) {} - // otherwise try to construct the url - return baseURI + locale + ".properties"; -} - -function getKey(locale, key) { - let bundle = Services.strings.createBundle(getLocaleURL(locale)); - try { - return bundle.GetStringFromName(key) + ""; - } - catch (_) {} - return undefined; -} - -function get(key, n, locales) { - // try this locale - let locale = locales.shift(); - let localized; - - if (typeof n == 'number') { - if (n == 0) { - localized = getKey(locale, key + '[zero]'); - } - else if (n == 1) { - localized = getKey(locale, key + '[one]'); - } - else if (n == 2) { - localized = getKey(locale, key + '[two]'); - } - - if (!localized) { - // Retrieve the plural mapping function - let pluralForm = (getRulesForLocale(locale.split("-")[0].toLowerCase()) || - getRulesForLocale("en"))(n); - localized = getKey(locale, key + '[' + pluralForm + ']'); - } - - if (!localized) { - localized = getKey(locale, key + '[other]'); - } - } - - if (!localized) { - localized = getKey(locale, key); - } - - if (!localized) { - localized = getKey(locale, key + '[other]'); - } - - if (localized) { - return localized; - } - - // try next locale - if (locales.length) - return get(key, n, locales); - - return undefined; -} -exports.get = (k, n) => get(k, n, Array.slice(preferedLocales)); diff --git a/addon-sdk/source/lib/sdk/preferences/native-options.js b/addon-sdk/source/lib/sdk/preferences/native-options.js deleted file mode 100644 index eee34cbf3bfc..000000000000 --- a/addon-sdk/source/lib/sdk/preferences/native-options.js +++ /dev/null @@ -1,178 +0,0 @@ -/* 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": "unstable" -}; - -const { Cc, Ci, Cu } = require('chrome'); -lazyRequire(this, '../system/events', "on"); -lazyRequire(this, '../self', "preferencesBranch"); -lazyRequire(this, '../l10n/prefs', "localizeInlineOptions"); - -lazyRequire(this, "resource://gre/modules/Services.jsm", "Services"); -lazyRequire(this, "resource://gre/modules/AddonManager.jsm", "AddonManager"); -lazyRequire(this, "resource://gre/modules/Preferences.jsm", "Preferences"); - -const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";; -const DEFAULT_OPTIONS_URL = 'data:text/xml,'; - -const VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color', - 'file', 'directory', 'control', 'menulist', 'radio']; - -const isFennec = require("sdk/system/xul-app").is("Fennec"); - -function enable({ preferences, id }) { - return new Promise(resolve => { - validate(preferences); - - setDefaults(preferences, preferencesBranch); - - // allow the use of custom options.xul - AddonManager.getAddonByID(id, (addon) => { - on('addon-options-displayed', onAddonOptionsDisplayed, true); - resolve({ id }); - }); - - function onAddonOptionsDisplayed({ subject: doc, data }) { - if (data === id) { - let parent; - - if (isFennec) { - parent = doc.querySelector('.options-box'); - - // NOTE: This disable the CSS rule that makes the options invisible - let item = doc.querySelector('#addons-details .addon-item'); - item.removeAttribute("optionsURL"); - } else { - parent = doc.getElementById('detail-downloads').parentNode; - } - - if (parent) { - injectOptions({ - preferences: preferences, - preferencesBranch: preferencesBranch, - document: doc, - parent: parent, - id: id - }); - localizeInlineOptions(doc); - } else { - throw Error("Preferences parent node not found in Addon Details. The configured custom preferences will not be visible."); - } - } - } - }); -} -exports.enable = enable; - -// centralized sanity checks -function validate(preferences) { - for (let { name, title, type, label, options } of preferences) { - // make sure the title is set and non-empty - if (!title) - throw Error("The '" + name + "' pref requires a title"); - - // make sure that pref type is a valid inline option type - if (!~VALID_PREF_TYPES.indexOf(type)) - throw Error("The '" + name + "' pref must be of valid type"); - - // if it's a control, make sure it has a label - if (type === 'control' && !label) - throw Error("The '" + name + "' control requires a label"); - - // if it's a menulist or radio, make sure it has options - if (type === 'menulist' || type === 'radio') { - if (!options) - throw Error("The '" + name + "' pref requires options"); - - // make sure each option has a value and a label - for (let item of options) { - if (!('value' in item) || !('label' in item)) - throw Error("Each option requires both a value and a label"); - } - } - - // TODO: check that pref type matches default value type - } -} -exports.validate = validate; - -// initializes default preferences, emulates defaults/prefs.js -function setDefaults(preferences, preferencesBranch) { - let prefs = new Preferences({ - branch: `extensions.${preferencesBranch}.`, - defaultBranch: true, - }); - - for (let { name, value } of preferences) - if (value !== undefined) - prefs.set(name, value); -} -exports.setDefaults = setDefaults; - -// dynamically injects inline options into about:addons page at runtime -// NOTE: on Firefox Desktop the about:addons page is a xul page document, -// on Firefox for Android the about:addons page is an xhtml page, to support both -// the XUL xml namespace have to be enforced. -function injectOptions({ preferences, preferencesBranch, document, parent, id }) { - preferences.forEach(({name, type, hidden, title, description, label, options, on, off}) => { - if (hidden) { - return; - } - - let setting = document.createElementNS(XUL_NS, 'setting'); - setting.setAttribute('pref-name', name); - setting.setAttribute('data-jetpack-id', id); - setting.setAttribute('pref', 'extensions.' + preferencesBranch + '.' + name); - setting.setAttribute('type', type); - setting.setAttribute('title', title); - if (description) - setting.setAttribute('desc', description); - - if (type === 'file' || type === 'directory') { - setting.setAttribute('fullpath', 'true'); - } - else if (type === 'control') { - let button = document.createElementNS(XUL_NS, 'button'); - button.setAttribute('pref-name', name); - button.setAttribute('data-jetpack-id', id); - button.setAttribute('label', label); - button.addEventListener('command', function() { - Services.obs.notifyObservers(null, `${id}-cmdPressed`, name); - }, true); - setting.appendChild(button); - } - else if (type === 'boolint') { - setting.setAttribute('on', on); - setting.setAttribute('off', off); - } - else if (type === 'menulist') { - let menulist = document.createElementNS(XUL_NS, 'menulist'); - let menupopup = document.createElementNS(XUL_NS, 'menupopup'); - for (let { value, label } of options) { - let menuitem = document.createElementNS(XUL_NS, 'menuitem'); - menuitem.setAttribute('value', value); - menuitem.setAttribute('label', label); - menupopup.appendChild(menuitem); - } - menulist.appendChild(menupopup); - setting.appendChild(menulist); - } - else if (type === 'radio') { - let radiogroup = document.createElementNS(XUL_NS, 'radiogroup'); - for (let { value, label } of options) { - let radio = document.createElementNS(XUL_NS, 'radio'); - radio.setAttribute('value', value); - radio.setAttribute('label', label); - radiogroup.appendChild(radio); - } - setting.appendChild(radiogroup); - } - - parent.appendChild(setting); - }); -} -exports.injectOptions = injectOptions;