Bug 1301655 - pt 0 - Add an optional parameter to nsIChromeRegistry.getSelectedLocale to allow callers to request the locale be returned as a valid BCP47 lang tag. r=gandalf
authorJonathan Kew <jkew@mozilla.com>
Fri, 28 Oct 2016 12:04:06 +0100
changeset 319928 b6ab66ffae99eed12351041efd822efc6ae18858
parent 319927 d523f32cf87f2122fbbca86e0e3d2d0a26942ab6
child 319929 cd3bd7aa413d765587d94db7a6fc8b10c4008af6
push id83271
push userjkew@mozilla.com
push dateFri, 28 Oct 2016 11:07:26 +0000
treeherdermozilla-inbound@686282bd2f19 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgandalf
bugs1301655
milestone52.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 1301655 - pt 0 - Add an optional parameter to nsIChromeRegistry.getSelectedLocale to allow callers to request the locale be returned as a valid BCP47 lang tag. r=gandalf
chrome/nsChromeRegistry.cpp
chrome/nsChromeRegistry.h
chrome/nsChromeRegistryChrome.cpp
chrome/nsChromeRegistryChrome.h
chrome/nsChromeRegistryContent.cpp
chrome/nsChromeRegistryContent.h
chrome/nsIChromeRegistry.idl
dom/encoding/FallbackEncoding.cpp
dom/xul/nsXULPrototypeCache.cpp
editor/composer/nsEditorSpellCheck.cpp
intl/unicharutil/util/ICUUtils.cpp
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -27,16 +27,20 @@
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsIWindowMediator.h"
 #include "nsIPrefService.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 
+#ifdef ENABLE_INTL_API
+#include "unicode/uloc.h"
+#endif
+
 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
 
 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
 // mozilla::TextRange and a TextRange in OSX headers.
 using mozilla::StyleSheet;
 using mozilla::dom::IsChromeURI;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -704,8 +708,37 @@ nsChromeRegistry::GetSingleton()
   else
     cr = new nsChromeRegistryChrome();
 
   if (NS_FAILED(cr->Init()))
     return nullptr;
 
   return cr.forget();
 }
+
+void
+nsChromeRegistry::SanitizeForBCP47(nsACString& aLocale)
+{
+#ifdef ENABLE_INTL_API
+  // 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);
+  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);
+  if (U_SUCCESS(err) && len > 0) {
+    aLocale.Assign(langTag, len);
+  }
+#else
+  // This is only really needed for Intl API purposes, AFAIK,
+  // so probably won't be used in a non-ENABLE_INTL_API build.
+  // But let's fix up the single anomalous code we actually ship,
+  // just in case:
+  if (aLocale.EqualsLiteral("ja-JP-mac")) {
+    aLocale.AssignLiteral("ja-JP");
+  }
+#endif
+}
--- a/chrome/nsChromeRegistry.h
+++ b/chrome/nsChromeRegistry.h
@@ -96,16 +96,18 @@ protected:
   nsresult SelectLocaleFromPref(nsIPrefBranch* prefs);
 
   static nsresult RefreshWindow(nsPIDOMWindowOuter* aWindow);
   static nsresult GetProviderAndPath(nsIURL* aChromeURL,
                                      nsACString& aProvider, nsACString& aPath);
 
   bool GetDirectionForLocale(const nsACString& aLocale);
 
