Bug 1091803 - Correctly treat general.useragent.locale and intl.accept_languages as complex prefs in all cases. r=mfinkle
authorRichard Newman <rnewman@mozilla.com>
Fri, 31 Oct 2014 16:39:47 -0700
changeset 213524 570921b6c56610333d5cdd333994d3e9650706a9
parent 213523 4abc7b1445aabbd9ddc0bbadea49a4e4e3476bd1
child 213525 1f830544ad5eb0a17eb46e6f4b3ed78192f29c3a
push id27754
push userphilringnalda@gmail.com
push dateSun, 02 Nov 2014 16:56:35 +0000
treeherdermozilla-central@6ca3405c22e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs1091803
milestone36.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 1091803 - Correctly treat general.useragent.locale and intl.accept_languages as complex prefs in all cases. r=mfinkle
mobile/android/chrome/content/browser.js
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -469,17 +469,47 @@ var BrowserApp = {
 
     if (!ParentalControls.isAllowed(ParentalControls.INSTALL_EXTENSION)) {
       // Disable extension installs
       Services.prefs.setIntPref("extensions.enabledScopes", 1);
       Services.prefs.setIntPref("extensions.autoDisableScopes", 1);
       Services.prefs.setBoolPref("xpinstall.enabled", false);
     }
 
-    // notify java that gecko has loaded
+    // Fix fallout from Bug 1091803.
+    if (Services.prefs.prefHasUserValue("intl.locale.os")) {
+      try {
+        let currentAcceptLang = Services.prefs.getCharPref("intl.accept_languages");
+
+        // The trailing comma is very important. This means we've set it to a
+        // real char pref, and it's something like "chrome://...,en-US,en".
+        if (currentAcceptLang.startsWith("chrome://global/locale/intl.properties,")) {
+          // If general.useragent.locale was set to a plain string, we ought to fix it, too.
+          try {
+            let currentUALocale = Services.prefs.getCharPref("general.useragent.locale");
+            if (currentUALocale.startsWith("chrome://")) {
+              // We're fine. This is what happens when you read a localized string as a char pref.
+            } else {
+              // Turn it into a localized string.
+              this.setLocalizedPref("general.useragent.locale", currentUALocale);
+            }
+          } catch (ee) {
+          }
+
+          // Now compute and save a valid Accept-Languages header from the clean strings.
+          let osLocale = this.getOSLocalePref();
+          let uaLocale = this.getUALocalePref();
+          this.computeAcceptLanguages(osLocale, uaLocale);
+        }
+      } catch (e) {
+        // Phew.
+      }
+    }
+
+    // Notify Java that Gecko has loaded.
     Messaging.sendRequest({ type: "Gecko:Ready" });
   },
 
   get _startupStatus() {
     delete this._startupStatus;
 
     let savedMilestone = null;
     try {
@@ -1498,16 +1528,43 @@ var BrowserApp = {
       if (formHelperMode == kFormHelperModeDynamic && this.isTablet)
         shouldZoom = false;
       // ZoomHelper.zoomToElement will handle not sending any message if this input is already mostly filling the screen
       ZoomHelper.zoomToElement(focused, -1, false,
           aAllowZoom && shouldZoom && !ViewportHandler.getViewportMetadata(aBrowser.contentWindow).isSpecified);
     }
   },
 
+  getUALocalePref: function () {
+    try {
+      return Services.prefs.getComplexValue("general.useragent.locale", Ci.nsIPrefLocalizedString).data;
+    } catch (e) {
+      try {
+        return Services.prefs.getCharPref("general.useragent.locale");
+      } catch (ee) {
+        return undefined;
+      }
+    }
+  },
+
+  getOSLocalePref: function () {
+    try {
+      return Services.prefs.getCharPref("intl.locale.os");
+    } catch (e) {
+      return undefined;
+    }
+  },
+
+  setLocalizedPref: function (pref, value) {
+    let pls = Cc["@mozilla.org/pref-localizedstring;1"]
+                .createInstance(Ci.nsIPrefLocalizedString);
+    pls.data = value;
+    Services.prefs.setComplexValue(pref, Ci.nsIPrefLocalizedString, pls);
+  },
+
   observe: function(aSubject, aTopic, aData) {
     let browser = this.selectedBrowser;
 
     switch (aTopic) {
 
       case "Session:Back":
         browser.goBack();
         break;
@@ -1739,47 +1796,42 @@ var BrowserApp = {
 
       case "Webapps:AutoUninstall":
         WebappManager.autoUninstall(JSON.parse(aData));
         break;
 
       case "Locale:OS":
         // We know the system locale. We use this for generating Accept-Language headers.
         console.log("Locale:OS: " + aData);
-        let currentOSLocale;
-        try {
-          currentOSLocale = Services.prefs.getCharPref("intl.locale.os");
-        } catch (e) {
-        }
+        let currentOSLocale = this.getOSLocalePref();
         if (currentOSLocale == aData) {
           break;
         }
 
         console.log("New OS locale.");
 
         // Ensure that this choice is immediately persisted, because
         // Gecko won't be told again if it forgets.
         Services.prefs.setCharPref("intl.locale.os", aData);
         Services.prefs.savePrefFile(null);
 
-        let appLocale;
-        try {
-          appLocale = Services.prefs.getCharPref("general.useragent.locale");
-        } catch (e) {
-        }
+        let appLocale = this.getUALocalePref();
 
         this.computeAcceptLanguages(aData, appLocale);
         break;
 
       case "Locale:Changed":
         if (aData) {
           // The value provided to Locale:Changed should be a BCP47 language tag
           // understood by Gecko -- for example, "es-ES" or "de".
           console.log("Locale:Changed: " + aData);
-          Services.prefs.setCharPref("general.useragent.locale", aData);
+
+          // We always write a localized pref, even though sometimes the value is a char pref.
+          // (E.g., on desktop single-locale builds.)
+          this.setLocalizedPref("general.useragent.locale", aData);
         } else {
           // Resetting.
           console.log("Switching to system locale.");
           Services.prefs.clearUserPref("general.useragent.locale");
         }
 
         Services.prefs.setBoolPref("intl.locale.matchOS", !aData);
 
@@ -1858,17 +1910,17 @@ var BrowserApp = {
     }
 
     if (appLocale && appLocale != osLocale) {
       chosen.unshift(appLocale);
     }
 
     let result = chosen.join(",");
     console.log("Setting intl.accept_languages to " + result);
-    Services.prefs.setCharPref("intl.accept_languages", result);
+    this.setLocalizedPref("intl.accept_languages", result);
   },
 
   get defaultBrowserWidth() {
     delete this.defaultBrowserWidth;
     let width = Services.prefs.getIntPref("browser.viewport.desktopWidth");
     return this.defaultBrowserWidth = width;
   },