Bug 1414390 - Add intl.locale.requested locale list to replace general.useragent.locale. r?jfkthame draft
authorZibi Braniecki <zbraniecki@mozilla.com>
Wed, 01 Nov 2017 20:16:21 -0700
changeset 703952 b334b09e5e7bbdf0ea769766d27a4e394f9313b8
parent 703363 4ce67352b2a9744ac51f0333cea0455e3d59bbf3
child 741937 ce5deb150f9ea29a831d836401cc0a32df659f97
push id91005
push userbmo:gandalf@aviary.pl
push dateMon, 27 Nov 2017 23:31:00 +0000
reviewersjfkthame
bugs1414390
milestone59.0a1
Bug 1414390 - Add intl.locale.requested locale list to replace general.useragent.locale. r?jfkthame This patch moves us from using an old pref `general.useragent.locale`combined with `intl.locale.matchOS` for retrieving user requested locale, to use a new preference `intl.locale.requested` which stores a list of well-formed BCP47 language tags. If set to empty, the OS locales are used. If not set at all, default locale is used. We are also adding a piece of code to migrate from old to new system. MozReview-Commit-ID: 854yQ1kC6Ee
browser/app/profile/firefox.js
browser/components/newtab/tests/browser/browser_packaged_as_locales.js
browser/components/nsBrowserGlue.js
browser/locales/en-US/firefox-l10n.js
intl/locale/LocaleService.cpp
intl/locale/tests/unit/test_localeService.js
mobile/android/installer/mobile-l10n.js
mobile/android/locales/en-US/mobile-l10n.js
modules/libpref/init/all.js
toolkit/locales/en-US/chrome/global/intl.properties
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -219,17 +219,16 @@ pref("browser.uitour.requireSecure", tru
 pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
 pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
 // How long to show a Hearbeat survey (two hours, in seconds)
 pref("browser.uitour.surveyDuration", 7200);
 
 pref("keyword.enabled", true);
 pref("browser.fixup.domainwhitelist.localhost", true);
 
-pref("general.useragent.locale", "@AB_CD@");
 pref("general.skins.selectedSkin", "classic/1.0");
 
 pref("general.smoothScroll", true);
 #ifdef UNIX_BUT_NOT_MAC
 pref("general.autoScroll", false);
 #else
 pref("general.autoScroll", true);
 #endif
@@ -516,16 +515,18 @@ pref("browser.bookmarks.openInTabClosesM
 
 // Scripts & Windows prefs
 pref("dom.disable_open_during_load",              true);
 pref("javascript.options.showInConsole",          true);
 #ifdef DEBUG
 pref("general.warnOnAboutConfig",                 false);
 #endif
 
+pref("intl.locale.requested", "@AB_CD@");
+
 // This is the pref to control the location bar, change this to true to
 // force this - this makes the origin of popup windows more obvious to avoid
 // spoofing. We would rather not do it by default because it affects UE for web
 // applications, but without it there isn't a really good way to prevent chrome
 // spoofing, see bug 337344
 pref("dom.disable_window_open_feature.location",  true);
 // prevent JS from setting status messages
 pref("dom.disable_window_status_change",          true);
--- a/browser/components/newtab/tests/browser/browser_packaged_as_locales.js
+++ b/browser/components/newtab/tests/browser/browser_packaged_as_locales.js
@@ -1,25 +1,24 @@
-const LOCALE_PREF = "general.useragent.locale";
-
+Components.utils.import("resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
 
 const DEFAULT_URL = "resource://activity-stream/prerendered/en-US/activity-stream-prerendered.html";
 async function getUrlForLocale(locale) {
-  await SpecialPowers.pushPrefEnv({set: [[LOCALE_PREF, locale]]});
+  Services.locale.setRequestedLocales([locale]);
   return aboutNewTabService.defaultURL;
 }
 
 /**
  * Test that an unknown locale defaults to en-US
  */
 add_task(async function test_unknown_locale() {
-  const url = await getUrlForLocale("foo-BAR");
+  const url = await getUrlForLocale("und");
   Assert.equal(url, DEFAULT_URL);
 });
 
 /**
  * Test that we at least have en-US
  */
 add_task(async function test_default_locale() {
   const url = await getUrlForLocale("en-US");
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2202,16 +2202,37 @@ BrowserGlue.prototype = {
           // Can't call resetToOriginalDefaultEngine because it doesn't
           // unhide the engine.
           let defaultEngine = Services.search.originalDefaultEngine;
           defaultEngine.hidden = false;
           Services.search.currentEngine = defaultEngine;
           Services.prefs.setCharPref("browser.search.reset.status", "silent");
         }
       });
+
+      // Migrate the old requested locales prefs to use the new model
+      const SELECTED_LOCALE_PREF = "general.useragent.locale";
+      const MATCHOS_LOCALE_PREF = "intl.locale.matchOS";
+
+      if (Services.prefs.prefHasUserValue(MATCHOS_LOCALE_PREF) ||
+          Services.prefs.prefHasUserValue(SELECTED_LOCALE_PREF)) {
+        if (Services.prefs.getBoolPref(MATCHOS_LOCALE_PREF, false)) {
+          Services.locale.setRequestedLocales([]);
+        } else {
+          let locale = Services.prefs.getComplexValue(SELECTED_LOCALE_PREF,
+            Ci.nsIPrefLocalizedString);
+          if (locale) {
+            try {
+              Services.locale.setRequestedLocales([locale.data]);
+            } catch (e) { /* Don't panic if the value is not a valid locale code. */ }
+          }
+        }
+        Services.prefs.clearUserPref(SELECTED_LOCALE_PREF);
+        Services.prefs.clearUserPref(MATCHOS_LOCALE_PREF);
+      }
     }
 
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
   },
 
   _checkForDefaultBrowser() {
     // Perform default browser checking.
--- a/browser/locales/en-US/firefox-l10n.js
+++ b/browser/locales/en-US/firefox-l10n.js
@@ -2,10 +2,8 @@
 # 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/.
 
 #filter substitution
 
 # LOCALIZATION NOTE: this preference is set to true for en-US specifically,
 # locales without this line have the setting set to false by default.
 pref("browser.search.geoSpecificDefaults", true);
-
-pref("general.useragent.locale", "@AB_CD@");
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -16,22 +16,20 @@
 #include "nsStringEnumerator.h"
 #include "nsXULAppAPI.h"
 #include "nsZipArchive.h"
 
 #include "unicode/uloc.h"
 
 #define INTL_SYSTEM_LOCALES_CHANGED "intl:system-locales-changed"
 
-#define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
-#define SELECTED_LOCALE_PREF "general.useragent.locale"
+#define REQUESTED_LOCALES_PREF "intl.locale.requested"
 
 static const char* kObservedPrefs[] = {
-  MATCH_OS_LOCALE_PREF,
-  SELECTED_LOCALE_PREF,
+  REQUESTED_LOCALES_PREF,
   nullptr
 };
 
 using namespace mozilla::intl;
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(LocaleService, mozILocaleService, nsIObserver,
                   nsISupportsWeakReference)
@@ -42,69 +40,84 @@ mozilla::StaticRefPtr<LocaleService> Loc
  * This function transforms a canonical Mozilla Language Tag, into it's
  * BCP47 compilant form.
  *
  * Example: "ja-JP-mac" -> "ja-JP-x-lvariant-mac"
  *
  * The BCP47 form should be used for all calls to ICU/Intl APIs.
  * The canonical form is used for all internal operations.
  */
-static void
-SanitizeForBCP47(nsACString& aLocale)
+static bool
+SanitizeForBCP47(nsACString& aLocale, bool strict)
 {
   // Currently, the only locale code we use that's not BCP47-conformant is
   // "ja-JP-mac" on OS X, but let's try to be more general than just
   // hard-coding that here.
   const int32_t LANG_TAG_CAPACITY = 128;
   char langTag[LANG_TAG_CAPACITY];
   nsAutoCString locale(aLocale);
+  locale.Trim(" ");
   UErrorCode err = U_ZERO_ERROR;
   // This is a fail-safe method that will set langTag to "und" if it cannot
   // match any part of the input locale code.
   int32_t len = uloc_toLanguageTag(locale.get(), langTag, LANG_TAG_CAPACITY,
-                                   false, &err);
+                                   strict, &err);
   if (U_SUCCESS(err) && len > 0) {
     aLocale.Assign(langTag, len);
   }
+  return U_SUCCESS(err);
 }
 
 static bool
 ReadRequestedLocales(nsTArray<nsCString>& aRetVal)
 {
-  nsAutoCString locale;
-
-  // First, we'll try to check if the user has `matchOS` pref selected
-  bool matchOSLocale = Preferences::GetBool(MATCH_OS_LOCALE_PREF);
+  nsAutoCString str;
+  nsresult rv = Preferences::GetCString(REQUESTED_LOCALES_PREF, str);
 
-  if (matchOSLocale) {
-    // If he has, we'll pick the locale from the system
-    if (OSPreferences::GetInstance()->GetSystemLocales(aRetVal)) {
-      // If we succeeded, return.
-      return true;
+  // We handle three scenarios here:
+  //
+  // 1) The pref is not set - use default locale
+  // 2) The pref is set to "" - use OS locales
+  // 3) The pref is set to a value - parse the locale list and use it
+  if (NS_SUCCEEDED(rv)) {
+    if (str.Length() > 0) {
+      for (const nsACString& part : str.Split(',')) {
+        nsAutoCString locale(part);
+        if (SanitizeForBCP47(locale, true)) {
+          // This is a hack required for us to handle the special Mozilla `ja-JP-mac`
+          // locales. We sanitize the input to normalize the case etc. but in result
+          // the `ja-JP-mac` will get turned into a BCP47 tag. Here we're turning it
+          // back into the form expected by Gecko resources.
+          if (locale.EqualsLiteral("ja-JP-x-lvariant-mac")) {
+            locale.Assign("ja-JP-mac");
+          }
+          if (!aRetVal.Contains(locale)) {
+            aRetVal.AppendElement(locale);
+          }
+        }
+      }
+    } else {
+      // If the pref string is empty, we'll take requested locales
+      // from the OS.
+      OSPreferences::GetInstance()->GetSystemLocales(aRetVal);
     }
+  } else {
+    nsAutoCString defaultLocale;
+    LocaleService::GetInstance()->GetDefaultLocale(defaultLocale);
+    aRetVal.AppendElement(defaultLocale);
   }
 
-  // Otherwise, we'll try to get the requested locale from the prefs.
-  if (!NS_SUCCEEDED(Preferences::GetCString(SELECTED_LOCALE_PREF, locale))) {
-    return false;
-  }
-
-  // At the moment we just take a single locale, but in the future
-  // we'll want to allow user to specify a list of requested locales.
-  aRetVal.AppendElement(locale);
-
   // Last fallback locale is a locale for the requested locale chain.
   // In the future we'll want to make the fallback chain differ per-locale.
-  // For now, it'll always fallback on en-US.
   //
   // Notice: This is not the same as DefaultLocale,
   // which follows the default locale the build is in.
-  LocaleService::GetInstance()->GetLastFallbackLocale(locale);
-  if (!aRetVal.Contains(locale)) {
-    aRetVal.AppendElement(locale);
+  LocaleService::GetInstance()->GetLastFallbackLocale(str);
+  if (!aRetVal.Contains(str)) {
+    aRetVal.AppendElement(str);
   }
   return true;
 }
 
 static bool
 ReadAvailableLocales(nsTArray<nsCString>& aRetVal)
 {
   nsCOMPtr<nsIToolkitChromeRegistry> cr =
@@ -218,17 +231,17 @@ LocaleService::GetAppLocalesAsLangTags(n
 void
 LocaleService::GetAppLocalesAsBCP47(nsTArray<nsCString>& aRetVal)
 {
   if (mAppLocales.IsEmpty()) {
     NegotiateAppLocales(mAppLocales);
   }
   for (uint32_t i = 0; i < mAppLocales.Length(); i++) {
     nsAutoCString locale(mAppLocales[i]);
-    SanitizeForBCP47(locale);
+    SanitizeForBCP47(locale, false);
     aRetVal.AppendElement(locale);
   }
 }
 
 void
 LocaleService::GetRegionalPrefsLocales(nsTArray<nsCString>& aRetVal)
 {
   bool useOSLocales = Preferences::GetBool("intl.regional_prefs.use_os_locales", false);
@@ -293,17 +306,16 @@ LocaleService::AssignRequestedLocales(co
   }
 }
 
 bool
 LocaleService::GetRequestedLocales(nsTArray<nsCString>& aRetVal)
 {
   if (mRequestedLocales.IsEmpty()) {
     ReadRequestedLocales(mRequestedLocales);
-
   }
 
   aRetVal = mRequestedLocales;
   return true;
 }
 
 bool
 LocaleService::GetAvailableLocales(nsTArray<nsCString>& aRetVal)
@@ -567,18 +579,17 @@ LocaleService::Observe(nsISupports *aSub
   MOZ_ASSERT(mIsServer, "This should only be called in the server mode.");
 
   if (!strcmp(aTopic, INTL_SYSTEM_LOCALES_CHANGED)) {
     RequestedLocalesChanged();
   } else {
     NS_ConvertUTF16toUTF8 pref(aData);
     // At the moment the only thing we're observing are settings indicating
     // user requested locales.
-    if (pref.EqualsLiteral(MATCH_OS_LOCALE_PREF) ||
-        pref.EqualsLiteral(SELECTED_LOCALE_PREF)) {
+    if (pref.EqualsLiteral(REQUESTED_LOCALES_PREF)) {
       RequestedLocalesChanged();
     }
   }
 
   return NS_OK;
 }
 
 bool
@@ -688,17 +699,17 @@ LocaleService::GetAppLocaleAsLangTag(nsA
 NS_IMETHODIMP
 LocaleService::GetAppLocaleAsBCP47(nsACString& aRetVal)
 {
   if (mAppLocales.IsEmpty()) {
     NegotiateAppLocales(mAppLocales);
   }
   aRetVal = mAppLocales[0];
 
-  SanitizeForBCP47(aRetVal);
+  SanitizeForBCP47(aRetVal, false);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocaleService::GetRegionalPrefsLocales(uint32_t* aCount, char*** aOutArray)
 {
   AutoTArray<nsCString,10> rgLocales;
 
@@ -972,29 +983,36 @@ LocaleService::GetRequestedLocale(nsACSt
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocaleService::SetRequestedLocales(const char** aRequested,
                                    uint32_t aRequestedCount)
 {
-  nsAutoCString lastFallbackLocale;
-  GetLastFallbackLocale(lastFallbackLocale);
-  MOZ_ASSERT(aRequestedCount < 2 ||
-             (aRequestedCount == 2 && lastFallbackLocale.Equals(aRequested[1])),
-      "We can only handle one requested locale (optionally with last fallback)");
+  nsAutoCString str;
 
-  if (aRequestedCount == 0) {
-    Preferences::ClearUser(SELECTED_LOCALE_PREF);
-  } else {
-    Preferences::SetCString(SELECTED_LOCALE_PREF, aRequested[0]);
+  for (uint32_t i = 0; i < aRequestedCount; i++) {
+    nsAutoCString locale(aRequested[i]);
+    if (!SanitizeForBCP47(locale, true)) {
+      NS_ERROR("Invalid language tag provided to SetRequestedLocales!");
+      return NS_ERROR_INVALID_ARG;
+    }
+    if (locale.EqualsLiteral("ja-JP-x-lvariant-mac")) {
+      // This is a hack for our code to handle `ja-JP-mac` special case.
+      locale.Assign("ja-JP-mac");
+    }
+
+    if (i > 0) {
+      str.AppendLiteral(",");
+    }
+    str.Append(locale);
   }
+  Preferences::SetCString(REQUESTED_LOCALES_PREF, str);
 
-  Preferences::SetBool(MATCH_OS_LOCALE_PREF, aRequestedCount == 0);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LocaleService::GetAvailableLocales(uint32_t* aCount, char*** aOutArray)
 {
   AutoTArray<nsCString, 100> availableLocales;
   bool res = GetAvailableLocales(availableLocales);
--- a/intl/locale/tests/unit/test_localeService.js
+++ b/intl/locale/tests/unit/test_localeService.js
@@ -44,19 +44,17 @@ add_test(function test_getAppLocalesAsLa
   do_check_true(appLocale == appLocales[0], "appLocale matches first entry in appLocales");
 
   const enUSLocales = appLocales.filter(loc => loc === "en-US");
   do_check_true(enUSLocales.length == 1, "en-US is present exactly one time");
 
   run_next_test();
 });
 
-const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
-const PREF_SELECTED_LOCALE = "general.useragent.locale";
-const PREF_OS_LOCALE       = "intl.locale.os";
+const PREF_REQUESTED_LOCALES = "intl.locale.requested";
 const REQ_LOC_CHANGE_EVENT = "intl:requested-locales-changed";
 
 add_test(function test_getRequestedLocales() {
   const requestedLocales = localeService.getRequestedLocales();
   do_check_true(Array.isArray(requestedLocales), "requestedLocales returns an array");
 
   run_next_test();
 });
@@ -67,104 +65,108 @@ add_test(function test_getRequestedLocal
  * pref for matchOS is set to true.
  *
  * Then, we test that when the matchOS is set to true, we will retrieve
  * OS locale from getRequestedLocales.
  */
 add_test(function test_getRequestedLocales_matchOS() {
   do_test_pending();
 
-  Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, false);
-  Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "ar-IR");
-  Services.prefs.setCharPref(PREF_OS_LOCALE, "en-US");
+  Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR");
 
   const observer = {
     observe: function (aSubject, aTopic, aData) {
       switch (aTopic) {
         case REQ_LOC_CHANGE_EVENT:
           const reqLocs = localeService.getRequestedLocales();
           do_check_true(reqLocs[0] === osPrefs.systemLocale);
           Services.obs.removeObserver(observer, REQ_LOC_CHANGE_EVENT);
           do_test_finished();
       }
     }
   };
 
   Services.obs.addObserver(observer, REQ_LOC_CHANGE_EVENT);
-  Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, true);
+  Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "");
 
   run_next_test();
 });
 
 /**
  * In this test we verify that after we set an observer on the LocaleService
  * event for requested locales change, it will be fired when the
  * pref for browser UI locale changes.
  */
-add_test(function test_getRequestedLocales_matchOS() {
+add_test(function test_getRequestedLocales_onChange() {
   do_test_pending();
 
-  Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, false);
-  Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "ar-IR");
+  Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR");
 
   const observer = {
     observe: function (aSubject, aTopic, aData) {
       switch (aTopic) {
         case REQ_LOC_CHANGE_EVENT:
           const reqLocs = localeService.getRequestedLocales();
           do_check_true(reqLocs[0] === "sr-RU");
           Services.obs.removeObserver(observer, REQ_LOC_CHANGE_EVENT);
           do_test_finished();
       }
     }
   };
 
   Services.obs.addObserver(observer, REQ_LOC_CHANGE_EVENT);
-  Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "sr-RU");
+  Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "sr-RU");
 
   run_next_test();
 });
 
 add_test(function test_getRequestedLocale() {
-  Services.prefs.setBoolPref(PREF_MATCH_OS_LOCALE, false);
-  Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "tlh");
+  Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "tlh");
 
   let requestedLocale = localeService.getRequestedLocale();
   do_check_true(requestedLocale === "tlh", "requestedLocale returns the right value");
 
-  Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "");
-
-  requestedLocale = localeService.getRequestedLocale();
-  do_check_true(requestedLocale === "", "requestedLocale returns empty value value");
-
-  Services.prefs.clearUserPref(PREF_MATCH_OS_LOCALE);
-  Services.prefs.clearUserPref(PREF_SELECTED_LOCALE);
+  Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES);
 
   run_next_test();
 });
 
 add_test(function test_setRequestedLocales() {
   localeService.setRequestedLocales([]);
 
-  let matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
-  do_check_true(matchOS === true);
+  localeService.setRequestedLocales(['de-AT', 'de-DE', 'de-CH']);
 
-  localeService.setRequestedLocales(['de-AT']);
-
-  matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
-  do_check_true(matchOS === false);
   let locales = localeService.getRequestedLocales();;
   do_check_true(locales[0] === 'de-AT');
+  do_check_true(locales[1] === 'de-DE');
+  do_check_true(locales[2] === 'de-CH');
 
   run_next_test();
 });
 
 add_test(function test_isAppLocaleRTL() {
   do_check_true(typeof localeService.isAppLocaleRTL === 'boolean');
 
   run_next_test();
 });
 
+/**
+ * This test verifies that all values coming from the pref are sanitized.
+ */
+add_test(function test_getRequestedLocales_sanitize() {
+  Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "de,2,#$@#,pl,!a2,DE-at,,;");
+
+  let locales = localeService.getRequestedLocales();
+  do_check_eq(locales[0], "de");
+  do_check_eq(locales[1], "pl");
+  do_check_eq(locales[2], "de-AT");
+  do_check_eq(locales[3], "und");
+  do_check_eq(locales[4], localeService.lastFallbackLocale);
+  do_check_eq(locales.length, 5);
+
+  Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES);
+
+  run_next_test();
+});
+
 do_register_cleanup(() => {
-  Services.prefs.clearUserPref(PREF_SELECTED_LOCALE);
-  Services.prefs.clearUserPref(PREF_MATCH_OS_LOCALE);
-  Services.prefs.clearUserPref(PREF_OS_LOCALE, "en-US");
+  Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES);
 });
--- a/mobile/android/installer/mobile-l10n.js
+++ b/mobile/android/installer/mobile-l10n.js
@@ -1,6 +1,6 @@
 /* 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/. */
 
 // Inherit locale from the OS, used for multi-locale builds
-pref("intl.locale.matchOS", true);
+pref("intl.locale.requested", "");
--- a/mobile/android/locales/en-US/mobile-l10n.js
+++ b/mobile/android/locales/en-US/mobile-l10n.js
@@ -1,7 +1,5 @@
 # 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/.
 
 #filter substitution
-
-pref("general.useragent.locale", "@AB_CD@");
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -17,17 +17,16 @@
  *  - Dashes are delimiters; use underscores instead.
  *  - The first character after a period must be alphabetic.
  *  - Computed values (e.g. 50 * 1024) don't work.
  */
 
 pref("preferences.allow.omt-write", true);
 
 pref("keyword.enabled", false);
-pref("general.useragent.locale", "chrome://global/locale/intl.properties");
 pref("general.useragent.compatMode.firefox", false);
 
 // This pref exists only for testing purposes. In order to disable all
 // overrides by default, don't initialize UserAgentOverrides.jsm.
 pref("general.useragent.site_specific_overrides", true);
 
 pref("general.config.obscure_value", 13); // for MCD .cfg files
 
@@ -2270,17 +2269,16 @@ pref("converter.html2txt.always_include_
 
 pref("intl.accept_languages",               "chrome://global/locale/intl.properties");
 pref("intl.menuitems.alwaysappendaccesskeys","chrome://global/locale/intl.properties");
 pref("intl.menuitems.insertseparatorbeforeaccesskeys","chrome://global/locale/intl.properties");
 pref("intl.charset.detector",               "chrome://global/locale/intl.properties");
 pref("intl.charset.fallback.override",      "");
 pref("intl.charset.fallback.tld",           true);
 pref("intl.ellipsis",                       "chrome://global-platform/locale/intl.properties");
-pref("intl.locale.matchOS",                 false);
 // this pref allows user to request that all internationalization formatters
 // like date/time formatting, unit formatting, calendars etc. should use
 // OS locale set instead of the app locale set.
 pref("intl.regional_prefs.use_os_locales",  false);
 // fallback charset list for Unicode conversion (converting from Unicode)
 // currently used for mail send only to handle symbol characters (e.g Euro, trademark, smartquotes)
 // for ISO-8859-1
 pref("intl.fallbackCharsetList.ISO-8859-1", "windows-1252");
--- a/toolkit/locales/en-US/chrome/global/intl.properties
+++ b/toolkit/locales/en-US/chrome/global/intl.properties
@@ -1,26 +1,16 @@
 # 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/.
 
-# LOCALIZATION NOTE (general.useragent.locale):
-# This is the valid BCP 47 language tag representing your locale.
-#
-# In most cases, this will simply be your locale code. However, in rare cases
-# (such as 'jp-JP-mac'), you may need to modify your locale code in order to
-# make it a valid BCP 47 language tag. (If your locale code does not include a
-# region subtag, do not include one in the language tag representing your
-# locale.)
-general.useragent.locale=en-US
-
 # LOCALIZATION NOTE (intl.accept_languages):
 # This is a comma-separated list of valid BCP 47 language tags.
 #
-# Begin with the value of 'general.useragent.locale'. Next, include language
+# Begin with the language tag of your locale. Next, include language
 # tags for other languages that you expect most users of your locale to be
 # able to speak, so that their browsing experience degrades gracefully if
 # content is not available in their primary language.
 #
 # It is recommended that you include "en-US, en" at the end of the list as a
 # last resort. However, if you know that users of your locale would prefer a
 # different variety of English, or if they are not likely to understand
 # English at all, you may opt to include a different English language tag, or