Bug 1475903 - Add mozIDOMLocalization API. r=mossop
authorZibi Braniecki <zbraniecki@mozilla.com>
Fri, 22 Jun 2018 13:14:23 -0700
changeset 430182 073983e062f70c4bbf25c84a80a9bcd32a9d9128
parent 430181 ebcc9ed3dcd22314863d505149d784aa68268480
child 430192 37b33c4f58b9372ad8d4fa969ad7a86ae305790a
push id67361
push userzbraniecki@mozilla.com
push dateSat, 04 Aug 2018 15:28:43 +0000
treeherderautoland@073983e062f7 [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
mobile/android/installer/package-manifest.in
--- 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
 
 ; [Normandy]
 @RESPATH@/components/shield.manifest
 @RESPATH@/components/shield-content-process.js
--- 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]
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -235,16 +235,19 @@
 @BINPATH@/components/PresentationDataChannelSessionTransport.manifest
 @BINPATH@/components/AndroidCastDeviceProvider.manifest
 @BINPATH@/components/AndroidCastDeviceProvider.js
 #endif
 
 @BINPATH@/components/mozIntl.manifest
 @BINPATH@/components/mozIntl.js
 
+@BINPATH@/components/mozDOMLocalization.js
+@BINPATH@/components/mozDOMLocalization.manifest
+
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsURLClassifier.manifest
 @BINPATH@/components/nsUrlClassifierHashCompleter.js
 @BINPATH@/components/nsUrlClassifierListManager.js
 @BINPATH@/components/nsUrlClassifierLib.js