diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp index 8ec8f8a8c497..dae1a85aaa90 100644 --- a/intl/locale/LocaleService.cpp +++ b/intl/locale/LocaleService.cpp @@ -97,7 +97,7 @@ SplitLocaleListStringIntoArray(nsACString& str, nsTArray& aRetVal) } } -static bool +static void ReadRequestedLocales(nsTArray& aRetVal) { nsAutoCString str; @@ -116,13 +116,16 @@ ReadRequestedLocales(nsTArray& aRetVal) } else { SplitLocaleListStringIntoArray(str, aRetVal); } - } else { + } + + // This will happen when either the pref is not set, + // or parsing of the pref didn't produce any usable + // result. + if (aRetVal.IsEmpty()) { nsAutoCString defaultLocale; LocaleService::GetInstance()->GetDefaultLocale(defaultLocale); aRetVal.AppendElement(defaultLocale); } - - return true; } LocaleService::LocaleService(bool aIsServer) @@ -148,7 +151,7 @@ LocaleService::NegotiateAppLocales(nsTArray& aRetVal) GetRequestedLocales(requestedLocales); NegotiateLanguages(requestedLocales, availableLocales, defaultLocale, - LangNegStrategy::Filtering, aRetVal); + kLangNegStrategyFiltering, aRetVal); } nsAutoCString lastFallbackLocale; @@ -202,72 +205,6 @@ LocaleService::~LocaleService() } } -void -LocaleService::GetAppLocalesAsLangTags(nsTArray& aRetVal) -{ - if (mAppLocales.IsEmpty()) { - NegotiateAppLocales(mAppLocales); - } - for (uint32_t i = 0; i < mAppLocales.Length(); i++) { - nsAutoCString locale(mAppLocales[i]); - if (locale.LowerCaseEqualsASCII("ja-jp-macos")) { - aRetVal.AppendElement("ja-JP-mac"); - } else { - aRetVal.AppendElement(locale); - } - } -} - -void -LocaleService::GetAppLocalesAsBCP47(nsTArray& aRetVal) -{ - if (mAppLocales.IsEmpty()) { - NegotiateAppLocales(mAppLocales); - } - aRetVal = mAppLocales; -} - -void -LocaleService::GetRegionalPrefsLocales(nsTArray& aRetVal) -{ - bool useOSLocales = Preferences::GetBool("intl.regional_prefs.use_os_locales", false); - - // If the user specified that they want to use OS Regional Preferences locales, - // try to retrieve them and use. - if (useOSLocales) { - if (OSPreferences::GetInstance()->GetRegionalPrefsLocales(aRetVal)) { - return; - } - - // If we fail to retrieve them, return the app locales. - GetAppLocalesAsBCP47(aRetVal); - return; - } - - // Otherwise, fetch OS Regional Preferences locales and compare the first one - // to the app locale. If the language subtag matches, we can safely use - // the OS Regional Preferences locale. - // - // This facilitates scenarios such as Firefox in "en-US" and User sets - // regional prefs to "en-GB". - nsAutoCString appLocale; - AutoTArray regionalPrefsLocales; - LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale); - - if (!OSPreferences::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales)) { - GetAppLocalesAsBCP47(aRetVal); - return; - } - - if (LocaleService::LanguagesMatch(appLocale, regionalPrefsLocales[0])) { - aRetVal = regionalPrefsLocales; - return; - } - - // Otherwise use the app locales. - GetAppLocalesAsBCP47(aRetVal); -} - void LocaleService::AssignAppLocales(const nsTArray& aAppLocales) { @@ -292,36 +229,6 @@ LocaleService::AssignRequestedLocales(const nsTArray& aRequestedLocal } } -bool -LocaleService::GetRequestedLocales(nsTArray& aRetVal) -{ - if (mRequestedLocales.IsEmpty()) { - ReadRequestedLocales(mRequestedLocales); - } - - aRetVal = mRequestedLocales; - return true; -} - -bool -LocaleService::GetAvailableLocales(nsTArray& aRetVal) -{ - MOZ_ASSERT(mIsServer, "This should only be called in the server mode."); - if (!mIsServer) { - return false; - } - - if (mAvailableLocales.IsEmpty()) { - // If there are no available locales set, it means that L10nRegistry - // did not register its locale pool yet. The best course of action - // is to use packaged locales until that happens. - GetPackagedLocales(mAvailableLocales); - } - - aRetVal = mAvailableLocales; - return true; -} - void LocaleService::RequestedLocalesChanged() { @@ -368,11 +275,11 @@ LocaleService::LocalesChanged() // according to the desired negotiation strategy. #define HANDLE_STRATEGY \ switch (aStrategy) { \ - case LangNegStrategy::Lookup: \ + case kLangNegStrategyLookup: \ return; \ - case LangNegStrategy::Matching: \ + case kLangNegStrategyMatching: \ continue; \ - case LangNegStrategy::Filtering: \ + case kLangNegStrategyFiltering: \ break; \ } @@ -420,7 +327,7 @@ LocaleService::LocalesChanged() void LocaleService::FilterMatches(const nsTArray& aRequested, const nsTArray& aAvailable, - LangNegStrategy aStrategy, + int32_t aStrategy, nsTArray& aRetVal) { // Local copy of the list of available locales, in Locale form for flexible @@ -434,7 +341,6 @@ LocaleService::FilterMatches(const nsTArray& aRequested, for (auto& requested : aRequested) { if (requested.IsEmpty()) { - MOZ_ASSERT(!requested.IsEmpty(), "Locale string cannot be empty."); continue; } @@ -466,7 +372,7 @@ LocaleService::FilterMatches(const nsTArray& aRequested, aRetVal.AppendElement(aAvailable[match - availLocales.begin()]); match->Invalidate(); foundMatch = true; - if (aStrategy != LangNegStrategy::Filtering) { + if (aStrategy != kLangNegStrategyFiltering) { return true; // we only want the first match } } @@ -507,43 +413,6 @@ LocaleService::FilterMatches(const nsTArray& aRequested, } } -void -LocaleService::NegotiateLanguages(const nsTArray& aRequested, - const nsTArray& aAvailable, - const nsACString& aDefaultLocale, - LangNegStrategy aStrategy, - nsTArray& aRetVal) -{ - MOZ_ASSERT(aDefaultLocale.IsEmpty() || Locale(aDefaultLocale).IsWellFormed(), - "If specified, default locale must be a well-formed BCP47 language tag."); - - if (aStrategy == LangNegStrategy::Lookup && aDefaultLocale.IsEmpty()) { - NS_WARNING("Default locale should be specified when using lookup strategy."); - } - - FilterMatches(aRequested, aAvailable, aStrategy, aRetVal); - - if (aStrategy == LangNegStrategy::Lookup) { - // If the strategy is Lookup and Filtering returned no matches, use - // the default locale. - if (aRetVal.Length() == 0) { - // If the default locale is empty, we already issued a warning, so - // now we will just pick up the LocaleService's defaultLocale. - if (aDefaultLocale.IsEmpty()) { - nsAutoCString defaultLocale; - GetDefaultLocale(defaultLocale); - aRetVal.AppendElement(defaultLocale); - } else { - aRetVal.AppendElement(aDefaultLocale); - } - } - } else if (!aDefaultLocale.IsEmpty() && !aRetVal.Contains(aDefaultLocale)) { - // If it's not a Lookup strategy, add the default locale only if it's - // set and it's not in the results already. - aRetVal.AppendElement(aDefaultLocale); - } -} - bool LocaleService::IsAppLocaleRTL() { @@ -593,17 +462,6 @@ LocaleService::IsServer() return mIsServer; } -static char** -CreateOutArray(const nsTArray& aArray) -{ - uint32_t n = aArray.Length(); - char** result = static_cast(moz_xmalloc(n * sizeof(char*))); - for (uint32_t i = 0; i < n; i++) { - result[i] = moz_xstrdup(aArray[i].get()); - } - return result; -} - static bool GetGREFileContents(const char* aFilePath, nsCString* aOutString) { @@ -673,15 +531,6 @@ LocaleService::InitPackagedLocales() } } -void -LocaleService::GetPackagedLocales(nsTArray& aRetVal) -{ - if (mPackagedLocales.IsEmpty()) { - InitPackagedLocales(); - } - aRetVal = mPackagedLocales; -} - /** * mozILocaleService methods */ @@ -723,25 +572,30 @@ LocaleService::GetLastFallbackLocale(nsACString& aRetVal) } NS_IMETHODIMP -LocaleService::GetAppLocalesAsLangTags(uint32_t* aCount, char*** aOutArray) -{ - AutoTArray locales; - GetAppLocalesAsLangTags(locales); - - *aCount = locales.Length(); - *aOutArray = CreateOutArray(locales); - - return NS_OK; -} - -NS_IMETHODIMP -LocaleService::GetAppLocalesAsBCP47(uint32_t* aCount, char*** aOutArray) +LocaleService::GetAppLocalesAsLangTags(nsTArray& aRetVal) { if (mAppLocales.IsEmpty()) { NegotiateAppLocales(mAppLocales); } - *aCount = mAppLocales.Length(); - *aOutArray = CreateOutArray(mAppLocales); + for (uint32_t i = 0; i < mAppLocales.Length(); i++) { + nsAutoCString locale(mAppLocales[i]); + if (locale.LowerCaseEqualsASCII("ja-jp-macos")) { + aRetVal.AppendElement("ja-JP-mac"); + } else { + aRetVal.AppendElement(locale); + } + } + return NS_OK; +} + + +NS_IMETHODIMP +LocaleService::GetAppLocalesAsBCP47(nsTArray& aRetVal) +{ + if (mAppLocales.IsEmpty()) { + NegotiateAppLocales(mAppLocales); + } + aRetVal = mAppLocales; return NS_OK; } @@ -767,137 +621,116 @@ LocaleService::GetAppLocaleAsBCP47(nsACString& aRetVal) } NS_IMETHODIMP -LocaleService::GetRegionalPrefsLocales(uint32_t* aCount, char*** aOutArray) +LocaleService::GetRegionalPrefsLocales(nsTArray& aRetVal) { - AutoTArray rgLocales; + bool useOSLocales = Preferences::GetBool("intl.regional_prefs.use_os_locales", false); - GetRegionalPrefsLocales(rgLocales); + // If the user specified that they want to use OS Regional Preferences locales, + // try to retrieve them and use. + if (useOSLocales) { + if (OSPreferences::GetInstance()->GetRegionalPrefsLocales(aRetVal)) { + return NS_OK; + } - *aCount = rgLocales.Length(); - *aOutArray = static_cast(moz_xmalloc(*aCount * sizeof(char*))); - - for (uint32_t i = 0; i < *aCount; i++) { - (*aOutArray)[i] = moz_xstrdup(rgLocales[i].get()); + // If we fail to retrieve them, return the app locales. + GetAppLocalesAsBCP47(aRetVal); + return NS_OK; } + // Otherwise, fetch OS Regional Preferences locales and compare the first one + // to the app locale. If the language subtag matches, we can safely use + // the OS Regional Preferences locale. + // + // This facilitates scenarios such as Firefox in "en-US" and User sets + // regional prefs to "en-GB". + nsAutoCString appLocale; + AutoTArray regionalPrefsLocales; + LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale); + + if (!OSPreferences::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales)) { + GetAppLocalesAsBCP47(aRetVal); + return NS_OK; + } + + if (LocaleService::LanguagesMatch(appLocale, regionalPrefsLocales[0])) { + aRetVal = regionalPrefsLocales; + return NS_OK; + } + + // Otherwise use the app locales. + GetAppLocalesAsBCP47(aRetVal); return NS_OK; } -static LocaleService::LangNegStrategy -ToLangNegStrategy(int32_t aStrategy) -{ - switch (aStrategy) { - case 1: - return LocaleService::LangNegStrategy::Matching; - case 2: - return LocaleService::LangNegStrategy::Lookup; - default: - return LocaleService::LangNegStrategy::Filtering; - } -} - NS_IMETHODIMP -LocaleService::NegotiateLanguages(const char** aRequested, - const char** aAvailable, - const char* aDefaultLocale, +LocaleService::NegotiateLanguages(const nsTArray& aRequested, + const nsTArray& aAvailable, + const nsACString& aDefaultLocale, int32_t aStrategy, - uint32_t aRequestedCount, - uint32_t aAvailableCount, - uint32_t* aCount, char*** aRetVal) + nsTArray& aRetVal) { if (aStrategy < 0 || aStrategy > 2) { return NS_ERROR_INVALID_ARG; } - // Check that the given string contains only ASCII characters valid in tags - // (i.e. alphanumerics, plus '-' and '_'), and is non-empty. - auto validTagChars = [](const char* s) { - if (!s || !*s) { - return false; - } - while (*s) { - if (isalnum((unsigned char)*s) || *s == '-' || *s == '_' || *s == '*') { - s++; + MOZ_ASSERT(aDefaultLocale.IsEmpty() || Locale(aDefaultLocale).IsWellFormed(), + "If specified, default locale must be a well-formed BCP47 language tag."); + + if (aStrategy == kLangNegStrategyLookup && aDefaultLocale.IsEmpty()) { + NS_WARNING("Default locale should be specified when using lookup strategy."); + } + + FilterMatches(aRequested, aAvailable, aStrategy, aRetVal); + + if (aStrategy == kLangNegStrategyLookup) { + // If the strategy is Lookup and Filtering returned no matches, use + // the default locale. + if (aRetVal.Length() == 0) { + // If the default locale is empty, we already issued a warning, so + // now we will just pick up the LocaleService's defaultLocale. + if (aDefaultLocale.IsEmpty()) { + nsAutoCString defaultLocale; + GetDefaultLocale(defaultLocale); + aRetVal.AppendElement(defaultLocale); } else { - return false; + aRetVal.AppendElement(aDefaultLocale); } } - return true; - }; - - AutoTArray requestedLocales; - for (uint32_t i = 0; i < aRequestedCount; i++) { - if (!validTagChars(aRequested[i])) { - continue; - } - requestedLocales.AppendElement(aRequested[i]); + } else if (!aDefaultLocale.IsEmpty() && !aRetVal.Contains(aDefaultLocale)) { + // If it's not a Lookup strategy, add the default locale only if it's + // set and it's not in the results already. + aRetVal.AppendElement(aDefaultLocale); } - - AutoTArray availableLocales; - for (uint32_t i = 0; i < aAvailableCount; i++) { - if (!validTagChars(aAvailable[i])) { - continue; - } - availableLocales.AppendElement(aAvailable[i]); - } - - nsAutoCString defaultLocale(aDefaultLocale); - - LangNegStrategy strategy = ToLangNegStrategy(aStrategy); - - AutoTArray supportedLocales; - NegotiateLanguages(requestedLocales, availableLocales, - defaultLocale, strategy, supportedLocales); - - *aRetVal = - static_cast(moz_xmalloc(sizeof(char*) * supportedLocales.Length())); - - *aCount = 0; - for (const auto& supported : supportedLocales) { - (*aRetVal)[(*aCount)++] = moz_xstrdup(supported.get()); - } - return NS_OK; } NS_IMETHODIMP -LocaleService::GetRequestedLocales(uint32_t* aCount, char*** aOutArray) +LocaleService::GetRequestedLocales(nsTArray& aRetVal) { - AutoTArray requestedLocales; - bool res = GetRequestedLocales(requestedLocales); - - if (!res) { - NS_ERROR("Couldn't retrieve selected locales from prefs!"); - return NS_ERROR_FAILURE; + if (mRequestedLocales.IsEmpty()) { + ReadRequestedLocales(mRequestedLocales); } - *aCount = requestedLocales.Length(); - *aOutArray = CreateOutArray(requestedLocales); - + aRetVal = mRequestedLocales; return NS_OK; } NS_IMETHODIMP LocaleService::GetRequestedLocale(nsACString& aRetVal) { - AutoTArray requestedLocales; - bool res = GetRequestedLocales(requestedLocales); - - if (!res) { - NS_ERROR("Couldn't retrieve selected locales from prefs!"); - return NS_ERROR_FAILURE; + if (mRequestedLocales.IsEmpty()) { + ReadRequestedLocales(mRequestedLocales); } - if (requestedLocales.Length() > 0) { - aRetVal = requestedLocales[0]; + if (mRequestedLocales.Length() > 0) { + aRetVal = mRequestedLocales[0]; } return NS_OK; } NS_IMETHODIMP -LocaleService::SetRequestedLocales(const char** aRequested, - uint32_t aRequestedCount) +LocaleService::SetRequestedLocales(const nsTArray& aRequested) { MOZ_ASSERT(mIsServer, "This should only be called in the server mode."); if (!mIsServer) { @@ -906,14 +739,14 @@ LocaleService::SetRequestedLocales(const char** aRequested, nsAutoCString str; - for (uint32_t i = 0; i < aRequestedCount; i++) { - nsAutoCString locale(aRequested[i]); + for (auto& req : aRequested) { + nsAutoCString locale(req); if (!SanitizeForBCP47(locale, true)) { NS_ERROR("Invalid language tag provided to SetRequestedLocales!"); return NS_ERROR_INVALID_ARG; } - if (i > 0) { + if (!str.IsEmpty()) { str.AppendLiteral(","); } str.Append(locale); @@ -924,18 +757,21 @@ LocaleService::SetRequestedLocales(const char** aRequested, } NS_IMETHODIMP -LocaleService::GetAvailableLocales(uint32_t* aCount, char*** aOutArray) +LocaleService::GetAvailableLocales(nsTArray& aRetVal) { - AutoTArray availableLocales; - bool res = GetAvailableLocales(availableLocales); - - if (!res) { - NS_ERROR("Couldn't retrieve available locales!"); - return NS_ERROR_FAILURE; + MOZ_ASSERT(mIsServer, "This should only be called in the server mode."); + if (!mIsServer) { + return NS_ERROR_UNEXPECTED; } - *aCount = availableLocales.Length(); - *aOutArray = CreateOutArray(availableLocales); + if (mAvailableLocales.IsEmpty()) { + // If there are no available locales set, it means that L10nRegistry + // did not register its locale pool yet. The best course of action + // is to use packaged locales until that happens. + GetPackagedLocales(mAvailableLocales); + } + + aRetVal = mAvailableLocales; return NS_OK; } @@ -947,8 +783,7 @@ LocaleService::GetIsAppLocaleRTL(bool* aRetVal) } NS_IMETHODIMP -LocaleService::SetAvailableLocales(const char** aAvailable, - uint32_t aAvailableCount) +LocaleService::SetAvailableLocales(const nsTArray& aAvailable) { MOZ_ASSERT(mIsServer, "This should only be called in the server mode."); if (!mIsServer) { @@ -957,8 +792,8 @@ LocaleService::SetAvailableLocales(const char** aAvailable, nsTArray newLocales; - for (uint32_t i = 0; i < aAvailableCount; i++) { - nsAutoCString locale(aAvailable[i]); + for (auto& avail : aAvailable) { + nsAutoCString locale(avail); if (!SanitizeForBCP47(locale, true)) { NS_ERROR("Invalid language tag provided to SetAvailableLocales!"); return NS_ERROR_INVALID_ARG; @@ -975,14 +810,11 @@ LocaleService::SetAvailableLocales(const char** aAvailable, } NS_IMETHODIMP -LocaleService::GetPackagedLocales(uint32_t* aCount, char*** aOutArray) +LocaleService::GetPackagedLocales(nsTArray& aRetVal) { if (mPackagedLocales.IsEmpty()) { InitPackagedLocales(); } - - *aCount = mPackagedLocales.Length(); - *aOutArray = CreateOutArray(mPackagedLocales); - + aRetVal = mPackagedLocales; return NS_OK; } diff --git a/intl/locale/LocaleService.h b/intl/locale/LocaleService.h index d39808354821..e419b80ddbf7 100644 --- a/intl/locale/LocaleService.h +++ b/intl/locale/LocaleService.h @@ -83,11 +83,9 @@ public: * See the mozILocaleService.idl for detailed description of the * strategies. */ - enum class LangNegStrategy { - Filtering, - Matching, - Lookup - }; + static const int32_t kLangNegStrategyFiltering = 0; + static const int32_t kLangNegStrategyMatching = 1; + static const int32_t kLangNegStrategyLookup = 2; explicit LocaleService(bool aIsServer); @@ -109,45 +107,6 @@ public: return RefPtr(GetInstance()).forget(); } - /** - * Returns a list of locales that the application should be localized to. - * - * The result is a ordered list of valid locale IDs and it should be - * used for all APIs that accept list of locales, like ECMA402 and L10n APIs. - * - * This API always returns at least one locale. - * - * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * Usage: - * nsTArray appLocales; - * LocaleService::GetInstance()->GetAppLocalesAsLangTags(appLocales); - * - * (See mozILocaleService.idl for a JS-callable version of this.) - */ - void GetAppLocalesAsLangTags(nsTArray& aRetVal); - void GetAppLocalesAsBCP47(nsTArray& aRetVal); - - - /** - * Returns a list of locales to use for any regional specific operations - * like date formatting, calendars, unit formatting etc. - * - * The result is a ordered list of valid locale IDs and it should be - * used for all APIs that accept list of locales, like ECMA402 and L10n APIs. - * - * This API always returns at least one locale. - * - * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * Usage: - * nsTArray rgLocales; - * LocaleService::GetInstance()->GetRegionalPrefsLocales(rgLocales); - * - * (See mozILocaleService.idl for a JS-callable version of this.) - */ - void GetRegionalPrefsLocales(nsTArray& aRetVal); - /** * This method should only be called in the client mode. * @@ -160,53 +119,6 @@ public: void AssignAppLocales(const nsTArray& aAppLocales); void AssignRequestedLocales(const nsTArray& aRequestedLocales); - /** - * Returns a list of locales that the user requested the app to be - * localized to. - * - * The result is a sorted list of valid locale IDs and it should be - * used as a requestedLocales input list for languages negotiation. - * - * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * Usage: - * nsTArray reqLocales; - * LocaleService::GetInstance()->GetRequestedLocales(reqLocales); - * - * Returns a boolean indicating if the attempt to retrieve prefs - * was successful. - * - * (See mozILocaleService.idl for a JS-callable version of this.) - */ - bool GetRequestedLocales(nsTArray& aRetVal); - - /** - * Returns a list of available locales that can be used to - * localize the app. - * - * The result is an unsorted list of valid locale IDs and it should be - * used as a availableLocales input list for languages negotiation. - * - * Example: ["de", "en-US", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * Usage: - * nsTArray availLocales; - * LocaleService::GetInstance()->GetAvailableLocales(availLocales); - * - * Returns a boolean indicating if the attempt to retrieve at least - * one locale was successful. - * - * (See mozILocaleService.idl for a JS-callable version of this.) - */ - bool GetAvailableLocales(nsTArray& aRetVal); - - /** - * Returns a list of locales packaged into the app bundle. - * - * (See mozILocaleService.idl for a JS-callable version of this.) - */ - void GetPackagedLocales(nsTArray& aRetVal); - /** * Those two functions allow to trigger cache invalidation on one of the * three cached values. @@ -223,32 +135,6 @@ public: void RequestedLocalesChanged(); void LocalesChanged(); - /** - * Negotiates the best locales out of an ordered list of requested locales and - * a list of available locales. - * - * Internally it uses the following naming scheme: - * - * Requested - locales requested by the user - * Available - locales for which the data is available - * Supported - locales negotiated by the algorithm - * - * Additionally, if defaultLocale is provided, it adds it to the end of the - * result list as a "last resort" locale. - * - * Strategy is one of the three strategies described at the top of this file. - * - * The result list is canonicalized and ordered according to the order - * of the requested locales. - * - * (See mozILocaleService.idl for a JS-callable version of this.) - */ - void NegotiateLanguages(const nsTArray& aRequested, - const nsTArray& aAvailable, - const nsACString& aDefaultLocale, - LangNegStrategy aLangNegStrategy, - nsTArray& aRetVal); - /** * Returns whether the current app locale is RTL. */ @@ -262,7 +148,7 @@ public: private: void FilterMatches(const nsTArray& aRequested, const nsTArray& aAvailable, - LangNegStrategy aStrategy, + int32_t aStrategy, nsTArray& aRetVal); void NegotiateAppLocales(nsTArray& aRetVal); diff --git a/intl/locale/mozILocaleService.idl b/intl/locale/mozILocaleService.idl index 5aae5b61b3fc..41ca6e3e6af0 100644 --- a/intl/locale/mozILocaleService.idl +++ b/intl/locale/mozILocaleService.idl @@ -80,13 +80,9 @@ interface mozILocaleService : nsISupports * use the BCP47 form. * * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * (See LocaleService.h for a more C++-friendly version of this.) */ - void getAppLocalesAsLangTags([optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aLocales); - void getAppLocalesAsBCP47([optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aLocales); + readonly attribute Array appLocalesAsLangTags; + readonly attribute Array appLocalesAsBCP47; /** * Returns a list of locales to use for any regional specific operations @@ -98,11 +94,8 @@ interface mozILocaleService : nsISupports * This API always returns at least one locale. * * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * (See LocaleService.h for a more C++-friendly version of this.) */ - void getRegionalPrefsLocales([optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aOutArray); + readonly attribute Array regionalPrefsLocales; /** * Negotiates the best locales out of a ordered list of requested locales and @@ -124,14 +117,10 @@ interface mozILocaleService : nsISupports * * (See LocaleService.h for a more C++-friendly version of this.) */ - void negotiateLanguages([array, size_is(aRequestedCount)] in string aRequested, - [array, size_is(aAvailableCount)] in string aAvailable, - [optional] in string aDefaultLocale, - [optional] in long langNegStrategy, - [optional] in unsigned long aRequestedCount, - [optional] in unsigned long aAvailableCount, - [optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aLocales); + Array negotiateLanguages(in Array aRequested, + in Array aAvailable, + [optional] in ACString aDefaultLocale, + [optional] in long langNegStrategy); /** * Returns the best locale that the application should be localized to. @@ -144,15 +133,15 @@ interface mozILocaleService : nsISupports * When retrieving the locales for Intl API or ICU locale settings, * use the BCP47 form. * - * Where possible, getAppLocales*() should be preferred over this API and + * Where possible, appLocales* should be preferred over this API and * all callsites should handle some form of "best effort" language * negotiation to respect user preferences in case the use case does * not have data for the first locale in the list. * * Example: "zh-Hans-HK" */ - ACString getAppLocaleAsLangTag(); - ACString getAppLocaleAsBCP47(); + readonly attribute ACString appLocaleAsLangTag; + readonly attribute ACString appLocaleAsBCP47; /** * Returns a list of locales that the user requested the app to be @@ -163,32 +152,12 @@ interface mozILocaleService : nsISupports * * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] */ - void getRequestedLocales([optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aLocales); + attribute Array requestedLocales; /** * Returns the top-requested locale from the user, or an empty string if none is set. */ - ACString getRequestedLocale(); - - /** - * Sets a list of locales that the user requested the app to be - * localized to. - * - * The argument is an ordered list of locale IDs which should be - * used as a requestedLocales input list for language negotiation. - * - * The current implementation is limited to handle at most one - * locale passed to the API. In the future we'll transition to support - * whole fallback chain. - * - * If an empty list is passed, the list of requested locales will - * be picked from the operating system. - * - * Example: ["de"] - */ - void setRequestedLocales([array, size_is(aRequestedCount)] in string aRequested, - [optional] in unsigned long aRequestedCount); + readonly attribute ACString requestedLocale; /** * Returns a list of locales that the app can be localized to. @@ -198,37 +167,17 @@ interface mozILocaleService : nsISupports * * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] */ - void getAvailableLocales([optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aLocales); + attribute Array availableLocales; /** * Returns whether the current app locale is RTL. */ readonly attribute boolean isAppLocaleRTL; - /** - * Sets a list of locales the application has resources to be localized into. - * - * The primary use of this function is to let L10nRegistry communicate all - * locale updates. - * - * The secondary use case is for testing purposes in scenarios in which the - * actual resources don't have to be available. - * It is recommended for tests to create a mock FileSource and register it in - * the L10nRegistry rather than using this call, in order to emulate full - * resource availability cycle. - * - */ - void setAvailableLocales([array, size_is(aAvailableCount)] in string aAvailable, - [optional] in unsigned long aAvailableCount); - /** * Returns a list of locales packaged into the app bundle. * * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] - * - * (See LocaleService.h for a more C++-friendly version of this.) */ - void getPackagedLocales([optional] out unsigned long aCount, - [retval, array, size_is(aCount)] out string aOutArray); + readonly attribute Array packagedLocales; }; diff --git a/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp b/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp index a8192fb25c73..5d4abc842b9b 100644 --- a/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp +++ b/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp @@ -15,8 +15,8 @@ TEST(Intl_Locale_LocaleService, Negotiate) { nsTArray availableLocales; nsTArray supportedLocales; nsAutoCString defaultLocale("en-US"); - LocaleService::LangNegStrategy strategy = - LocaleService::LangNegStrategy::Filtering; + int32_t strategy = + LocaleService::kLangNegStrategyFiltering; requestedLocales.AppendElement(NS_LITERAL_CSTRING("sr")); @@ -36,8 +36,8 @@ TEST(Intl_Locale_LocaleService, UseLSDefaultLocale) { nsTArray availableLocales; nsTArray supportedLocales; nsAutoCString defaultLocale(""); - LocaleService::LangNegStrategy strategy = - LocaleService::LangNegStrategy::Lookup; + int32_t strategy = + LocaleService::kLangNegStrategyLookup; requestedLocales.AppendElement(NS_LITERAL_CSTRING("sr")); diff --git a/intl/locale/tests/unit/test_localeService.js b/intl/locale/tests/unit/test_localeService.js index 2c071782c6d3..1999e4c0cba8 100644 --- a/intl/locale/tests/unit/test_localeService.js +++ b/intl/locale/tests/unit/test_localeService.js @@ -30,11 +30,11 @@ add_test(function test_lastFallbackLocale() { run_next_test(); }); -add_test(function test_getAppLocalesAsLangTags() { - const appLocale = localeService.getAppLocaleAsLangTag(); +add_test(function test_appLocalesAsLangTags() { + const appLocale = localeService.appLocaleAsLangTag; Assert.ok(appLocale != "", "appLocale is non-empty"); - const appLocales = localeService.getAppLocalesAsLangTags(); + const appLocales = localeService.appLocalesAsLangTags; Assert.ok(Array.isArray(appLocales), "appLocales returns an array"); Assert.ok(appLocale == appLocales[0], "appLocale matches first entry in appLocales"); @@ -48,8 +48,8 @@ add_test(function test_getAppLocalesAsLangTags() { 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(); +add_test(function test_requestedLocales() { + const requestedLocales = localeService.requestedLocales; Assert.ok(Array.isArray(requestedLocales), "requestedLocales returns an array"); run_next_test(); @@ -61,9 +61,9 @@ add_test(function test_getRequestedLocales() { * 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. + * OS locale from requestedLocales. */ -add_test(function test_getRequestedLocales_matchOS() { +add_test(function test_requestedLocales_matchOS() { do_test_pending(); Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR"); @@ -72,7 +72,7 @@ add_test(function test_getRequestedLocales_matchOS() { observe: function (aSubject, aTopic, aData) { switch (aTopic) { case REQ_LOC_CHANGE_EVENT: - const reqLocs = localeService.getRequestedLocales(); + const reqLocs = localeService.requestedLocales; Assert.ok(reqLocs[0] === osPrefs.systemLocale); Services.obs.removeObserver(observer, REQ_LOC_CHANGE_EVENT); do_test_finished(); @@ -91,7 +91,7 @@ add_test(function test_getRequestedLocales_matchOS() { * event for requested locales change, it will be fired when the * pref for browser UI locale changes. */ -add_test(function test_getRequestedLocales_onChange() { +add_test(function test_requestedLocales_onChange() { do_test_pending(); Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR"); @@ -100,7 +100,7 @@ add_test(function test_getRequestedLocales_onChange() { observe: function (aSubject, aTopic, aData) { switch (aTopic) { case REQ_LOC_CHANGE_EVENT: - const reqLocs = localeService.getRequestedLocales(); + const reqLocs = localeService.requestedLocales; Assert.ok(reqLocs[0] === "sr-RU"); Services.obs.removeObserver(observer, REQ_LOC_CHANGE_EVENT); do_test_finished(); @@ -114,10 +114,10 @@ add_test(function test_getRequestedLocales_onChange() { run_next_test(); }); -add_test(function test_getRequestedLocale() { +add_test(function test_requestedLocale() { Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "tlh"); - let requestedLocale = localeService.getRequestedLocale(); + let requestedLocale = localeService.requestedLocale; Assert.ok(requestedLocale === "tlh", "requestedLocale returns the right value"); Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES); @@ -125,10 +125,10 @@ add_test(function test_getRequestedLocale() { run_next_test(); }); -add_test(function test_setRequestedLocales() { - localeService.setRequestedLocales(['de-AT', 'de-DE', 'de-CH']); +add_test(function test_requestedLocales() { + localeService.requestedLocales = ['de-AT', 'de-DE', 'de-CH']; - let locales = localeService.getRequestedLocales(); + let locales = localeService.requestedLocales; Assert.ok(locales[0] === 'de-AT'); Assert.ok(locales[1] === 'de-DE'); Assert.ok(locales[2] === 'de-CH'); @@ -142,22 +142,22 @@ add_test(function test_isAppLocaleRTL() { run_next_test(); }); -add_test(function test_getPackagedLocales() { - const locales = localeService.getPackagedLocales(); +add_test(function test_packagedLocales() { + const locales = localeService.packagedLocales; Assert.ok(locales.length !== 0, "Packaged locales are empty"); run_next_test(); }); -add_test(function test_setAvailableLocales() { - const avLocales = localeService.getAvailableLocales(); - localeService.setAvailableLocales(["und", "ar-IR"]); +add_test(function test_availableLocales() { + const avLocales = localeService.availableLocales; + localeService.availableLocales = ["und", "ar-IR"]; - let locales = localeService.getAvailableLocales(); + let locales = localeService.availableLocales; Assert.ok(locales.length == 2); Assert.ok(locales[0] === 'und'); Assert.ok(locales[1] === 'ar-IR'); - localeService.setAvailableLocales(avLocales); + localeService.availableLocales = avLocales; run_next_test(); }); @@ -165,10 +165,10 @@ add_test(function test_setAvailableLocales() { /** * This test verifies that all values coming from the pref are sanitized. */ -add_test(function test_getRequestedLocales_sanitize() { +add_test(function test_requestedLocales_sanitize() { Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "de,2,#$@#,pl,ąó,!a2,DE-at,,;"); - let locales = localeService.getRequestedLocales(); + let locales = localeService.requestedLocales; Assert.equal(locales[0], "de"); Assert.equal(locales[1], "pl"); Assert.equal(locales[2], "de-AT"); @@ -181,27 +181,27 @@ add_test(function test_getRequestedLocales_sanitize() { }); add_test(function test_handle_ja_JP_mac() { - const bkpAvLocales = localeService.getAvailableLocales(); + const bkpAvLocales = localeService.availableLocales; - localeService.setAvailableLocales(["ja-JP-mac", "en-US"]); + localeService.availableLocales = ["ja-JP-mac", "en-US"]; - localeService.setRequestedLocales(['ja-JP-mac']); + localeService.requestedLocales = ['ja-JP-mac']; - let reqLocales = localeService.getRequestedLocales(); + let reqLocales = localeService.requestedLocales; Assert.equal(reqLocales[0], 'ja-JP-macos'); - let avLocales = localeService.getAvailableLocales(); + let avLocales = localeService.availableLocales; Assert.equal(avLocales[0], 'ja-JP-macos'); - let appLocales = localeService.getAppLocalesAsBCP47(); + let appLocales = localeService.appLocalesAsBCP47; Assert.equal(appLocales[0], 'ja-JP-macos'); - let appLocalesAsLT = localeService.getAppLocalesAsLangTags(); + let appLocalesAsLT = localeService.appLocalesAsLangTags; Assert.equal(appLocalesAsLT[0], 'ja-JP-mac'); - Assert.equal(localeService.getAppLocaleAsLangTag(), "ja-JP-mac"); + Assert.equal(localeService.appLocaleAsLangTag, "ja-JP-mac"); - localeService.setAvailableLocales(bkpAvLocales); + localeService.availableLocales = bkpAvLocales; run_next_test(); }); diff --git a/intl/locale/tests/unit/test_localeService_negotiateLanguages.js b/intl/locale/tests/unit/test_localeService_negotiateLanguages.js index fb0007be726b..56bddaf4adf9 100644 --- a/intl/locale/tests/unit/test_localeService_negotiateLanguages.js +++ b/intl/locale/tests/unit/test_localeService_negotiateLanguages.js @@ -82,23 +82,9 @@ const data = { [["ja-JP-mac", "de-DE"], ["ja-JP-mac", "de-DE"], ["ja-JP-mac", "de-DE"]], ], "should not crash on invalid input": [ - [null, ["fr-FR"], []], - [[null], [], []], - [[undefined], [], []], - [[undefined], [null], []], - [[undefined], [undefined], []], - [[null], [null], null, null, []], - [undefined, ["fr-FR"], []], - [2, ["fr-FR"], []], - ["fr-FR", ["fr-FR"], []], [["fą-FŻ"], ["ór_Fń"], []], - [["fr-FR"], null, []], - [["fr-FR"], undefined, []], - [["fr-FR"], 2, []], - [["fr-FR"], "fr-FR", []], [["2"], ["ąóżł"], []], - [[[]], ["fr-FR"], []], - [[[]], [[2]], []], + [[[""]], ["fr-FR"], []], ], }, "matching": { @@ -143,4 +129,26 @@ function run_test() } } } + + // Verify that we error out when requested or available is not an array. + for ([req, avail] in [ + [null, ["fr-FR"]], + [undefined, ["fr-FR"]], + [2, ["fr-FR"]], + ["fr-FR", ["fr-FR"]], + [["fr-FR"], null], + [["fr-FR"], undefined], + [["fr-FR"], 2], + [["fr-FR"], "fr-FR"], + [[null], []], + [[undefined], []], + [[undefined], [null]], + [[undefined], [undefined]], + [[null], [null]], + [[[]], [[2]]], + ]) { + Assert.throws(() => { + nl(req, avail); + }, err => err.result == Cr.NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY); + } }