Bug 1475903 - Add mozIDOMLocalization API. r=mossop
☠☠ backed out by 9440c3b5d589 ☠ ☠
authorZibi Braniecki <zbraniecki@mozilla.com>
Fri, 22 Jun 2018 13:14:23 -0700
changeset 429693 fbbb0327f0f1a70336548ca7655b4f60cf847d9d
parent 429692 d363b70ff752caef217571f42fa71a92ca81a401
child 429694 3317065f14c6837a1560adb69ecb177421c85a7a
push id67222
push userzbraniecki@mozilla.com
push dateThu, 02 Aug 2018 00:14:03 +0000
treeherderautoland@fbbb0327f0f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmossop
bugs1475903
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1475903 - Add mozIDOMLocalization API. r=mossop In order to use DOMLocalization from C++ we need an XPIDL interface. mozIDOMLocalization exposes the class and functionality allowing DocumentL10n to hook into it. MozReview-Commit-ID: GPMhw61LPEg
browser/installer/package-manifest.in
intl/l10n/moz.build
intl/l10n/mozDOMLocalization.js
intl/l10n/mozDOMLocalization.manifest
intl/l10n/mozIDOMLocalization.idl
intl/l10n/test/chrome.ini
intl/l10n/test/dom/test_mozdom_translateElements.html
intl/l10n/test/dom/test_mozdom_translateFragment.html
intl/l10n/test/dom/test_mozdom_translateRoots.html
intl/l10n/test/test_mozdomlocalization.js
intl/l10n/test/xpcshell.ini
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -359,16 +359,19 @@
 @RESPATH@/components/TestInterfaceJSMaplike.js
 #endif
 
 #if defined(MOZ_DEBUG) || defined(MOZ_DEV_EDITION) || defined(NIGHTLY_BUILD)
 @RESPATH@/browser/components/testComponents.manifest
 @RESPATH@/browser/components/startupRecorder.js
 #endif
 
