Bug 1246748 - Complete the implementation of chrome.i18n.getUILanguage, r?kmag draft
authorbsilverberg <bsilverberg@mozilla.com>
Wed, 10 Feb 2016 11:41:52 -0500
changeset 330110 3d2899f17d99376324d14e6305b03c524ad7b389
parent 330089 7042e8a19f94d6e075ec149567aea74dfd06c392
child 514099 595a87c76b2abdf5d7d39b7fd0e10557a5e3f233
push id10677
push userbmo:bob.silverberg@gmail.com
push dateWed, 10 Feb 2016 16:43:48 +0000
reviewerskmag
bugs1246748
milestone47.0a1
Bug 1246748 - Complete the implementation of chrome.i18n.getUILanguage, r?kmag Implement chrome.i18n.getUILanguage including tests MozReview-Commit-ID: AYGWaKm7oHB
toolkit/components/extensions/Extension.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
@@ -638,16 +638,20 @@ ExtensionData.prototype = {
   get defaultLocale() {
     if (this.manifest.default_locale != null) {
       return this.normalizeLocaleCode(this.manifest.default_locale);
     }
 
     return null;
   },
 
+  get uiLocale() {
+    return this.localeData.uiLocale;
+  },
+
   // Normalizes a Chrome-compatible locale code to the appropriate
   // Gecko-compatible variant. Currently, this means simply
   // replacing underscores with hyphens.
   normalizeLocaleCode(locale) {
     return String.replace(locale, /_/g, "-");
   },
 
   // Reads the locale file for the given Gecko-compatible locale code, and
@@ -1177,9 +1181,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/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,14 @@
 "use strict";
 
 extensions.registerSchemaAPI("i18n", null, (extension, context) => {
   return {
     i18n: {
       getMessage: function(messageName, substitutions) {
         return extension.localizeMessage(messageName, substitutions);
       },
+      getUILanguage: function() {
+        return extension.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,20 @@
   <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";
 
+const LOCALE = "general.useragent.locale";
+
+SimpleTest.registerCleanupFunction(() => { SpecialPowers.clearUserPref(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 +160,69 @@ 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_default() {
+
+  function backgroundScript() {
+    const expectedLang = "en_US";
+    browser.test.log("running test_get_ui_language_default");
+    browser.test.assertEq(expectedLang,
+                          browser.i18n.getUILanguage(),
+                          "returned language should be the expected default");
+    browser.test.assertEq(browser.i18n.getMessage("@@ui_locale"),
+                          browser.i18n.getUILanguage(),
+                          "returned language should be the expected default");
+    browser.test.notifyPass("test_get_ui_language_default");
+  }
+
+  let extensionData = {
+    background: "(" + backgroundScript + ")()",
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  yield extension.startup();
+  info("extension loaded");
+  yield extension.awaitFinish("test_get_ui_language_default");
+  yield extension.unload();
+  info("extension unloaded");
+});
+
+add_task(function* test_get_ui_language_custom() {
+
+  function backgroundScript() {
+    const LOCALE = "general.useragent.locale";
+    const expectedLang = "he";
+
+    SpecialPowers.setCharPref(LOCALE, "he");
+
+    browser.test.log("running test_get_ui_language_custom");
+    browser.test.assertEq(expectedLang,
+                          browser.i18n.getUILanguage(),
+                          "returned language should be the overriden locale");
+    browser.test.assertEq(browser.i18n.getMessage("@@ui_locale"),
+                          browser.i18n.getUILanguage(),
+                          "returned language should be the  overriden locale");
+    SpecialPowers.clearUserPref(LOCALE);
+    browser.test.notifyPass("test_get_ui_language_custom");
+  }
+
+  let extensionData = {
+    background: "(" + backgroundScript + ")()",
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  yield extension.startup();
+  info("extension loaded");
+  yield extension.awaitFinish("test_get_ui_language_custom");
+  yield extension.unload();
+  info("extension unloaded");
+});
+
 </script>
 
 </body>
 </html>