# HG changeset patch # User Zibi Braniecki # Date 1515226989 28800 # Node ID 641eff95e2018901759d2f39b25b5a7162630c9e # Parent 2cee5e3e544a9bcd698389b98df8082bed147c3e Bug 1428530 - Separate out mozilla::intl::Locale. r=jfkthame MozReview-Commit-ID: IELFjNCoJEo diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp --- a/intl/locale/LocaleService.cpp +++ b/intl/locale/LocaleService.cpp @@ -6,16 +6,17 @@ #include "LocaleService.h" #include // find_if() #include "mozilla/ClearOnShutdown.h" #include "mozilla/Omnijar.h" #include "mozilla/Preferences.h" #include "mozilla/DebugOnly.h" #include "mozilla/Services.h" +#include "mozilla/intl/MozLocale.h" #include "mozilla/intl/OSPreferences.h" #include "nsIObserverService.h" #include "nsStringEnumerator.h" #include "nsIToolkitChromeRegistry.h" #include "nsXULAppAPI.h" #include "nsZipArchive.h" #include "unicode/uloc.h" @@ -800,159 +801,16 @@ LocaleService::NegotiateLanguages(const *aCount = 0; for (const auto& supported : supportedLocales) { (*aRetVal)[(*aCount)++] = moz_xstrdup(supported.get()); } return NS_OK; } -LocaleService::Locale::Locale(const nsCString& aLocale, bool aRange) - : mLocaleStr(aLocale) -{ - int32_t partNum = 0; - - nsAutoCString normLocale(aLocale); - normLocale.ReplaceChar('_', '-'); - - for (const nsACString& part : normLocale.Split('-')) { - switch (partNum) { - case 0: - if (part.EqualsLiteral("*") || - part.Length() == 2 || part.Length() == 3) { - mLanguage.Assign(part); - } - break; - case 1: - if (part.EqualsLiteral("*") || part.Length() == 4) { - mScript.Assign(part); - break; - } - - // fallover to region case - partNum++; - MOZ_FALLTHROUGH; - case 2: - if (part.EqualsLiteral("*") || part.Length() == 2) { - mRegion.Assign(part); - } - break; - case 3: - if (part.EqualsLiteral("*") || (part.Length() >= 3 && part.Length() <= 8)) { - mVariant.Assign(part); - } - break; - } - partNum++; - } - - if (aRange) { - if (mLanguage.IsEmpty()) { - mLanguage.AssignLiteral("*"); - } - if (mScript.IsEmpty()) { - mScript.AssignLiteral("*"); - } - if (mRegion.IsEmpty()) { - mRegion.AssignLiteral("*"); - } - if (mVariant.IsEmpty()) { - mVariant.AssignLiteral("*"); - } - } -} - -static bool -SubtagMatches(const nsCString& aSubtag1, const nsCString& aSubtag2) -{ - return aSubtag1.EqualsLiteral("*") || - aSubtag2.EqualsLiteral("*") || - aSubtag1.Equals(aSubtag2, nsCaseInsensitiveCStringComparator()); -} - -bool -LocaleService::Locale::Matches(const LocaleService::Locale& aLocale) const -{ - return SubtagMatches(mLanguage, aLocale.mLanguage) && - SubtagMatches(mScript, aLocale.mScript) && - SubtagMatches(mRegion, aLocale.mRegion) && - SubtagMatches(mVariant, aLocale.mVariant); -} - -bool -LocaleService::Locale::LanguageMatches(const LocaleService::Locale& aLocale) const -{ - return SubtagMatches(mLanguage, aLocale.mLanguage) && - SubtagMatches(mScript, aLocale.mScript); -} - -void -LocaleService::Locale::SetVariantRange() -{ - mVariant.AssignLiteral("*"); -} - -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) -{ - const int32_t kLocaleMax = 160; - char maxLocale[kLocaleMax]; - nsAutoCString locale(aLocale); - - UErrorCode status = U_ZERO_ERROR; - 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; - - // We don't update variant from likelySubtag since it's not going to - // provide it and we want to preserve the range - - return true; -} - NS_IMETHODIMP LocaleService::GetRequestedLocales(uint32_t* aCount, char*** aOutArray) { AutoTArray requestedLocales; bool res = GetRequestedLocales(requestedLocales); if (!res) { NS_ERROR("Couldn't retrieve selected locales from prefs!"); diff --git a/intl/locale/LocaleService.h b/intl/locale/LocaleService.h --- a/intl/locale/LocaleService.h +++ b/intl/locale/LocaleService.h @@ -248,60 +248,16 @@ public: bool IsAppLocaleRTL(); static bool LanguagesMatch(const nsCString& aRequested, const nsCString& aAvailable); bool IsServer(); private: - /** - * Locale object, a BCP47-style tag decomposed into subtags for - * matching purposes. - * - * If constructed with aRange = true, any missing subtags will be - * set to "*". - */ - class Locale - { - public: - Locale(const nsCString& aLocale, bool aRange); - - bool Matches(const Locale& aLocale) const; - bool LanguageMatches(const Locale& aLocale) const; - - void SetVariantRange(); - void SetRegionRange(); - - // 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) && - mScript.Equals(aOther.mScript, cmp) && - mRegion.Equals(aOther.mRegion, cmp) && - mVariant.Equals(aOther.mVariant, cmp); - } - - private: - const nsCString& mLocaleStr; - nsCString mLanguage; - nsCString mScript; - nsCString mRegion; - nsCString mVariant; - - bool AddLikelySubtagsForLocale(const nsACString& aLocale); - }; - void FilterMatches(const nsTArray& aRequested, const nsTArray& aAvailable, LangNegStrategy aStrategy, nsTArray& aRetVal); void NegotiateAppLocales(nsTArray& aRetVal); virtual ~LocaleService(); diff --git a/intl/locale/MozLocale.cpp b/intl/locale/MozLocale.cpp new file mode 100644 --- /dev/null +++ b/intl/locale/MozLocale.cpp @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#include "mozilla/intl/MozLocale.h" + +#include "unicode/uloc.h" + +using namespace mozilla::intl; + +/** + * Note: The file name is `MozLocale` to avoid compilation problems on case-insensitive + * Windows. The class name is `Locale`. + */ +Locale::Locale(const nsCString& aLocale, bool aRange) + : mLocaleStr(aLocale) +{ + int32_t partNum = 0; + + nsAutoCString normLocale(aLocale); + normLocale.ReplaceChar('_', '-'); + + for (const nsACString& part : normLocale.Split('-')) { + switch (partNum) { + case 0: + if (part.EqualsLiteral("*") || + part.Length() == 2 || part.Length() == 3) { + mLanguage.Assign(part); + } + break; + case 1: + if (part.EqualsLiteral("*") || part.Length() == 4) { + mScript.Assign(part); + break; + } + + // fallover to region case + partNum++; + MOZ_FALLTHROUGH; + case 2: + if (part.EqualsLiteral("*") || part.Length() == 2) { + mRegion.Assign(part); + } + break; + case 3: + if (part.EqualsLiteral("*") || (part.Length() >= 3 && part.Length() <= 8)) { + mVariant.Assign(part); + } + break; + } + partNum++; + } + + if (aRange) { + if (mLanguage.IsEmpty()) { + mLanguage.AssignLiteral("*"); + } + if (mScript.IsEmpty()) { + mScript.AssignLiteral("*"); + } + if (mRegion.IsEmpty()) { + mRegion.AssignLiteral("*"); + } + if (mVariant.IsEmpty()) { + mVariant.AssignLiteral("*"); + } + } +} + +static bool +SubtagMatches(const nsCString& aSubtag1, const nsCString& aSubtag2) +{ + return aSubtag1.EqualsLiteral("*") || + aSubtag2.EqualsLiteral("*") || + aSubtag1.Equals(aSubtag2, nsCaseInsensitiveCStringComparator()); +} + +bool +Locale::Matches(const Locale& aLocale) const +{ + return SubtagMatches(mLanguage, aLocale.mLanguage) && + SubtagMatches(mScript, aLocale.mScript) && + SubtagMatches(mRegion, aLocale.mRegion) && + SubtagMatches(mVariant, aLocale.mVariant); +} + +bool +Locale::LanguageMatches(const Locale& aLocale) const +{ + return SubtagMatches(mLanguage, aLocale.mLanguage) && + SubtagMatches(mScript, aLocale.mScript); +} + +void +Locale::SetVariantRange() +{ + mVariant.AssignLiteral("*"); +} + +void +Locale::SetRegionRange() +{ + mRegion.AssignLiteral("*"); +} + +bool +Locale::AddLikelySubtags() +{ + return AddLikelySubtagsForLocale(mLocaleStr); +} + +bool +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 +Locale::AddLikelySubtagsForLocale(const nsACString& aLocale) +{ + const int32_t kLocaleMax = 160; + char maxLocale[kLocaleMax]; + nsAutoCString locale(aLocale); + + UErrorCode status = U_ZERO_ERROR; + 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; + + // We don't update variant from likelySubtag since it's not going to + // provide it and we want to preserve the range + + return true; +} diff --git a/intl/locale/MozLocale.h b/intl/locale/MozLocale.h new file mode 100644 --- /dev/null +++ b/intl/locale/MozLocale.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef mozilla_intl_Locale_h__ +#define mozilla_intl_Locale_h__ + +#include "nsString.h" + +namespace mozilla { +namespace intl { + +/** + * Locale object, a BCP47-style tag decomposed into subtags for + * matching purposes. + * + * If constructed with aRange = true, any missing subtags will be + * set to "*". + * + * Note: The file name is `MozLocale` to avoid compilation problems on case-insensitive + * Windows. The class name is `Locale`. + */ +class Locale { + public: + Locale(const nsCString& aLocale, bool aRange); + + bool Matches(const Locale& aLocale) const; + bool LanguageMatches(const Locale& aLocale) const; + + + void SetVariantRange(); + void SetRegionRange(); + + // 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) && + mScript.Equals(aOther.mScript, cmp) && + mRegion.Equals(aOther.mRegion, cmp) && + mVariant.Equals(aOther.mVariant, cmp); + } + + private: + const nsCString& mLocaleStr; + nsCString mLanguage; + nsCString mScript; + nsCString mRegion; + nsCString mVariant; + + bool AddLikelySubtagsForLocale(const nsACString& aLocale); +}; + +} // intl +} // namespace mozilla + +#endif /* mozilla_intl_Locale_h__ */ diff --git a/intl/locale/moz.build b/intl/locale/moz.build --- a/intl/locale/moz.build +++ b/intl/locale/moz.build @@ -27,22 +27,24 @@ EXPORTS += [ 'DateTimeFormat.h', 'nsCollationCID.h', 'nsLanguageAtomService.h', 'nsUConvPropertySearch.h', ] EXPORTS.mozilla.intl += [ 'LocaleService.h', + 'MozLocale.h', 'OSPreferences.h', ] UNIFIED_SOURCES += [ 'DateTimeFormat.cpp', 'LocaleService.cpp', + 'MozLocale.cpp', 'nsCollation.cpp', 'nsCollationFactory.cpp', 'nsLanguageAtomService.cpp', 'nsUConvPropertySearch.cpp', 'OSPreferences.cpp', ] EXTRA_JS_MODULES += [