Bug 1400006 - Extend language negotiation in LocaleService to support looking for the best likelySubtag for the locale with region stripped. r?jfkthame
MozReview-Commit-ID: BR1WrgXSf6a
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -368,17 +368,24 @@ LocaleService::OnLocalesChanged()
* ^^
* |-- ICU likelySubtags expands it to 'en-Latn-US'
*
* 4) Attempt to look up for a different variant of the same locale.
* Example: ['ja-JP-win'] * ['ja-JP-mac'] = ['ja-JP-mac']
* ^^^^^^^^^
* |----------- replace variant with range: 'ja-JP-*'
*
- * 5) Attempt to look up for a different region of the same locale.
+ * 5) Attempt to look up for a maximized version of the requested locale,
+ * stripped of the region code.
+ * Example: ['en-CA'] * ['en-ZA', 'en-US'] = ['en-US', 'en-ZA']
+ * ^^^^^
+ * |----------- look for likelySubtag of 'en': 'en-Latn-US'
+ *
+ *
+ * 6) Attempt to look up for a different region of the same locale.
* Example: ['en-GB'] * ['en-AU'] = ['en-AU']
* ^^^^^
* |----- replace region with range: 'en-*'
*
* It uses one of the strategies described in LocaleService.h.
*/
void
LocaleService::FilterMatches(const nsTArray<nsCString>& aRequested,
@@ -454,17 +461,25 @@ LocaleService::FilterMatches(const nsTAr
}
// 4) Try to match against a variant as a range
requestedLocale.SetVariantRange();
if (findRangeMatches(requestedLocale)) {
HANDLE_STRATEGY;
}
- // 5) Try to match against a region as a range
+ // 5) Try to match against the likely subtag without region
+ if (requestedLocale.AddLikelySubtagsWithoutRegion()) {
+ if (findRangeMatches(requestedLocale)) {
+ HANDLE_STRATEGY;
+ }
+ }
+
+
+ // 6) Try to match against a region as a range
requestedLocale.SetRegionRange();
if (findRangeMatches(requestedLocale)) {
HANDLE_STRATEGY;
}
}
}
bool
@@ -817,38 +832,63 @@ void
LocaleService::Locale::SetRegionRange()
{
mRegion.AssignLiteral("*");
}
bool
LocaleService::Locale::AddLikelySubtags()
{
+ return AddLikelySubtagsForLocale(mLocaleStr);
+}
+
+bool
+LocaleService::Locale::AddLikelySubtagsWithoutRegion()
+{
+ nsAutoCString locale(mLanguage);
+
+ if (!mScript.IsEmpty()) {
+ locale.Append("-");
+ locale.Append(mScript);
+ }
+
+ // We don't add variant here because likelySubtag doesn't care about it.
+
+ return AddLikelySubtagsForLocale(locale);
+}
+
+bool
+LocaleService::Locale::AddLikelySubtagsForLocale(const nsACString& aLocale)
+{
#ifdef ENABLE_INTL_API
const int32_t kLocaleMax = 160;
char maxLocale[kLocaleMax];
+ nsAutoCString locale(aLocale);
UErrorCode status = U_ZERO_ERROR;
- uloc_addLikelySubtags(mLocaleStr.get(), maxLocale, kLocaleMax, &status);
+ uloc_addLikelySubtags(locale.get(), maxLocale, kLocaleMax, &status);
if (U_FAILURE(status)) {
return false;
}
nsDependentCString maxLocStr(maxLocale);
Locale loc = Locale(maxLocStr, false);
if (loc == *this) {
return false;
}
mLanguage = loc.mLanguage;
mScript = loc.mScript;
mRegion = loc.mRegion;
- mVariant = loc.mVariant;
+
+ // We don't update variant from likelySubtag since it's not going to
+ // provide it and we want to preserve the range
+
return true;
#else
return false;
#endif
}
NS_IMETHODIMP
LocaleService::GetRequestedLocales(uint32_t* aCount, char*** aOutArray)
--- a/intl/locale/LocaleService.h
+++ b/intl/locale/LocaleService.h
@@ -266,17 +266,19 @@ private:
Locale(const nsCString& aLocale, bool aRange);
bool Matches(const Locale& aLocale) const;
bool LanguageMatches(const Locale& aLocale) const;
void SetVariantRange();
void SetRegionRange();
- bool AddLikelySubtags(); // returns false if nothing changed
+ // returns false if nothing changed
+ bool AddLikelySubtags();
+ bool AddLikelySubtagsWithoutRegion();
const nsCString& AsString() const {
return mLocaleStr;
}
bool operator== (const Locale& aOther) {
const auto& cmp = nsCaseInsensitiveCStringComparator();
return mLanguage.Equals(aOther.mLanguage, cmp) &&
@@ -286,16 +288,18 @@ private:
}
private:
const nsCString& mLocaleStr;
nsCString mLanguage;
nsCString mScript;
nsCString mRegion;
nsCString mVariant;
+
+ bool AddLikelySubtagsForLocale(const nsACString& aLocale);
};
void FilterMatches(const nsTArray<nsCString>& aRequested,
const nsTArray<nsCString>& aAvailable,
LangNegStrategy aStrategy,
nsTArray<nsCString>& aRetVal);
void NegotiateAppLocales(nsTArray<nsCString>& aRetVal);
--- a/intl/locale/tests/unit/test_localeService_negotiateLanguages.js
+++ b/intl/locale/tests/unit/test_localeService_negotiateLanguages.js
@@ -30,16 +30,19 @@ const data = {
[["fr"], ["fr-CA", "fr-FR"], ["fr-FR", "fr-CA"]],
[["az-IR"], ["az-Latn", "az-Arab"], ["az-Arab"]],
[["sr-RU"], ["sr-Cyrl", "sr-Latn"], ["sr-Latn"]],
[["sr"], ["sr-Latn", "sr-Cyrl"], ["sr-Cyrl"]],
[["zh-GB"], ["zh-Hans", "zh-Hant"], ["zh-Hant"]],
[["sr", "ru"], ["sr-Latn", "ru"], ["ru"]],
[["sr-RU"], ["sr-Latn-RO", "sr-Cyrl"], ["sr-Latn-RO"]],
],
+ "should match likelySubtag region over other regions": [
+ [["en-CA"], ["en-ZA", "en-GB", "en-US"], ["en-US", "en-ZA", "en-GB"]],
+ ],
"should match on a requested locale as a range": [
[["en-*-US"], ["en-US"], ["en-US"]],
[["en-Latn-US-*"], ["en-Latn-US"], ["en-Latn-US"]],
[["en-*-US-*"], ["en-US"], ["en-US"]],
],
"should match cross-region": [
[["en"], ["en-US"], ["en-US"]],
[["en-US"], ["en-GB"], ["en-GB"]],