mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1118946 - API to provide localized properties r=ferjm,sicking
This commit is contained in:
parent
1640f9ea16
commit
df56e4d957
@ -47,14 +47,17 @@ this.Langpacks = {
|
||||
_data: {},
|
||||
_broadcaster: null,
|
||||
_appIdFromManifestURL: null,
|
||||
_appFromManifestURL: null,
|
||||
|
||||
init: function() {
|
||||
ppmm.addMessageListener("Webapps:GetLocalizationResource", this);
|
||||
ppmm.addMessageListener("Webapps:GetLocalizedValue", this);
|
||||
},
|
||||
|
||||
registerRegistryFunctions: function(aBroadcaster, aIdGetter) {
|
||||
registerRegistryFunctions: function(aBroadcaster, aIdGetter, aAppGetter) {
|
||||
this._broadcaster = aBroadcaster;
|
||||
this._appIdFromManifestURL = aIdGetter;
|
||||
this._appFromManifestURL = aAppGetter;
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
@ -64,6 +67,9 @@ this.Langpacks = {
|
||||
case "Webapps:GetLocalizationResource":
|
||||
this.getLocalizationResource(data, mm);
|
||||
break;
|
||||
case "Webapps:GetLocalizedValue":
|
||||
this.getLocalizedValue(data, mm);
|
||||
break;
|
||||
default:
|
||||
debug("Unexpected message: " + aMessage.name);
|
||||
}
|
||||
@ -108,6 +114,35 @@ this.Langpacks = {
|
||||
this._broadcaster("Webapps:UpdateState", message);
|
||||
},
|
||||
|
||||
_getResource: function(aURL, aResponseType) {
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.mozBackgroundRequest = true;
|
||||
xhr.open("GET", aURL);
|
||||
|
||||
// Default to text response type, but the webidl binding takes care of
|
||||
// validating the dataType value.
|
||||
xhr.responseType = "text";
|
||||
if (aResponseType === "json") {
|
||||
xhr.responseType = "json";
|
||||
} else if (aResponseType === "binary") {
|
||||
xhr.responseType = "blob";
|
||||
}
|
||||
|
||||
return new Promise((aResolve, aReject) => {
|
||||
xhr.addEventListener("load", function() {
|
||||
debug("Success loading " + aURL);
|
||||
if (xhr.status >= 200 && xhr.status < 400) {
|
||||
aResolve(xhr.response);
|
||||
} else {
|
||||
aReject();
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("error", aReject);
|
||||
xhr.send(null);
|
||||
});
|
||||
},
|
||||
|
||||
getLocalizationResource: function(aData, aMm) {
|
||||
debug("getLocalizationResource " + uneval(aData));
|
||||
|
||||
@ -143,33 +178,103 @@ this.Langpacks = {
|
||||
let href = item.url + aData.path;
|
||||
debug("Will load " + href);
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.mozBackgroundRequest = true;
|
||||
xhr.open("GET", href);
|
||||
this._getResource(href, aData.dataType).then(
|
||||
(aResponse) => {
|
||||
aMm.sendAsyncMessage("Webapps:GetLocalizationResource:Return",
|
||||
{ requestID: aData.requestID, oid: aData.oid, data: aResponse });
|
||||
},
|
||||
() => { sendError("Error loading " + href, "UnavailableResource"); }
|
||||
);
|
||||
},
|
||||
|
||||
// Default to text response type, but the webidl binding takes care of
|
||||
// validating the dataType value.
|
||||
xhr.responseType = "text";
|
||||
if (aData.dataType === "json") {
|
||||
xhr.responseType = "json";
|
||||
} else if (aData.dataType === "binary") {
|
||||
xhr.responseType = "blob";
|
||||
getLocalizedValue: function(aData, aMm) {
|
||||
debug("getLocalizedValue " + aData.property);
|
||||
function sendError(aMsg, aCode) {
|
||||
debug(aMsg);
|
||||
aMm.sendAsyncMessage("Webapps:GetLocalizedValue:Return",
|
||||
{ success: false,
|
||||
requestID: aData.requestID,
|
||||
oid: aData.oid,
|
||||
error: aCode });
|
||||
}
|
||||
|
||||
xhr.addEventListener("load", function() {
|
||||
debug("Success loading " + href);
|
||||
if (xhr.status >= 200 && xhr.status < 400) {
|
||||
aMm.sendAsyncMessage("Webapps:GetLocalizationResource:Return",
|
||||
{ requestID: aData.requestID, oid: aData.oid, data: xhr.response });
|
||||
function getValueFromManifest(aManifest) {
|
||||
debug("Getting " + aData.property + " from the manifest.");
|
||||
let value = aManifest._localeProp(aData.property);
|
||||
if (!value) {
|
||||
sendError("No property " + aData.property + " in manifest", "UnknownProperty");
|
||||
} else {
|
||||
sendError("Error loading " + href, "UnavailableResource");
|
||||
aMm.sendAsyncMessage("Webapps:GetLocalizedValue:Return",
|
||||
{ success: true,
|
||||
requestID: aData.requestID,
|
||||
oid: aData.oid,
|
||||
value: value });
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("error", function() {
|
||||
sendError("Error loading " + href, "UnavailableResource");
|
||||
});
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
function getValueFromLangpack(aItem, aManifest) {
|
||||
debug("Getting value from langpack at " + aItem.url + "/manifest.json")
|
||||
let href = aItem.url + "/manifest.json";
|
||||
|
||||
function getProperty(aResponse, aProp) {
|
||||
let root = aData.entryPoint && aResponse.entry_points &&
|
||||
aResponse.entry_points[aData.entryPoint]
|
||||
? aResponse.entry_points[aData.entryPoint]
|
||||
: aResponse;
|
||||
return root[aProp];
|
||||
}
|
||||
|
||||
self._getResource(href, "json").then(
|
||||
(aResponse) => {
|
||||
let propValue = getProperty(aResponse, aData.property);
|
||||
if (propValue) {
|
||||
aMm.sendAsyncMessage("Webapps:GetLocalizedValue:Return",
|
||||
{ success: true,
|
||||
requestID: aData.requestID,
|
||||
oid: aData.oid,
|
||||
value: propValue });
|
||||
} else {
|
||||
getValueFromManifest(aManifest);
|
||||
}
|
||||
},
|
||||
() => { getValueFromManifest(aManifest); }
|
||||
);
|
||||
}
|
||||
|
||||
// We need to get the app with the manifest since the version is only
|
||||
// available in the manifest.
|
||||
this._appFromManifestURL(aData.manifestURL, aData.entryPoint)
|
||||
.then(aApp => {
|
||||
let manifest = aApp.manifest;
|
||||
|
||||
// No langpack for this app or we have langpack(s) for this app, but
|
||||
// not for this language.
|
||||
// Fallback to the manifest values.
|
||||
if (!this._data[aData.manifestURL] ||
|
||||
!this._data[aData.manifestURL].langs[aData.lang]) {
|
||||
getValueFromManifest(manifest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!manifest.version) {
|
||||
getValueFromManifest(manifest);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we have the langpack for the right app version.
|
||||
let item = this._data[aData.manifestURL].langs[aData.lang];
|
||||
// Only keep x.y in the manifest's version in case it's x.y.z
|
||||
let manVersion = manifest.version.split('.').slice(0, 2).join('.');
|
||||
if (item.target == manVersion) {
|
||||
getValueFromLangpack(item, manifest);
|
||||
return;
|
||||
}
|
||||
// Fallback on getting the value from the manifest.
|
||||
getValueFromManifest(manifest);
|
||||
})
|
||||
.catch(aError => { sendError("No app!", "NoSuchApp") });
|
||||
},
|
||||
|
||||
// Validates the langpack part of a manifest.
|
||||
|
@ -699,6 +699,24 @@ WebappsApplication.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
getLocalizedValue: function(aProperty, aLang, aEntryPoint) {
|
||||
this.addMessageListeners(["Webapps:GetLocalizedValue:Return"]);
|
||||
return this.createPromise((aResolve, aReject) => {
|
||||
cpmm.sendAsyncMessage("Webapps:GetLocalizedValue",
|
||||
{ manifestURL: this.manifestURL,
|
||||
oid: this._id,
|
||||
topId: this._topId,
|
||||
property: aProperty,
|
||||
lang: aLang,
|
||||
entryPoint: aEntryPoint,
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_prepareForContent: function() {
|
||||
if (this.__DOM_IMPL__) {
|
||||
return this.__DOM_IMPL__;
|
||||
@ -736,7 +754,8 @@ WebappsApplication.prototype = {
|
||||
if (aMessage.name == "Webapps:Connect:Return:OK" ||
|
||||
aMessage.name == "Webapps:Connect:Return:KO" ||
|
||||
aMessage.name == "Webapps:GetConnections:Return:OK" ||
|
||||
aMessage.name == "Webapps:Export:Return") {
|
||||
aMessage.name == "Webapps:Export:Return" ||
|
||||
aMessage.name == "Webapps:GetLocalizedValue:Return") {
|
||||
req = this.takePromiseResolver(msg.requestID);
|
||||
} else {
|
||||
req = this.takeRequest(msg.requestID);
|
||||
@ -832,6 +851,14 @@ WebappsApplication.prototype = {
|
||||
req.reject(new this._window.DOMError(msg.error || ""));
|
||||
}
|
||||
break;
|
||||
case "Webapps:GetLocalizedValue:Return":
|
||||
this.removeMessageListeners(["Webapps:GetLocalizedValue:Return"]);
|
||||
if (msg.success) {
|
||||
req.resolve(msg.value);
|
||||
} else {
|
||||
req.reject(new this._window.DOMError(msg.error || ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -251,7 +251,8 @@ this.DOMApplicationRegistry = {
|
||||
this.loadAndUpdateApps();
|
||||
|
||||
Langpacks.registerRegistryFunctions(this.broadcastMessage.bind(this),
|
||||
this._appIdForManifestURL.bind(this));
|
||||
this._appIdForManifestURL.bind(this),
|
||||
this.getFullAppByManifestURL.bind(this));
|
||||
},
|
||||
|
||||
// loads the current registry, that could be empty on first run.
|
||||
@ -4669,6 +4670,30 @@ this.DOMApplicationRegistry = {
|
||||
return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
|
||||
},
|
||||
|
||||
// Returns a promise that resolves to the app object with the manifest.
|
||||
getFullAppByManifestURL: function(aManifestURL, aEntryPoint) {
|
||||
let app = this.getAppByManifestURL(aManifestURL);
|
||||
if (!app) {
|
||||
return Promise.reject("NoSuchApp");
|
||||
}
|
||||
|
||||
return this.getManifestFor(aManifestURL).then((aManifest) => {
|
||||
let manifest = aEntryPoint && aManifest.entry_points &&
|
||||
aManifest.entry_points[aEntryPoint]
|
||||
? aManifest.entry_points[aEntryPoint]
|
||||
: aManifest;
|
||||
|
||||
// `version` doesn't change based on entry points, and we need it
|
||||
// to check langpack versions.
|
||||
if (manifest !== aManifest) {
|
||||
manifest.version = aManifest.version;
|
||||
}
|
||||
|
||||
app.manifest = new ManifestHelper(manifest, app.origin, app.manifestURL);
|
||||
return app;
|
||||
});
|
||||
},
|
||||
|
||||
_getAppWithManifest: Task.async(function*(aManifestURL) {
|
||||
let app = this.getAppByManifestURL(aManifestURL);
|
||||
if (!app) {
|
||||
|
8
dom/apps/tests/langpack/fr/manifest.json
Normal file
8
dom/apps/tests/langpack/fr/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name" : "Version française.",
|
||||
"entry_points": {
|
||||
"dialer": {
|
||||
"name": "téléphone"
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,9 @@
|
||||
"revision": 201411051234,
|
||||
"name": "Français",
|
||||
"apps": {
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/fr/"
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/fr/",
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest_no_version.webapp": "tests/dom/apps/tests/langpack/fr/",
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest_version_xyz.webapp": "tests/dom/apps/tests/langpack/fr/"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6,14 +6,18 @@
|
||||
"revision": 201411051234,
|
||||
"name": "Deutsch",
|
||||
"apps": {
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/de/"
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/de/",
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest_no_version.webapp": "tests/dom/apps/tests/langpack/de/",
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest_version_xyz.webapp": "tests/dom/apps/tests/langpack/de/"
|
||||
}
|
||||
},
|
||||
"pl": {
|
||||
"revision": 201411051234,
|
||||
"name": "Polski",
|
||||
"apps": {
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/pl/"
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/pl/",
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest_no_version.webapp": "tests/dom/apps/tests/langpack/pl/",
|
||||
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest_version_xyz.webapp": "tests/dom/apps/tests/langpack/pl/"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
74
dom/apps/tests/langpack/localizedvalues.html
Normal file
74
dom/apps/tests/langpack/localizedvalues.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Langpack Test : localized values</title>
|
||||
<script>
|
||||
function success(data) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
alert(data);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function error(domError) {
|
||||
console.log(domError.name);
|
||||
return new Promise(function(resolve, reject) {
|
||||
alert(domError.name);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
var app;
|
||||
|
||||
function getApp() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var req = navigator.mozApps.getSelf();
|
||||
req.onsuccess = () => { app = req.result; resolve(); }
|
||||
req.onerror = () => { reject(req.error); }
|
||||
});
|
||||
}
|
||||
|
||||
// Success: unknown language, fallback to manifest.
|
||||
function test1() {
|
||||
return app.getLocalizedValue("name", "es")
|
||||
.then(success, error);
|
||||
}
|
||||
|
||||
// Error : unknown property.
|
||||
function test2() {
|
||||
return app.getLocalizedValue("foobar", "fr")
|
||||
.then(success, error);
|
||||
}
|
||||
|
||||
// Success, value from the langpack.
|
||||
function test3() {
|
||||
return app.getLocalizedValue("name", "fr")
|
||||
.then(success, error);
|
||||
}
|
||||
|
||||
// Success, value from the manifest's entry point.
|
||||
function test4() {
|
||||
return app.getLocalizedValue("name", "es", "dialer")
|
||||
.then(success, error);
|
||||
}
|
||||
|
||||
// Success, value from the langpack's entry point.
|
||||
function test5() {
|
||||
return app.getLocalizedValue("name", "fr", "dialer")
|
||||
.then(success, error);
|
||||
}
|
||||
|
||||
function run() {
|
||||
getApp().then(test1)
|
||||
.then(test2)
|
||||
.then(test3)
|
||||
.then(test4)
|
||||
.then(test5)
|
||||
.catch(error);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="run()">
|
||||
<h1>Langpack Test : localized values</h1>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +1,9 @@
|
||||
{
|
||||
"name": "Localization test app"
|
||||
"name": "Localization test app",
|
||||
"version": "2.2",
|
||||
"entry_points": {
|
||||
"dialer": {
|
||||
"name": "dialer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
dom/apps/tests/langpack/manifest_no_version.webapp
Normal file
8
dom/apps/tests/langpack/manifest_no_version.webapp
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Localization test app",
|
||||
"entry_points": {
|
||||
"dialer": {
|
||||
"name": "dialer"
|
||||
}
|
||||
}
|
||||
}
|
9
dom/apps/tests/langpack/manifest_version_xyz.webapp
Normal file
9
dom/apps/tests/langpack/manifest_version_xyz.webapp
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "Localization test app",
|
||||
"version": "2.2.1",
|
||||
"entry_points": {
|
||||
"dialer": {
|
||||
"name": "dialer"
|
||||
}
|
||||
}
|
||||
}
|
@ -206,6 +206,101 @@ function runTest() {
|
||||
req.onerror = mozAppsError;
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
// Test localized values with a x.y manifest version.
|
||||
installApp(appManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Install the fr langpack.
|
||||
installApp(lang1ManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Install the de and pl langpack.
|
||||
installApp(lang2ManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Opens the iframe to the localized values test page.
|
||||
openPage("localizedvalues.html",
|
||||
["Localization test app",
|
||||
"UnknownProperty",
|
||||
"Version française.",
|
||||
"dialer",
|
||||
"téléphone"]);
|
||||
yield undefined;
|
||||
|
||||
// Clean up after ourselves by uninstalling apps.
|
||||
info(apps.length + " applications to uninstall.");
|
||||
while (apps.length) {
|
||||
let app = apps.pop();
|
||||
req = navigator.mozApps.mgmt.uninstall(app);
|
||||
req.onsuccess = continueTest;
|
||||
req.onerror = mozAppsError;
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
// Test localized values with versionless manifest.
|
||||
appManifestURL = uriPrefix + "manifest_no_version.webapp";
|
||||
installApp(appManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Install the fr langpack.
|
||||
installApp(lang1ManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Install the de and pl langpack.
|
||||
installApp(lang2ManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Opens the iframe to the localized values test page.
|
||||
openPage("localizedvalues.html",
|
||||
["Localization test app",
|
||||
"UnknownProperty",
|
||||
"Localization test app",
|
||||
"dialer",
|
||||
"dialer"]);
|
||||
yield undefined;
|
||||
|
||||
// Clean up after ourselves by uninstalling apps.
|
||||
info(apps.length + " applications to uninstall.");
|
||||
while (apps.length) {
|
||||
let app = apps.pop();
|
||||
req = navigator.mozApps.mgmt.uninstall(app);
|
||||
req.onsuccess = continueTest;
|
||||
req.onerror = mozAppsError;
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
// Test localized values with a x.y.z manifest version.
|
||||
appManifestURL = uriPrefix + "manifest_version_xyz.webapp"
|
||||
installApp(appManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Install the fr langpack.
|
||||
installApp(lang1ManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Install the de and pl langpack.
|
||||
installApp(lang2ManifestURL);
|
||||
yield undefined;
|
||||
|
||||
// Opens the iframe to the localized values test page.
|
||||
openPage("localizedvalues.html",
|
||||
["Localization test app",
|
||||
"UnknownProperty",
|
||||
"Version française.",
|
||||
"dialer",
|
||||
"téléphone"]);
|
||||
yield undefined;
|
||||
|
||||
// Clean up after ourselves by uninstalling apps.
|
||||
info(apps.length + " applications to uninstall.");
|
||||
while (apps.length) {
|
||||
let app = apps.pop();
|
||||
req = navigator.mozApps.mgmt.uninstall(app);
|
||||
req.onsuccess = continueTest;
|
||||
req.onerror = mozAppsError;
|
||||
yield undefined;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -106,6 +106,12 @@ interface DOMApplication : EventTarget {
|
||||
|
||||
// Export this app as a shareable Blob.
|
||||
Promise<Blob> export();
|
||||
|
||||
// Returns the localized value of a property, using either the manifest or
|
||||
// a langpack if one is available.
|
||||
Promise<DOMString> getLocalizedValue(DOMString property,
|
||||
DOMString locale,
|
||||
optional DOMString entryPoint);
|
||||
};
|
||||
|
||||
[JSImplementation="@mozilla.org/webapps/manager;1",
|
||||
|
Loading…
Reference in New Issue
Block a user