gecko-dev/intl/locale/MozLocale.cpp

158 строки
3.5 KiB
C++
Исходник Обычный вид История

/* -*- 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;
}