Move Add-on SDK source to toolkit/jetpack

This commit is contained in:
NTD 2018-02-09 06:46:43 -05:00 committed by Roy Tam
commit 23b67db438
993 changed files with 484 additions and 100663 deletions

View file

@ -0,0 +1,9 @@
/* 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 json = require("./json/core");
const properties = require("./properties/core");
exports.get = json.usingJSON ? json.get : properties.get;

View file

@ -0,0 +1,32 @@
/* 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");
});

View file

@ -0,0 +1,36 @@
/* 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";
}

View file

@ -0,0 +1,70 @@
/* 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");
const { getPreferedLocales, findClosestLocale } = require("./locale");
const { readURI } = require("../net/url");
const { resolve } = require("../core/promise");
function parseJsonURI(uri) {
return readURI(uri).
then(JSON.parse).
then(null, 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
};
});
});
}

View file

@ -0,0 +1,127 @@
/* 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");
/**
* Gets the currently selected locale for display.
* Gets all usable locale that we can use sorted by priority of relevance
* @return Array of locales, begins with highest priority
*/
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const PREF_ACCEPT_LANGUAGES = "intl.accept_languages";
function getPreferedLocales(caseSensitve) {
let locales = [];
function addLocale(locale) {
locale = locale.trim();
if (!caseSensitve)
locale = locale.toLowerCase();
if (locales.indexOf(locale) === -1)
locales.push(locale);
}
// Most important locale is OS one. But we use it, only if
// "intl.locale.matchOS" pref is set to `true`.
// Currently only used for multi-locales mobile builds.
// http://mxr.mozilla.org/mozilla-central/source/mobile/android/installer/Makefile.in#46
if (prefs.get(PREF_MATCH_OS_LOCALE, false)) {
let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].
getService(Ci.nsILocaleService);
let osLocale = localeService.getLocaleComponentForUserAgent();
addLocale(osLocale);
}
// In some cases, mainly on Fennec and on Linux version,
// `general.useragent.locale` is a special 'localized' value, like:
// "chrome://global/locale/intl.properties"
let browserUiLocale = prefs.getLocalized(PREF_SELECTED_LOCALE, "") ||
prefs.get(PREF_SELECTED_LOCALE, "");
if (browserUiLocale)
addLocale(browserUiLocale);
// Third priority is the list of locales used for web content
let contentLocales = prefs.getLocalized(PREF_ACCEPT_LANGUAGES, "") ||
prefs.get(PREF_ACCEPT_LANGUAGES, "");
if (contentLocales) {
// This list is a string of locales seperated by commas.
// There is spaces after commas, so strip each item
for (let locale of contentLocales.split(","))
addLocale(locale.replace(/(^\s+)|(\s+$)/g, ""));
}
// Finally, we ensure that en-US is the final fallback if it wasn't added
addLocale("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;
}

View file

@ -0,0 +1,407 @@
/* 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];
}

View file

@ -0,0 +1,51 @@
/* 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 { on } = require("../system/events");
const core = require("./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;

View file

@ -0,0 +1,87 @@
/* 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");
const { newURI } = require('../../url/utils')
const { getRulesForLocale } = require("../plural-rules");
const { getPreferedLocales } = require('../locale');
const { rootURI } = require("@loader/options");
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
const baseURI = rootURI + "locale/";
const 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));