Bug 1380916 - Introduce OSPreferences::GetRegionalPrefsLocales. r?jfkthame draft
authorZibi Braniecki <zbraniecki@mozilla.com>
Thu, 13 Jul 2017 10:40:40 -0700
changeset 608730 25cbf8c912d00b93d6f77b8c13444e2cc9bf53b5
parent 607669 03bcd6d65af62c5e60a0ab9247ccce43885e707b
child 637407 e89ec03ed3e836a1a53aafc829b365fe7049cdbe
push id68394
push userbmo:gandalf@aviary.pl
push dateFri, 14 Jul 2017 04:08:00 +0000
reviewersjfkthame
bugs1380916
milestone56.0a1
Bug 1380916 - Introduce OSPreferences::GetRegionalPrefsLocales. r?jfkthame Introduce a separate API for retrieving locale set from the host environment used for regional preferences localization. MozReview-Commit-ID: 3597QstZjS3
intl/locale/OSPreferences.cpp
intl/locale/OSPreferences.h
intl/locale/gtk/OSPreferences_gtk.cpp
intl/locale/mac/OSPreferences_mac.cpp
intl/locale/mozIOSPreferences.idl
intl/locale/windows/OSPreferences_win.cpp
--- a/intl/locale/OSPreferences.cpp
+++ b/intl/locale/OSPreferences.cpp
@@ -50,16 +50,32 @@ OSPreferences::GetSystemLocales(nsTArray
 
   // If we failed to get the system locale, we still need
   // to return something because there are tests out there that
   // depend on system locale to be set.
   aRetVal.AppendElement(NS_LITERAL_CSTRING("en-US"));
   return false;
 }
 