+  void SanitizeForBCP47(nsACString& aLocale);
+
 public:
   static already_AddRefed<nsChromeRegistry> GetSingleton();
 
   struct ManifestProcessingContext
   {
     ManifestProcessingContext(NSLocationType aType, mozilla::FileLocation &aFile)
       : mType(aType)
       , mFile(aFile)
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -219,40 +219,45 @@ getUILangCountry(nsACString& aUILang)
 }
 
 NS_IMETHODIMP
 nsChromeRegistryChrome::IsLocaleRTL(const nsACString& package, bool *aResult)
 {
   *aResult = false;
 
   nsAutoCString locale;
-  GetSelectedLocale(package, locale);
+  GetSelectedLocale(package, false, locale);
   if (locale.Length() < 2)
     return NS_OK;
 
   *aResult = GetDirectionForLocale(locale);
   return NS_OK;
 }
 
 nsresult
 nsChromeRegistryChrome::GetSelectedLocale(const nsACString& aPackage,
+                                          bool aAsBCP47,
                                           nsACString& aLocale)
 {
   nsCString realpackage;
   nsresult rv = OverrideLocalePackage(aPackage, realpackage);
   if (NS_FAILED(rv))
     return rv;
   PackageEntry* entry;
   if (!mPackagesHash.Get(realpackage, &entry))
     return NS_ERROR_FILE_NOT_FOUND;
 
   aLocale = entry->locales.GetSelected(mSelectedLocale, nsProviderArray::LOCALE);
   if (aLocale.IsEmpty())
     return NS_ERROR_FAILURE;
 
+  if (aAsBCP47) {
+    SanitizeForBCP47(aLocale);
+  }
+
   return NS_OK;
 }
 
 nsresult
 nsChromeRegistryChrome::OverrideLocalePackage(const nsACString& aPackage,
                                               nsACString& aOverride)
 {
   const nsACString& pref = NS_LITERAL_CSTRING(PACKAGE_OVERRIDE_BRANCH) + aPackage;
--- a/chrome/nsChromeRegistryChrome.h
+++ b/chrome/nsChromeRegistryChrome.h
@@ -31,16 +31,17 @@ class nsChromeRegistryChrome : public ns
 
   NS_IMETHOD CheckForNewChrome() override;
   NS_IMETHOD CheckForOSAccessibility() override;
   NS_IMETHOD GetLocalesForPackage(const nsACString& aPackage,
                                   nsIUTF8StringEnumerator* *aResult) override;
   NS_IMETHOD IsLocaleRTL(const nsACString& package,
                          bool *aResult) override;
   NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+                               bool aAsBCP47,
                                nsACString& aLocale) override;
   NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
                      const char16_t *someData) override;
 
 #ifdef MOZ_XUL
   NS_IMETHOD GetXULOverlays(nsIURI *aURI,
                             nsISimpleEnumerator **_retval) override;
   NS_IMETHOD GetStyleOverlays(nsIURI *aURI,
--- a/chrome/nsChromeRegistryContent.cpp
+++ b/chrome/nsChromeRegistryContent.cpp
@@ -217,23 +217,27 @@ nsChromeRegistryContent::IsLocaleRTL(con
     return NS_ERROR_NOT_AVAILABLE;
   }
   *aResult = GetDirectionForLocale(mLocale);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeRegistryContent::GetSelectedLocale(const nsACString& aPackage,
+                                           bool aAsBCP47,
                                            nsACString& aLocale)
 {
   if (aPackage != nsDependentCString("global")) {
     NS_ERROR("Uh-oh, caller wanted something other than 'some local'");
     return NS_ERROR_NOT_AVAILABLE;
   }
   aLocale = mLocale;
+  if (aAsBCP47) {
+    SanitizeForBCP47(aLocale);
+  }
   return NS_OK;
 }
   
 NS_IMETHODIMP
 nsChromeRegistryContent::Observe(nsISupports* aSubject, const char* aTopic,
                                  const char16_t* aData)
 {
   CONTENT_NOT_IMPLEMENTED();
--- a/chrome/nsChromeRegistryContent.h
+++ b/chrome/nsChromeRegistryContent.h
@@ -28,16 +28,17 @@ class nsChromeRegistryContent : public n
                                   nsIUTF8StringEnumerator* *aResult) override;
   NS_IMETHOD CheckForNewChrome() override;
   NS_IMETHOD CheckForOSAccessibility() override;
   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
                      const char16_t* aData) override;
   NS_IMETHOD IsLocaleRTL(const nsACString& package,
                          bool *aResult) override;
   NS_IMETHOD GetSelectedLocale(const nsACString& aPackage,
+                               bool aAsBCP47,
                                nsACString& aLocale) override;
   NS_IMETHOD GetStyleOverlays(nsIURI *aChromeURL,
                               nsISimpleEnumerator **aResult) override;
   NS_IMETHOD GetXULOverlays(nsIURI *aChromeURL,
                             nsISimpleEnumerator **aResult) override;
 
   void RegisterPackage(const ChromePackage& aPackage);
   void RegisterOverride(const OverrideMapping& aOverride);