+@RESPATH@/components/mozDOMLocalization.js
+@RESPATH@/components/mozDOMLocalization.manifest
+
 ; [Extensions]
 @RESPATH@/components/extensions-toolkit.manifest
 @RESPATH@/components/extension-process-script.js
 @RESPATH@/browser/components/extensions-browser.manifest
 
 ; Modules
 @RESPATH@/browser/modules/*
 @RESPATH@/modules/*
--- a/intl/l10n/moz.build
+++ b/intl/l10n/moz.build
@@ -6,16 +6,27 @@
 
 EXTRA_JS_MODULES += [
     'DOMLocalization.jsm',
     'L10nRegistry.jsm',
     'Localization.jsm',
     'MessageContext.jsm',
 ]
 
+XPIDL_SOURCES += [
+    'mozIDOMLocalization.idl',
+]
+
+XPIDL_MODULE = 'locale'
+
+EXTRA_COMPONENTS += [
+    'mozDOMLocalization.js',
+    'mozDOMLocalization.manifest',
+]
+
 XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 JAR_MANIFESTS += ['jar.mn']
 
 SPHINX_TREES['l10n'] = 'docs'
 
new file mode 100644
--- /dev/null
+++ b/intl/l10n/mozDOMLocalization.js
@@ -0,0 +1,9 @@
+const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
+const { DOMLocalization } = ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
+
+DOMLocalization.prototype.classID =
+  Components.ID("{29cc3895-8835-4c5b-b53a-0c0d1a458dee}");
+DOMLocalization.prototype.QueryInterface =
+  ChromeUtils.generateQI([Ci.mozIDOMLocalization, Ci.nsISupportsWeakReference]);
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMLocalization]);
new file mode 100644
--- /dev/null
+++ b/intl/l10n/mozDOMLocalization.manifest
@@ -0,0 +1,2 @@
+component {29cc3895-8835-4c5b-b53a-0c0d1a458dee} mozDOMLocalization.js
+contract @mozilla.org/intl/domlocalization;1 {29cc3895-8835-4c5b-b53a-0c0d1a458dee}
new file mode 100644
--- /dev/null
+++ b/intl/l10n/mozIDOMLocalization.idl
@@ -0,0 +1,27 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+webidl Document;
+webidl Element;
+
+[scriptable, uuid(7c468500-541f-4fe0-98c9-92a53b63ec8d)]
+interface mozIDOMLocalization : nsISupports
+{
+  unsigned long addResourceIds(in Array<AString> resourceIds);
+  unsigned long removeResourceIds(in Array<AString> resourceIds);
+
+  Promise formatMessages(in Array<jsval> aKeys);
+  Promise formatValues(in Array<jsval> aKeys);
+  Promise formatValue(in DOMString aId, [optional] in jsval aArgs);
+
+  Promise translateFragment(in Element aElement);
+  Promise translateElements(in Array<Element> aElements);
+
+  void connectRoot(in Element aElement);
+  Promise translateRoots();
+  readonly attribute Promise ready;
+};
--- a/intl/l10n/test/chrome.ini
+++ b/intl/l10n/test/chrome.ini
@@ -9,8 +9,12 @@
 [dom/test_domloc_translateRoots.html]
 [dom/test_domloc_mutations.html]
 [dom/test_domloc_overlay.html]
 [dom/test_domloc_overlay_repeated.html]
 [dom/test_domloc_overlay_missing_all.html]
 [dom/test_domloc_overlay_missing_children.html]
 [dom/test_domloc_overlay_sanitized.html]
 [dom/test_domloc.xul]
+
+[dom/test_mozdom_translateElements.html]
+[dom/test_mozdom_translateFragment.html]
+[dom/test_mozdom_translateRoots.html]
new file mode 100644
--- /dev/null
+++ b/intl/l10n/test/dom/test_mozdom_translateElements.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test mozIDOMLocalization.translateElements</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  <script type="application/javascript">
+  "use strict";
+  const domLocalization =
+    Cc["@mozilla.org/intl/domlocalization;1"].createInstance(
+      Ci.mozIDOMLocalization);
+  const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
+  const { L10nRegistry, FileSource } =
+    ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
+
+  const fs = {
+    "/localization/en-US/browser/menu.ftl": `
+title = Hello World
+link =
+  .title = Click me
+`,
+  };
+  const originalLoad = L10nRegistry.load;
+  const originalRequested = Services.locale.getRequestedLocales();
+
+  L10nRegistry.load = async function(url) {
+    return fs.hasOwnProperty(url) ? fs[url] : false;
+  };
+
+  const source = new FileSource("test", ["en-US"], "/localization/{locale}");
+  L10nRegistry.registerSource(source);
+
+  window.onload = async function() {
+    SimpleTest.waitForExplicitFinish();
+
+    domLocalization.addResourceIds(["/browser/menu.ftl"], 1);
+
+    const p1 = document.querySelectorAll("p")[0];
+    const link1 = document.querySelectorAll("a")[0];
+
+    await domLocalization.translateElements([p1, link1], 2);
+
+    is(p1.textContent, "Hello World");
+    is(link1.getAttribute("title"), "Click me");
+
+    // Cleanup
+    L10nRegistry.removeSource(source.name);
+    L10nRegistry.load = originalLoad;
+    Services.locale.setRequestedLocales(originalRequested);
+
+    SimpleTest.finish();
+  };
+  </script>
+</head>
+<body>
+  <p data-l10n-id="title" />
+  <a data-l10n-id="link" />
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/intl/l10n/test/dom/test_mozdom_translateFragment.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test mozIDOMLocalization.translateFragment</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  <script type="application/javascript">
+  "use strict";
+  const domLocalization =
+    Cc["@mozilla.org/intl/domlocalization;1"].createInstance(
+      Ci.mozIDOMLocalization);
+  const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
+  const { L10nRegistry, FileSource } =
+    ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
+
+  const fs = {
+    "/localization/en-US/browser/menu.ftl": `
+title = Hello World
+subtitle = Welcome to Fluent
+`,
+  };
+  const originalLoad = L10nRegistry.load;
+  const originalRequested = Services.locale.getRequestedLocales();
+
+  L10nRegistry.load = async function(url) {
+    return fs.hasOwnProperty(url) ? fs[url] : false;
+  };
+
+  const source = new FileSource("test", ["en-US"], "/localization/{locale}");
+  L10nRegistry.registerSource(source);
+
+  window.onload = async function() {
+    SimpleTest.waitForExplicitFinish();
+
+    domLocalization.addResourceIds(["/browser/menu.ftl"], 1);
+
+    const frag = document.querySelectorAll("div")[0];
+    const h1 = document.querySelectorAll("h1")[0];
+    const p1 = document.querySelectorAll("p")[0];
+
+    await domLocalization.translateFragment(frag);
+    is(h1.textContent, "Hello World");
+    is(p1.textContent, "Welcome to Fluent");
+
+    // Cleanup
+    L10nRegistry.removeSource(source.name);
+    L10nRegistry.load = originalLoad;
+    Services.locale.setRequestedLocales(originalRequested);
+
+    SimpleTest.finish();
+  };
+  </script>
+</head>
+<body>
+  <div>
+    <h1 data-l10n-id="title" />
+    <p data-l10n-id="subtitle" />
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/intl/l10n/test/dom/test_mozdom_translateRoots.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test mozIDOMLocalization.connectRoot and translateRoots</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  <script type="application/javascript">
+  "use strict";
+  const domLocalization =
+    Cc["@mozilla.org/intl/domlocalization;1"].createInstance(
+      Ci.mozIDOMLocalization);
+  const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
+  const { L10nRegistry, FileSource } =
+    ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
+
+  const fs = {
+    "/localization/en-US/browser/menu.ftl": `
+title = Hello World
+title2 = Hello Another World
+`,
+  };
+  const originalLoad = L10nRegistry.load;
+  const originalRequested = Services.locale.getRequestedLocales();
+
+  L10nRegistry.load = async function(url) {
+    return fs.hasOwnProperty(url) ? fs[url] : false;
+  };
+
+  const source = new FileSource("test", ["en-US"], "/localization/{locale}");
+  L10nRegistry.registerSource(source);
+
+  window.onload = async function() {
+    SimpleTest.waitForExplicitFinish();
+
+    domLocalization.addResourceIds(["/browser/menu.ftl"], 1);
+
+    const frag1 = document.querySelectorAll("div")[0];
+    const frag2 = document.querySelectorAll("div")[1];
+    const h1 = document.querySelectorAll("h1")[0];
+    const h2 = document.querySelectorAll("h2")[0];
+
+    domLocalization.connectRoot(frag1);
+    domLocalization.connectRoot(frag2);
+
+    await domLocalization.translateRoots();
+
+    is(h1.textContent, "Hello World");
+    is(h2.textContent, "Hello Another World");
+
+    // Cleanup
+    L10nRegistry.removeSource(source.name);
+    L10nRegistry.load = originalLoad;
+    Services.locale.setRequestedLocales(originalRequested);
+
+    SimpleTest.finish();
+  };
+  </script>
+</head>
+<body>
+  <div>
+    <h1 data-l10n-id="title"></h1>
+  </div>
+  <div>
+    <h2 data-l10n-id="title2"></h2>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/intl/l10n/test/test_mozdomlocalization.js
@@ -0,0 +1,72 @@
+const domLocalization =
+  Cc["@mozilla.org/intl/domlocalization;1"].createInstance(
+    Ci.mozIDOMLocalization);
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
+const { L10nRegistry, FileSource } =
+  ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
+
+const fs = {
+  "/localization/en-US/browser/menu.ftl": "key = [en] Value",
+};
+const originalLoad = L10nRegistry.load;
+const originalRequested = Services.locale.getRequestedLocales();
+
+L10nRegistry.load = async function(url) {
+  return fs.hasOwnProperty(url) ? fs[url] : false;
+};
+
+const source = new FileSource("test", ["en-US"], "/localization/{locale}");
+L10nRegistry.registerSource(source);
+
+add_task(function test_methods_presence() {
+  equal(typeof domLocalization.addResourceIds, "function");
+  equal(typeof domLocalization.removeResourceIds, "function");
+
+  equal(typeof domLocalization.formatMessages, "function");
+  equal(typeof domLocalization.formatValues, "function");
+  equal(typeof domLocalization.formatValue, "function");
+
+  equal(typeof domLocalization.translateFragment, "function");
+  equal(typeof domLocalization.translateElements, "function");
+
+  equal(typeof domLocalization.connectRoot, "function");
+  equal(typeof domLocalization.translateRoots, "function");
+
+  equal(typeof domLocalization.ready, "object");
+});
+
+add_task(function test_add_remove_resources() {
+  equal(domLocalization.addResourceIds(["./path1.ftl", "./path2.ftl"], 2), 2);
+  equal(domLocalization.removeResourceIds(["./path1.ftl", "./path2.ftl"], 2), 0);
+});
+
+add_task(async function test_format_messages() {
+  domLocalization.addResourceIds(["/browser/menu.ftl"], 1);
+
+  let msgs = await domLocalization.formatMessages([{"id": "key"}], 1);
+  equal(msgs.length, 1);
+  equal(msgs[0].value, "[en] Value");
+});
+
+add_task(async function test_format_values() {
+  let msgs = await domLocalization.formatValues([{"id": "key"}], 1);
+  equal(msgs.length, 1);
+  equal(msgs[0], "[en] Value");
+});
+
+add_task(async function test_format_value() {
+  let msg = await domLocalization.formatValue("key");
+  equal(msg, "[en] Value");
+});
+
+add_task(async function test_ready() {
+  await domLocalization.ready;
+  equal(1, 1);
+});
+
+add_task(function cleanup() {
+  L10nRegistry.sources.clear();
+  L10nRegistry.load = originalLoad;
+  Services.locale.setRequestedLocales(originalRequested);
+});
--- a/intl/l10n/test/xpcshell.ini
+++ b/intl/l10n/test/xpcshell.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 head =
 
 [test_domlocalization.js]
 [test_l10nregistry.js]
 [test_localization.js]
 [test_messagecontext.js]
+[test_mozdomlocalization.js]
 [test_pseudo.js]