Bug 1428530 - Separate out mozilla::intl::Locale. r=jfkthame

MozReview-Commit-ID: IELFjNCoJEo

--HG--
extra : rebase_source : a735a893e93669af5b91951519ea9dadeb8123ad
This commit is contained in:
Zibi Braniecki 2018-01-06 00:23:09 -08:00
parent aab6457784
commit 9ca3cdc5a5
5 changed files with 212 additions and 187 deletions

153
intl/locale/Locale.cpp Normal file
View File

@ -0,0 +1,153 @@
/* -*- 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 "Locale.h"
#include "unicode/uloc.h"
using namespace mozilla::intl;
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;
}

56
intl/locale/Locale.h Normal file
View File

@ -0,0 +1,56 @@
#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 "*".
*/
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__ */

View File

@ -10,6 +10,7 @@
#include "mozilla/Omnijar.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/intl/Locale.h"
#include "mozilla/intl/OSPreferences.h"
#include "nsIObserverService.h"
#include "nsIToolkitChromeRegistry.h"
@ -804,149 +805,6 @@ LocaleService::NegotiateLanguages(const char** aRequested,
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)
{

View File

@ -253,50 +253,6 @@ public:
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<nsCString>& aRequested,
const nsTArray<nsCString>& aAvailable,
LangNegStrategy aStrategy,

View File

@ -33,12 +33,14 @@ EXPORTS += [
]
EXPORTS.mozilla.intl += [
'Locale.h',
'LocaleService.h',
'OSPreferences.h',
]
UNIFIED_SOURCES += [
'DateTimeFormat.cpp',
'Locale.cpp',
'LocaleService.cpp',
'nsCollation.cpp',
'nsCollationFactory.cpp',