+bool
+OSPreferences::GetRegionalPrefsLocales(nsTArray<nsCString>& aRetVal)
+{
+  if (!mRegionalPrefsLocales.IsEmpty()) {
+    aRetVal = mRegionalPrefsLocales;
+    return true;
+  }
+
+  if (ReadRegionalPrefsLocales(aRetVal)) {
+    mRegionalPrefsLocales = aRetVal;
+    return true;
+  }
+
+  return false;
+}
+
 void
 OSPreferences::Refresh()
 {
   nsTArray<nsCString> newLocales;
   ReadSystemLocales(newLocales);
 
   if (mSystemLocales != newLocales) {
     mSystemLocales = Move(newLocales);
@@ -333,16 +349,40 @@ OSPreferences::GetSystemLocale(nsACStrin
     GetSystemLocales(locales);
     if (!locales.IsEmpty()) {
       aRetVal = locales[0];
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+OSPreferences::GetRegionalPrefsLocales(uint32_t* aCount, char*** aOutArray)
+{
+  AutoTArray<nsCString,10> tempLocales;
+  nsTArray<nsCString>* regionalPrefsLocalesPtr;
+
+  if (!mRegionalPrefsLocales.IsEmpty()) {
+    // use cached value
+    regionalPrefsLocalesPtr = &mRegionalPrefsLocales;
+  } else {
+    // get a (perhaps temporary/fallback/hack) value
+    GetRegionalPrefsLocales(tempLocales);
+    regionalPrefsLocalesPtr = &tempLocales;
+  }
+  *aCount = regionalPrefsLocalesPtr->Length();
+  *aOutArray = static_cast<char**>(moz_xmalloc(*aCount * sizeof(char*)));
+
+  for (uint32_t i = 0; i < *aCount; i++) {
+    (*aOutArray)[i] = moz_xstrdup((*regionalPrefsLocalesPtr)[i].get());
+  }
+
+  return NS_OK;
+}
+
 static OSPreferences::DateTimeFormatStyle
 ToDateTimeFormatStyle(int32_t aTimeFormat)
 {
   switch (aTimeFormat) {
     // See mozIOSPreferences.idl for the integer values here.
     case 0:
       return OSPreferences::DateTimeFormatStyle::None;
     case 1:
--- a/intl/locale/OSPreferences.h
+++ b/intl/locale/OSPreferences.h
@@ -73,17 +73,18 @@ public:
    */
   static already_AddRefed<OSPreferences> GetInstanceAddRefed()
   {
     return RefPtr<OSPreferences>(GetInstance()).forget();
   }
 
 
   /**
-   * Returns a list of locales used by the host environment.
+   * Returns a list of locales used by the host environment for UI
+   * localization.
    *
    * The result is a sorted list and we expect that the OS attempts to
    * use the top locale from the list for which it has data.
    *
    * Each element of the list is a valid locale ID that can be passed to ICU
    * and ECMA402 Intl APIs,
    * At the same time each element is a valid BCP47 language tag that can be
    * used for language negotiation.
@@ -96,21 +97,45 @@ public:
    * Usage:
    *   nsTArray<nsCString> systemLocales;
    *   OSPreferences::GetInstance()->GetSystemLocales(systemLocales);
    *
    * (See mozIOSPreferences.idl for a JS-callable version of this.)
    */
   bool GetSystemLocales(nsTArray<nsCString>& aRetVal);
 
+  /**
+   * Returns a list of locales used by host environment for regional
+   * preferences internationalization.
+   *
+   * The result is a sorted list and we expect that the OS attempts to
+   * use the top locale from the list for which it has data.
+   *
+   * Each element of the list is a valid locale ID that can be passed to ICU
+   * and ECMA402 Intl APIs,
+   *
+   * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
+   *
+   * The return bool value indicates whether the function successfully
+   * resolved at least one locale.
+   *
+   * Usage:
+   *   nsTArray<nsCString> systemLocales;
+   *   OSPreferences::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales);
+   *
+   * (See mozIOSPreferences.idl for a JS-callable version of this.)
+   */
+  bool GetRegionalPrefsLocales(nsTArray<nsCString>& aRetVal);
+
   static bool GetDateTimeConnectorPattern(const nsACString& aLocale,
                                           nsAString& aRetVal);
 
 protected:
   nsTArray<nsCString> mSystemLocales;
+  nsTArray<nsCString> mRegionalPrefsLocales;
 
 private:
   virtual ~OSPreferences() {};
 
   static StaticRefPtr<OSPreferences> sInstance;
 
   static bool CanonicalizeLanguageTag(nsCString& aLoc);
 
@@ -138,16 +163,18 @@ private:
    *
    * It is only called when the cache is empty or invalidated.
    *
    * The return value indicates whether the function successfully
    * resolved at least one locale.
    */
   bool ReadSystemLocales(nsTArray<nsCString>& aRetVal);
 
+  bool ReadRegionalPrefsLocales(nsTArray<nsCString>& aRetVal);
+
   /**
    * This is a host environment specific method that will be implemented
    * separately for each platform.
    *
    * It is `best-effort` kind of API that attempts to construct the best
    * possible date/time pattern for the given styles and locales.
    *
    * In case we fail to, or don't know how to retrieve the pattern in a
--- a/intl/locale/gtk/OSPreferences_gtk.cpp
+++ b/intl/locale/gtk/OSPreferences_gtk.cpp
@@ -20,16 +20,24 @@ OSPreferences::ReadSystemLocales(nsTArra
 
   if (CanonicalizeLanguageTag(defaultLang)) {
     aLocaleList.AppendElement(defaultLang);
     return true;
   }
   return false;
 }
 
+bool
+OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList)
+{
+  // For now we're just taking System Locales since we don't know of any better
+  // API for regional prefs.
+  return ReadSystemLocales(aLocaleList);
+}
+
 /*
  * This looks up into gtk settings for hourCycle format.
  *
  * This works for all GUIs that use gtk settings like Gnome, Elementary etc.
  * Ubuntu does not use those settings so we'll want to support them separately.
  *
  * We're taking the current 12/24h settings irrelevant of the locale, because
  * in the UI user selects this setting for all locales.
--- a/intl/locale/mac/OSPreferences_mac.cpp
+++ b/intl/locale/mac/OSPreferences_mac.cpp
@@ -35,16 +35,24 @@ OSPreferences::ReadSystemLocales(nsTArra
   if (CanonicalizeLanguageTag(locale)) {
     aLocaleList.AppendElement(locale);
     return true;
   }
 
   return false;
 }
 
+bool
+OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList)
+{
+  // For now we're just taking System Locales since we don't know of any better
+  // API for regional prefs.
+  return ReadSystemLocales(aLocaleList);
+}
+
 static CFDateFormatterStyle
 ToCFDateFormatterStyle(OSPreferences::DateTimeFormatStyle aFormatStyle)
 {
   switch (aFormatStyle) {
     case OSPreferences::DateTimeFormatStyle::None:
       return kCFDateFormatterNoStyle;
     case OSPreferences::DateTimeFormatStyle::Short:
       return kCFDateFormatterShortStyle;
--- a/intl/locale/mozIOSPreferences.idl
+++ b/intl/locale/mozIOSPreferences.idl
@@ -18,37 +18,52 @@ interface mozIOSPreferences : nsISupport
 {
   const long dateTimeFormatStyleNone     = 0;
   const long dateTimeFormatStyleShort    = 1;
   const long dateTimeFormatStyleMedium   = 2;
   const long dateTimeFormatStyleLong     = 3;
   const long dateTimeFormatStyleFull     = 4;
 
   /**
-   * Returns a list of locales used by the host environment.
+   * Returns a list of locales used by the host environment for UI
+   * localization.
    *
    * The result is a sorted list and we expect that the OS attempts to
    * use the top locale from the list for which it has data.
    *
    * Each element of the list is a valid locale ID that can be passed to ICU
    * and ECMA402 Intl APIs,
    * At the same time each element is a valid BCP47 language tag that can be
    * used for language negotiation.
    *
    * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
    *
-   * The API may return an empty list in case no locale could
-   * be retrieved from the system.
-   *
    * (See OSPreferences.h for a more C++-friendly version of this.)
    */
   void getSystemLocales([optional] out unsigned long aCount,
                         [retval, array, size_is(aCount)] out string aOutArray);
 
   /**
+   * Returns a list of locales used by host environment for regional
+   * preferences internationalization.
+   *
+   * The result is a sorted list and we expect that the OS attempts to
+   * use the top locale from the list for which it has data.
+   *
+   * Each element of the list is a valid locale ID that can be passed to ICU
+   * and ECMA402 Intl APIs,
+   *
+   * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
+   *
+   * (See OSPreferences.h for a more C++-friendly version of this.)
+   */
+  void getRegionalPrefsLocales([optional] out unsigned long aCount,
+                               [retval, array, size_is(aCount)] out string aOutArray);
+
+  /**
    * Returns the best locale that the host environment is localized to.
    *
    * The result is a valid locale ID and it should be
    * used for all APIs that do not handle language negotiation.
    *
    * In any scenario involving language negotiation, GetSystemLocales should
    * be preferred over the single value.
    *
--- a/intl/locale/windows/OSPreferences_win.cpp
+++ b/intl/locale/windows/OSPreferences_win.cpp
@@ -27,16 +27,36 @@ OSPreferences::ReadSystemLocales(nsTArra
 
   if (CanonicalizeLanguageTag(loc)) {
     aLocaleList.AppendElement(loc);
     return true;
   }
   return false;
 }
 
+bool
+OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList)
+{
+  MOZ_ASSERT(aLocaleList.IsEmpty());
+
+  WCHAR locale[LOCALE_NAME_MAX_LENGTH];
+  if (NS_WARN_IF(!LCIDToLocaleName(LOCALE_USER_DEFAULT, locale,
+                                   LOCALE_NAME_MAX_LENGTH, 0))) {
+    return false;
+  }
+
+  NS_LossyConvertUTF16toASCII loc(locale);
+
+  if (CanonicalizeLanguageTag(loc)) {
+    aLocaleList.AppendElement(loc);
+    return true;
+  }
+  return false;
+}
+
 /**
  * Windows distinguishes between System Locale (the locale OS is in), and
  * User Locale (the locale used for regional settings etc.).
  *
  * For DateTimePattern, we want to retrieve the User Locale.
  */
 static void
 ReadUserLocale(nsCString& aRetVal)