Commit bc43c8e8 authored by Brian Stell's avatar Brian Stell Committed by Commit Bot

[intl] Port getAvailableLocales to C++

R=gsathya@chromium.org
Bug: v8:5751

Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: If842ab4850fc8d75bebb5331188ee237c5f1e9d7
Reviewed-on: https://chromium-review.googlesource.com/1097419Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarNebojša Ćirić <cira@chromium.org>
Commit-Queue: Brian Stell <bstell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53850}
parent 8ea702e6
......@@ -23,6 +23,14 @@ class TimeZone;
namespace v8 {
namespace internal {
enum class IcuService {
kBreakIterator,
kCollator,
kDateFormat,
kNumberFormat,
kPluralRules
};
const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat,
std::unique_ptr<uc16[]>* dest,
int32_t length);
......
......@@ -13,6 +13,7 @@
#include "src/api.h"
#include "src/global-handles.h"
#include "src/heap/factory.h"
#include "src/intl.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/objects/managed.h"
......@@ -1078,5 +1079,84 @@ void V8BreakIterator::DeleteBreakIterator(
GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
}
// Build the shortened locale; eg, convert xx_Yyyy_ZZ to xx_ZZ.
bool IntlUtil::RemoveLocaleScriptTag(const std::string& icu_locale,
std::string* locale_less_script) {
icu::Locale new_locale = icu::Locale::createCanonical(icu_locale.c_str());
const char* icu_script = new_locale.getScript();
if (icu_script == NULL || strlen(icu_script) == 0) {
*locale_less_script = std::string();
return false;
}
const char* icu_language = new_locale.getLanguage();
const char* icu_country = new_locale.getCountry();
icu::Locale short_locale = icu::Locale(icu_language, icu_country);
const char* icu_name = short_locale.getName();
*locale_less_script = std::string(icu_name);
return true;
}
std::set<std::string> IntlUtil::GetAvailableLocales(const IcuService& service) {
const icu::Locale* icu_available_locales = nullptr;
int32_t count = 0;
switch (service) {
case IcuService::kBreakIterator:
icu_available_locales = icu::BreakIterator::getAvailableLocales(count);
break;
case IcuService::kCollator:
icu_available_locales = icu::Collator::getAvailableLocales(count);
break;
case IcuService::kDateFormat:
icu_available_locales = icu::DateFormat::getAvailableLocales(count);
break;
case IcuService::kNumberFormat:
icu_available_locales = icu::NumberFormat::getAvailableLocales(count);
break;
case IcuService::kPluralRules:
// TODO(littledan): For PluralRules, filter out locales that
// don't support PluralRules.
// PluralRules is missing an appropriate getAvailableLocales method,
// so we should filter from all locales, but it's not clear how; see
// https://ssl.icu-project.org/trac/ticket/12756
icu_available_locales = icu::Locale::getAvailableLocales(count);
break;
}
UErrorCode error = U_ZERO_ERROR;
char result[ULOC_FULLNAME_CAPACITY];
std::set<std::string> locales;
for (int32_t i = 0; i < count; ++i) {
const char* icu_name = icu_available_locales[i].getName();
error = U_ZERO_ERROR;
// No need to force strict BCP47 rules.
uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
// This shouldn't happen, but lets not break the user.
continue;
}
std::string locale(result);
locales.insert(locale);
std::string shortened_locale;
if (IntlUtil::RemoveLocaleScriptTag(icu_name, &shortened_locale)) {
error = U_ZERO_ERROR;
char bcp47_result[ULOC_FULLNAME_CAPACITY];
uloc_toLanguageTag(shortened_locale.c_str(), bcp47_result,
ULOC_FULLNAME_CAPACITY, true, &error);
if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
// This shouldn't happen, but lets not break the user.
continue;
}
locales.insert(shortened_locale);
}
}
return locales;
}
} // namespace internal
} // namespace v8
......@@ -9,6 +9,10 @@
#ifndef V8_OBJECTS_INTL_OBJECTS_H_
#define V8_OBJECTS_INTL_OBJECTS_H_
#include <set>
#include <string>
#include "src/intl.h"
#include "src/objects.h"
#include "unicode/uversion.h"
......@@ -159,6 +163,19 @@ class V8BreakIterator {
V8BreakIterator();
};
class IntlUtil {
public:
// Gets the ICU locales for a given service. If there is a locale with a
// script tag then the locales also include a locale without the script; eg,
// pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India) would include
// pa_IN.
static std::set<std::string> GetAvailableLocales(const IcuService& service);
// If locale has a script tag then return true and the locale without the
// script else return false and an empty string
static bool RemoveLocaleScriptTag(const std::string& icu_locale,
std::string* locale_less_script);
};
} // namespace internal
} // namespace v8
......
......@@ -397,6 +397,7 @@ v8_source_set("cctest_sources") {
if (v8_enable_i18n_support) {
defines += [ "V8_INTL_SUPPORT" ]
public_deps += [ "//third_party/icu" ]
} else {
sources -= [ "test-intl.cc" ]
}
......
......@@ -7,6 +7,7 @@
#include "src/builtins/builtins-intl.h"
#include "src/lookup.h"
#include "src/objects-inl.h"
#include "src/objects/intl-objects.h"
#include "test/cctest/cctest.h"
namespace v8 {
......@@ -191,6 +192,51 @@ TEST(GetOptions) {
CHECK(result->IsFalse(isolate));
}
bool ScriptTagWasRemoved(std::string locale, std::string expected) {
std::string without_script_tag;
bool didShorten =
IntlUtil::RemoveLocaleScriptTag(locale, &without_script_tag);
return didShorten && expected == without_script_tag;
}
bool ScriptTagWasNotRemoved(std::string locale) {
std::string without_script_tag;
bool didShorten =
IntlUtil::RemoveLocaleScriptTag(locale, &without_script_tag);
return !didShorten && without_script_tag.empty();
}
TEST(RemoveLocaleScriptTag) {
CHECK(ScriptTagWasRemoved("aa_Bbbb_CC", "aa_CC"));
CHECK(ScriptTagWasRemoved("aaa_Bbbb_CC", "aaa_CC"));
CHECK(ScriptTagWasNotRemoved("aa"));
CHECK(ScriptTagWasNotRemoved("aaa"));
CHECK(ScriptTagWasNotRemoved("aa_CC"));
CHECK(ScriptTagWasNotRemoved("aa_Bbb_CC"));
CHECK(ScriptTagWasNotRemoved("aa_1bbb_CC"));
}
TEST(GetAvailableLocales) {
std::set<std::string> locales;
locales = IntlUtil::GetAvailableLocales(IcuService::kBreakIterator);
CHECK(locales.count("en-US"));
CHECK(!locales.count("abcdefg"));
locales = IntlUtil::GetAvailableLocales(IcuService::kCollator);
CHECK(locales.count("en-US"));
locales = IntlUtil::GetAvailableLocales(IcuService::kDateFormat);
CHECK(locales.count("en-US"));
locales = IntlUtil::GetAvailableLocales(IcuService::kNumberFormat);
CHECK(locales.count("en-US"));
locales = IntlUtil::GetAvailableLocales(IcuService::kPluralRules);
CHECK(locales.count("en-US"));
}
} // namespace internal
} // namespace v8
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment