Bug 1350646: Part 9 - Remove SDK l10n modules. r=Mossop

MozReview-Commit-ID: 8CZq3jjxnv0

--HG--
extra : source : 5a45d9e25a007c6ab18bd8da4a41f0fe3b9318c0
This commit is contained in:
Kris Maglione 2017-08-05 21:29:31 -07:00
Родитель 3b5d5ab88e
Коммит 8eb28f45a2
12 изменённых файлов: 0 добавлений и 1200 удалений

Просмотреть файл

@ -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',

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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.
});

Просмотреть файл

@ -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");
});

Просмотреть файл

@ -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";
}

Просмотреть файл

@ -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
};
});
});
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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];
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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));

Просмотреть файл

@ -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,<placeholder/>';
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;