зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1192433: Part 3 - Support localized names and descriptions in WebExtension manifests. r=Mossop
--HG-- extra : commitid : 79RHXd1mZtp extra : rebase_source : 3bbd8ae3184d58ba5d2c1d332e0209fb2d0a19ef
This commit is contained in:
Родитель
e18450690a
Коммит
4a1b170b2c
|
@ -22,6 +22,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ChromeManifestParser",
|
|||
"resource://gre/modules/ChromeManifestParser.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
|
||||
"resource://gre/modules/Locale.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
|
@ -828,15 +830,20 @@ function getRDFProperty(aDs, aResource, aProperty) {
|
|||
/**
|
||||
* Reads an AddonInternal object from a manifest stream.
|
||||
*
|
||||
* @param aStream
|
||||
* An open stream to read the manifest from
|
||||
* @param aUri
|
||||
* A |file:| or |jar:| URL for the manifest
|
||||
* @return an AddonInternal object
|
||||
* @throws if the install manifest in the stream is corrupt or could not
|
||||
* be read
|
||||
*/
|
||||
function loadManifestFromWebManifest(aStream) {
|
||||
let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
let manifest = decoder.decodeFromStream(aStream, aStream.available());
|
||||
var loadManifestFromWebManifest = Task.async(function* loadManifestFromWebManifest(aUri) {
|
||||
// We're passed the URI for the manifest file. Get the URI for its
|
||||
// parent directory.
|
||||
let uri = NetUtil.newURI("./", null, aUri);
|
||||
|
||||
let extension = new ExtensionData(uri);
|
||||
|
||||
let manifest = yield extension.readManifest();
|
||||
|
||||
function findProp(obj, current, properties) {
|
||||
if (properties.length == 0)
|
||||
|
@ -903,30 +910,46 @@ function loadManifestFromWebManifest(aStream) {
|
|||
|
||||
addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
|
||||
|
||||
addon.defaultLocale = {
|
||||
name: getProp("name"),
|
||||
description: getOptionalProp("description"),
|
||||
creator: null,
|
||||
homepageURL: null,
|
||||
function getLocale(aLocale) {
|
||||
let result = {
|
||||
name: extension.localize(getProp("name"), aLocale),
|
||||
description: extension.localize(getOptionalProp("description"), aLocale),
|
||||
creator: null,
|
||||
homepageURL: null,
|
||||
|
||||
developers: null,
|
||||
translators: null,
|
||||
contributors: null,
|
||||
developers: null,
|
||||
translators: null,
|
||||
contributors: null,
|
||||
locales: [aLocale],
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read the list of available locales, and pre-load messages for
|
||||
// all locales.
|
||||
let locales = yield extension.initAllLocales();
|
||||
|
||||
// If there were any errors loading the extension, bail out now.
|
||||
if (extension.errors.length)
|
||||
throw new Error("Extension is invalid");
|
||||
|
||||
addon.defaultLocale = getLocale(extension.defaultLocale);
|
||||
addon.locales = Array.from(locales.keys(), getLocale);
|
||||
|
||||
delete addon.defaultLocale.locales;
|
||||
|
||||
addon.targetApplications = [{
|
||||
id: TOOLKIT_ID,
|
||||
minVersion: AddonManagerPrivate.webExtensionsMinPlatformVersion,
|
||||
maxVersion: "*",
|
||||
}];
|
||||
|
||||
addon.locales = [];
|
||||
addon.targetPlatforms = [];
|
||||
addon.userDisabled = false;
|
||||
addon.softDisabled = addon.blocklistState == Blocklist.STATE_SOFTBLOCKED;
|
||||
|
||||
return addon;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Reads an AddonInternal object from an RDF stream.
|
||||
|
@ -1251,8 +1274,19 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal
|
|||
return size;
|
||||
}
|
||||
|
||||
function loadFromRDF(aFile, aStream) {
|
||||
let addon = loadManifestFromRDF(Services.io.newFileURI(aFile), aStream);
|
||||
function loadFromRDF(aUri) {
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(aUri.file, -1, -1, false);
|
||||
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(fis, 4096);
|
||||
try {
|
||||
var addon = loadManifestFromRDF(aUri, bis);
|
||||
} finally {
|
||||
bis.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
let iconFile = aDir.clone();
|
||||
iconFile.append("icon.png");
|
||||
|
@ -1283,32 +1317,21 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal
|
|||
"install manifest");
|
||||
}
|
||||
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, -1, -1, false);
|
||||
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(fis, 4096);
|
||||
let uri = Services.io.newFileURI(file).QueryInterface(Ci.nsIFileURL);
|
||||
|
||||
try {
|
||||
let addon = file.leafName == FILE_WEB_MANIFEST ?
|
||||
loadManifestFromWebManifest(bis) :
|
||||
loadFromRDF(file, bis);
|
||||
let addon = file.leafName == FILE_WEB_MANIFEST ?
|
||||
yield loadManifestFromWebManifest(uri) :
|
||||
loadFromRDF(uri);
|
||||
|
||||
addon._sourceBundle = aDir.clone();
|
||||
addon._installLocation = aInstallLocation;
|
||||
addon.size = getFileSize(aDir);
|
||||
addon.signedState = yield verifyDirSignedState(aDir, addon);
|
||||
addon.appDisabled = !isUsableAddon(addon);
|
||||
addon._sourceBundle = aDir.clone();
|
||||
addon._installLocation = aInstallLocation;
|
||||
addon.size = getFileSize(aDir);
|
||||
addon.signedState = yield verifyDirSignedState(aDir, addon);
|
||||
addon.appDisabled = !isUsableAddon(addon);
|
||||
|
||||
defineSyncGUID(addon);
|
||||
defineSyncGUID(addon);
|
||||
|
||||
return addon;
|
||||
}
|
||||
finally {
|
||||
bis.close();
|
||||
fis.close();
|
||||
}
|
||||
return addon;
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -1320,9 +1343,17 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal
|
|||
* @throws if the XPI file does not contain a valid install manifest
|
||||
*/
|
||||
var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader, aInstallLocation) {
|
||||
function loadFromRDF(aStream) {
|
||||
let uri = buildJarURI(aZipReader.file, FILE_RDF_MANIFEST);
|
||||
let addon = loadManifestFromRDF(uri, aStream);
|
||||
function loadFromRDF(aUri) {
|
||||
let zis = aZipReader.getInputStream(entry);
|
||||
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(zis, 4096);
|
||||
try {
|
||||
var addon = loadManifestFromRDF(aUri, bis);
|
||||
} finally {
|
||||
bis.close();
|
||||
zis.close();
|
||||
}
|
||||
|
||||
if (aZipReader.hasEntry("icon.png")) {
|
||||
addon.icons[32] = "icon.png";
|
||||
|
@ -1335,7 +1366,7 @@ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
|
|||
|
||||
// Binary components can only be loaded from unpacked addons.
|
||||
if (addon.unpack) {
|
||||
uri = buildJarURI(aZipReader.file, "chrome.manifest");
|
||||
let uri = buildJarURI(aZipReader.file, "chrome.manifest");
|
||||
let chromeManifest = ChromeManifestParser.parseSync(uri);
|
||||
addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
|
||||
"binary-component");
|
||||
|
@ -1352,35 +1383,26 @@ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
|
|||
"install manifest");
|
||||
}
|
||||
|
||||
let zis = aZipReader.getInputStream(entry);
|
||||
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(zis, 4096);
|
||||
let uri = buildJarURI(aZipReader.file, entry);
|
||||
|
||||
try {
|
||||
let addon = entry == FILE_WEB_MANIFEST ?
|
||||
loadManifestFromWebManifest(bis) :
|
||||
loadFromRDF(bis);
|
||||
let addon = entry == FILE_WEB_MANIFEST ?
|
||||
yield loadManifestFromWebManifest(uri) :
|
||||
loadFromRDF(uri);
|
||||
|
||||
addon._sourceBundle = aZipReader.file;
|
||||
addon._installLocation = aInstallLocation;
|
||||
addon._sourceBundle = aZipReader.file;
|
||||
addon._installLocation = aInstallLocation;
|
||||
|
||||
addon.size = 0;
|
||||
let entries = aZipReader.findEntries(null);
|
||||
while (entries.hasMore())
|
||||
addon.size += aZipReader.getEntry(entries.getNext()).realSize;
|
||||
addon.size = 0;
|
||||
let entries = aZipReader.findEntries(null);
|
||||
while (entries.hasMore())
|
||||
addon.size += aZipReader.getEntry(entries.getNext()).realSize;
|
||||
|
||||
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
|
||||
addon.appDisabled = !isUsableAddon(addon);
|
||||
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
|
||||
addon.appDisabled = !isUsableAddon(addon);
|
||||
|
||||
defineSyncGUID(addon);
|
||||
defineSyncGUID(addon);
|
||||
|
||||
return addon;
|
||||
}
|
||||
finally {
|
||||
bis.close();
|
||||
zis.close();
|
||||
}
|
||||
return addon;
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": {
|
||||
"message": "foo",
|
||||
"description": "foo"
|
||||
},
|
||||
"desc": {
|
||||
"message": "bar",
|
||||
"description": "bar"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": {
|
||||
"message": "le foo",
|
||||
"description": "foo"
|
||||
},
|
||||
"desc": {
|
||||
"message": "le bar",
|
||||
"description": "bar"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "Web Extension __MSG_name__",
|
||||
"description": "Descripton __MSG_desc__ of add-on",
|
||||
"version": "1.0",
|
||||
"manifest_version": 2,
|
||||
"default_locale": "en",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "webextension3@tests.mozilla.org"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
const ID = "webextension1@tests.mozilla.org";
|
||||
|
||||
const PREF_SELECTED_LOCALE = "general.useragent.locale";
|
||||
|
||||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
|
@ -142,6 +144,33 @@ add_task(function*() {
|
|||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
add_task(function* test_manifest_localization() {
|
||||
const ID = "webextension3@tests.mozilla.org";
|
||||
|
||||
yield promiseInstallAllFiles([do_get_addon("webextension_3")], true);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
|
||||
equal(addon.name, "Web Extension foo");
|
||||
equal(addon.description, "Descripton bar of add-on");
|
||||
|
||||
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "fr-FR");
|
||||
yield promiseRestartManager();
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
|
||||
equal(addon.name, "Web Extension le foo");
|
||||
equal(addon.description, "Descripton le bar of add-on");
|
||||
|
||||
Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "de");
|
||||
yield promiseRestartManager();
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
|
||||
equal(addon.name, "Web Extension foo");
|
||||
equal(addon.description, "Descripton bar of add-on");
|
||||
});
|
||||
|
||||
// Missing ID should cause a failure
|
||||
add_task(function*() {
|
||||
writeWebManifestForExtension({
|
||||
|
|
Загрузка…
Ссылка в новой задаче