Bug 1246748 - Complete the implementation of chrome.i18n.getUILanguage, r?kmag draft
authorbsilverberg <bsilverberg@mozilla.com>
Thu, 18 Feb 2016 07:50:17 -0500
changeset 331860 d2fe41b5c3781d6707bfd544f733da5e4e30717f
parent 330089 7042e8a19f94d6e075ec149567aea74dfd06c392
child 514482 6f5988c53f47bf9ee83a3e2767f87086623bb60f
push id11095
push userbmo:bob.silverberg@gmail.com
push dateThu, 18 Feb 2016 12:51:27 +0000
reviewerskmag
bugs1246748
milestone47.0a1
Bug 1246748 - Complete the implementation of chrome.i18n.getUILanguage, r?kmag Implement chrome.i18n.getUILanguage including tests Add API to content scripts MozReview-Commit-ID: IcDlLj8Et73
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionContent.jsm
toolkit/components/extensions/ExtensionUtils.jsm
toolkit/components/extensions/ext-i18n.js
toolkit/components/extensions/schemas/i18n.json
toolkit/components/extensions/test/mochitest/test_ext_i18n.html
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1177,9 +1177,8 @@ Extension.prototype = extend(Object.crea
   hasPermission(perm) {
     return this.permissions.has(perm);
   },
 
   get name() {
     return this.localize(this.manifest.name);
   },
 });
-
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -113,16 +113,20 @@ var api = context => {
 
       inIncognitoContext: PrivateBrowsingUtils.isContentWindowPrivate(context.contentWindow),
     },
 
     i18n: {
       getMessage: function(messageName, substitutions) {
         return context.extension.localizeMessage(messageName, substitutions);
       },
+
+      getUILanguage: function() {
+        return context.extension.localeData.uiLocale;
+      },
     },
   };
 };
 
 // Represents a content script.
 function Script(options, deferred = PromiseUtils.defer()) {
   this.options = options;
   this.run_at = this.options.run_at;
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -328,19 +328,17 @@ LocaleData.prototype = {
           }
         };
         return str.replace(/\$(?:([1-9]\d*)|(\$+))/g, replacer);
       }
     }
 
     // Check for certain pre-defined messages.
     if (message == "@@ui_locale") {
-      // Return the browser locale, but convert it to a Chrome-style
-      // locale code.
-      return Locale.getLocale().replace(/-/g, "_");
+      return this.uiLocale;
     } else if (message.startsWith("@@bidi_")) {
       let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
       let rtl = registry.isLocaleRTL("global");
 
       if (message == "@@bidi_dir") {
         return rtl ? "rtl" : "ltr";
       } else if (message == "@@bidi_reversed_dir") {
         return rtl ? "ltr" : "rtl";
@@ -421,16 +419,23 @@ LocaleData.prototype = {
 
       // Message names are also case-insensitive, so normalize them to lower-case.
       result.set(key.toLowerCase(), value);
     }
 
     this.messages.set(locale, result);
     return result;
   },
+
+  get uiLocale() {
+    // Return the browser locale, but convert it to a Chrome-style
+    // locale code.
+    return Locale.getLocale().replace(/-/g, "_");
+  },
+
 };
 
 // This is a generic class for managing event listeners. Example usage:
 //
 // new EventManager(context, "api.subAPI", fire => {
 //   let listener = (...) => {
 //     // Fire any listeners registered with addListener.
 //     fire(arg1, arg2);
--- a/toolkit/components/extensions/ext-i18n.js
+++ b/toolkit/components/extensions/ext-i18n.js
@@ -1,11 +1,15 @@
 "use strict";
 
 extensions.registerSchemaAPI("i18n", null, (extension, context) => {
   return {
     i18n: {
       getMessage: function(messageName, substitutions) {
         return extension.localizeMessage(messageName, substitutions);
       },
+
+      getUILanguage: function() {
+        return extension.localeData.uiLocale;
+      },
     },
   };
 });
--- a/toolkit/components/extensions/schemas/i18n.json
+++ b/toolkit/components/extensions/schemas/i18n.json
@@ -63,17 +63,16 @@
         ],
         "returns": {
           "type": "string",
           "description": "Message localized for current locale."
         }
       },
       {
         "name": "getUILanguage",
-        "unsupported": true,
         "type": "function",
         "description": "Gets the browser UI language of the browser. This is different from $(ref:i18n.getAcceptLanguages) which returns the preferred user languages.",
         "parameters": [],
         "returns": {
           "type": "string",
           "description": "The browser UI language code such as en-US or fr-FR."
         }
       },
--- a/toolkit/components/extensions/test/mochitest/test_ext_i18n.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_i18n.html
@@ -9,16 +9,18 @@
   <script type="text/javascript" src="head.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 
 <script type="text/javascript">
 "use strict";
 
+SimpleTest.registerCleanupFunction(() => { SpecialPowers.clearUserPref("general.useragent.locale"); });
+
 add_task(function* test_i18n() {
   function runTests(assertEq) {
     let _ = browser.i18n.getMessage.bind(browser.i18n);
 
     let url = browser.runtime.getURL("/");
     assertEq(url, `moz-extension://${_("@@extension_id")}/`, "@@extension_id builtin message");
 
     assertEq("Foo.", _("Foo"), "Simple message in selected locale.");
@@ -156,12 +158,91 @@ add_task(function* test_i18n() {
   let win = window.open("file_sample.html");
   yield extension.awaitMessage("content-script-finished");
   win.close();
 
   yield extension.awaitFinish("l10n");
   yield extension.unload();
 });
 
+add_task(function* test_get_ui_language() {
+  function getResults() {
+    return {
+      getUILanguage: browser.i18n.getUILanguage(),
+      getMessage: browser.i18n.getMessage("@@ui_locale"),
+    };
+  }
+
+  function background(getResults) {
+    function checkResults(source, results, expected) {
+      browser.test.assertEq(
+        expected,
+        results.getUILanguage,
+        `Got expected getUILanguage result in ${source}`
+      );
+      browser.test.assertEq(
+        expected,
+        results.getMessage,
+        `Got expected getMessage result in ${source}`
+      );
+    }
+
+    let tabId;
+
+    browser.test.onMessage.addListener(([msg, expected]) => {
+      browser.tabs.sendMessage(tabId, "get-results", result => {
+        checkResults("contentScript", result, expected);
+        checkResults("background", getResults(), expected);
+
+        browser.test.sendMessage("done");
+      });
+    });
+
+    browser.tabs.query({currentWindow: true, active: true}, tabs => {
+      tabId = tabs[0].id;
+      browser.test.sendMessage("ready");
+    });
+  }
+
+  function content(getResults) {
+    browser.runtime.onMessage.addListener((msg, sender, respond) => {
+      respond(getResults());
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "content_scripts": [{
+        "matches": ["http://mochi.test/*/file_sample.html"],
+        "run_at": "document_start",
+        "js": ["content_script.js"],
+      }],
+    },
+
+    background: `(${background})(${getResults})`,
+
+    files: {
+      "content_script.js": `(${content})(${getResults})`,
+    },
+  });
+
+  let win = window.open("file_sample.html");
+
+  yield extension.startup();
+  yield extension.awaitMessage("ready");
+
+  extension.sendMessage(["expect-results", "en_US"]);
+  yield extension.awaitMessage("done");
+
+  SpecialPowers.setCharPref("general.useragent.locale", "he");
+
+  extension.sendMessage(["expect-results", "he"]);
+  yield extension.awaitMessage("done");
+
+  win.close();
+
+  yield extension.unload();
+});
+
 </script>
 
 </body>
 </html>