--- a/chrome/nsIChromeRegistry.idl
+++ b/chrome/nsIChromeRegistry.idl
@@ -45,18 +45,23 @@ interface nsIChromeRegistry : nsISupport
   [notxpcom] boolean wrappersEnabled(in nsIURI aURI);
 };
 
 [scriptable, uuid(93251ddf-5e85-4172-ac2a-31780562974f)]
 interface nsIXULChromeRegistry : nsIChromeRegistry
 {
   /* Should be called when locales change to reload all chrome (including XUL). */
   void reloadChrome();
-  
-  ACString getSelectedLocale(in ACString packageName);
+
+  // If the optional asBCP47 parameter is true, the locale code will be
+  // converted to a BCP47 language tag; in particular, this means that
+  // "ja-JP-mac" will be returned as "ja-JP-x-lvariant-mac", which can be
+  // passed to ECMA402 Intl API methods without throwing a RangeError.
+  ACString getSelectedLocale(in ACString packageName,
+                             [optional] in boolean asBCP47);
   
   // Get the direction of the locale via the intl.uidirection.<locale> pref
   boolean isLocaleRTL(in ACString package);
 
   /* Should be called when skins change. Reloads only stylesheets. */
   void refreshSkins();
 
   /**
--- a/dom/encoding/FallbackEncoding.cpp
+++ b/dom/encoding/FallbackEncoding.cpp
@@ -64,17 +64,17 @@ FallbackEncoding::Get(nsACString& aFallb
     aFallback = mFallback;
     return;
   }
 
   nsAutoCString locale;
   nsCOMPtr<nsIXULChromeRegistry> registry =
     mozilla::services::GetXULChromeRegistryService();
   if (registry) {
-    registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), locale);
+    registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), false, locale);
   }
 
   // Let's lower case the string just in case unofficial language packs
   // don't stick to conventions.
   ToLowerCase(locale); // ASCII lowercasing with CString input!
 
   // Special case Traditional Chinese before throwing away stuff after the
   // language itself. Today we only ship zh-TW, but be defensive about
--- a/dom/xul/nsXULPrototypeCache.cpp
+++ b/dom/xul/nsXULPrototypeCache.cpp
@@ -482,17 +482,17 @@ nsXULPrototypeCache::BeginCaching(nsIURI
     // all subsequent packages of cached chrome URIs....
     nsAutoCString package;
     rv = aURI->GetHost(package);
     if (NS_FAILED(rv))
         return rv;
     nsCOMPtr<nsIXULChromeRegistry> chromeReg
         = do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
     nsAutoCString locale;
-    rv = chromeReg->GetSelectedLocale(package, locale);
+    rv = chromeReg->GetSelectedLocale(package, false, locale);
     if (NS_FAILED(rv))
         return rv;
 
     nsAutoCString fileChromePath, fileLocale;
 
     UniquePtr<char[]> buf;
     uint32_t len, amtRead;
     nsCOMPtr<nsIObjectInputStream> objectInput;
--- a/editor/composer/nsEditorSpellCheck.cpp
+++ b/editor/composer/nsEditorSpellCheck.cpp
@@ -917,17 +917,17 @@ nsEditorSpellCheck::DictionaryFetched(Di
   // As next fallback, try the current locale.
   if (NS_FAILED(rv)) {
     nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
       mozilla::services::GetXULChromeRegistryService();
 
     if (packageRegistry) {
       nsAutoCString utf8DictName;
       rv2 = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
-                                               utf8DictName);
+                                               false, utf8DictName);
       dictName.Assign(EmptyString());
       AppendUTF8toUTF16(utf8DictName, dictName);
 #ifdef DEBUG_DICT
       printf("***** Trying locale |%s|\n",
              NS_ConvertUTF16toUTF8(dictName).get());
 #endif
       rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
     }
--- a/intl/unicharutil/util/ICUUtils.cpp
+++ b/intl/unicharutil/util/ICUUtils.cpp
@@ -70,17 +70,17 @@ ICUUtils::LanguageTagIterForContent::Get
 
   if (mCurrentFallbackIndex < 2) {
     mCurrentFallbackIndex = 2;
     // Else try the user-agent's locale:
     nsCOMPtr<nsIToolkitChromeRegistry> cr =
       mozilla::services::GetToolkitChromeRegistryService();
     nsAutoCString uaLangTag;
     if (cr) {
-      cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), uaLangTag);
+      cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), true, uaLangTag);
     }
     if (!uaLangTag.IsEmpty()) {
       aBCP47LangTag = uaLangTag;
       return;
     }
   }
 
   // TODO: Probably not worth it, but maybe have a fourth fallback to using