summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/js-locale.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects/js-locale.cc')
-rw-r--r--deps/v8/src/objects/js-locale.cc569
1 files changed, 312 insertions, 257 deletions
diff --git a/deps/v8/src/objects/js-locale.cc b/deps/v8/src/objects/js-locale.cc
index 78fb30fa41..be438a2508 100644
--- a/deps/v8/src/objects/js-locale.cc
+++ b/deps/v8/src/objects/js-locale.cc
@@ -20,39 +20,29 @@
#include "src/objects-inl.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-locale-inl.h"
+#include "unicode/char16ptr.h"
#include "unicode/locid.h"
#include "unicode/uloc.h"
#include "unicode/unistr.h"
-#include "unicode/uvernum.h"
-#include "unicode/uversion.h"
-
-#if U_ICU_VERSION_MAJOR_NUM >= 59
-#include "unicode/char16ptr.h"
-#endif
namespace v8 {
namespace internal {
namespace {
-JSLocale::CaseFirst GetCaseFirst(const char* str) {
- if (strcmp(str, "upper") == 0) return JSLocale::CaseFirst::UPPER;
- if (strcmp(str, "lower") == 0) return JSLocale::CaseFirst::LOWER;
- if (strcmp(str, "false") == 0) return JSLocale::CaseFirst::FALSE_VALUE;
- UNREACHABLE();
-}
-
-JSLocale::HourCycle GetHourCycle(const char* str) {
- if (strcmp(str, "h11") == 0) return JSLocale::HourCycle::H11;
- if (strcmp(str, "h12") == 0) return JSLocale::HourCycle::H12;
- if (strcmp(str, "h23") == 0) return JSLocale::HourCycle::H23;
- if (strcmp(str, "h24") == 0) return JSLocale::HourCycle::H24;
- UNREACHABLE();
-}
-
-JSLocale::Numeric GetNumeric(const char* str) {
- return strcmp(str, "true") == 0 ? JSLocale::Numeric::TRUE_VALUE
- : JSLocale::Numeric::FALSE_VALUE;
+// Helper function to check a locale is valid. It will return false if
+// the length of the extension fields are incorrect. For example, en-u-a or
+// en-u-co-b will return false.
+bool IsValidLocale(const icu::Locale& locale) {
+ // icu::Locale::toLanguageTag won't return U_STRING_NOT_TERMINATED_WARNING for
+ // incorrect locale yet. So we still need the following uloc_toLanguageTag
+ // TODO(ftang): Change to use icu::Locale::toLanguageTag once it indicate
+ // error.
+ char result[ULOC_FULLNAME_CAPACITY];
+ UErrorCode status = U_ZERO_ERROR;
+ uloc_toLanguageTag(locale.getName(), result, ULOC_FULLNAME_CAPACITY, true,
+ &status);
+ return U_SUCCESS(status) && status != U_STRING_NOT_TERMINATED_WARNING;
}
struct OptionData {
@@ -65,9 +55,9 @@ struct OptionData {
// Inserts tags from options into locale string.
Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
Handle<JSReceiver> options,
- char* icu_locale) {
+ icu::Locale* icu_locale) {
CHECK(isolate);
- CHECK(icu_locale);
+ CHECK(!icu_locale->isBogus());
const std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23",
"h24"};
@@ -85,6 +75,7 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
// TODO(cira): Pass in values as per the spec to make this to be
// spec compliant.
+ UErrorCode status = U_ZERO_ERROR;
for (const auto& option_to_bcp47 : kOptionToUnicodeTagMap) {
std::unique_ptr<char[]> value_str = nullptr;
bool value_bool = false;
@@ -114,14 +105,9 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
// Overwrite existing, or insert new key-value to the locale string.
const char* value = uloc_toLegacyType(key, value_str.get());
- UErrorCode status = U_ZERO_ERROR;
if (value) {
- // TODO(cira): ICU puts artificial limit on locale length, while BCP47
- // doesn't. Switch to C++ API when it's ready.
- // Related ICU bug - https://ssl.icu-project.org/trac/ticket/13417.
- uloc_setKeywordValue(key, value, icu_locale, ULOC_FULLNAME_CAPACITY,
- &status);
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
+ icu_locale->setKeywordValue(key, value, status);
+ if (U_FAILURE(status)) {
return Just(false);
}
} else {
@@ -129,277 +115,346 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
}
}
+ // Check all the unicode extension fields are in the right length.
+ if (!IsValidLocale(*icu_locale)) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
+ Nothing<bool>());
+ }
+
return Just(true);
}
-// Fills in the JSLocale object slots with Unicode tag/values.
-bool PopulateLocaleWithUnicodeTags(Isolate* isolate, const char* icu_locale,
- Handle<JSLocale> locale_holder) {
- CHECK(isolate);
- CHECK(icu_locale);
-
- Factory* factory = isolate->factory();
-
+Handle<Object> UnicodeKeywordValue(Isolate* isolate, Handle<JSLocale> locale,
+ const char* key) {
+ icu::Locale* icu_locale = locale->icu_locale()->raw();
UErrorCode status = U_ZERO_ERROR;
- UEnumeration* keywords = uloc_openKeywords(icu_locale, &status);
- if (!keywords) return true;
-
- char value[ULOC_FULLNAME_CAPACITY];
- while (const char* keyword = uenum_next(keywords, nullptr, &status)) {
- uloc_getKeywordValue(icu_locale, keyword, value, ULOC_FULLNAME_CAPACITY,
- &status);
- if (U_FAILURE(status)) {
- status = U_ZERO_ERROR;
- continue;
- }
-
- // Ignore those we don't recognize - spec allows that.
- const char* bcp47_key = uloc_toUnicodeLocaleKey(keyword);
- if (bcp47_key) {
- const char* bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
- if (bcp47_value) {
- if (strcmp(bcp47_key, "kn") == 0) {
- locale_holder->set_numeric(GetNumeric(bcp47_value));
- } else if (strcmp(bcp47_key, "ca") == 0) {
- Handle<String> bcp47_handle =
- factory->NewStringFromAsciiChecked(bcp47_value);
- locale_holder->set_calendar(*bcp47_handle);
- } else if (strcmp(bcp47_key, "kf") == 0) {
- locale_holder->set_case_first(GetCaseFirst(bcp47_value));
- } else if (strcmp(bcp47_key, "co") == 0) {
- Handle<String> bcp47_handle =
- factory->NewStringFromAsciiChecked(bcp47_value);
- locale_holder->set_collation(*bcp47_handle);
- } else if (strcmp(bcp47_key, "hc") == 0) {
- locale_holder->set_hour_cycle(GetHourCycle(bcp47_value));
- } else if (strcmp(bcp47_key, "nu") == 0) {
- Handle<String> bcp47_handle =
- factory->NewStringFromAsciiChecked(bcp47_value);
- locale_holder->set_numbering_system(*bcp47_handle);
- }
- }
- }
+ std::string value =
+ icu_locale->getUnicodeKeywordValue<std::string>(key, status);
+ if (status == U_ILLEGAL_ARGUMENT_ERROR || value == "") {
+ return isolate->factory()->undefined_value();
}
+ return isolate->factory()->NewStringFromAsciiChecked(value.c_str());
+}
- uenum_close(keywords);
+bool InRange(size_t value, size_t start, size_t end) {
+ return (start <= value) && (value <= end);
+}
+bool InRange(char value, char start, char end) {
+ return (start <= value) && (value <= end);
+}
+bool IsCheckRange(const std::string& str, size_t min, size_t max,
+ bool(range_check_func)(char)) {
+ if (!InRange(str.length(), min, max)) return false;
+ for (size_t i = 0; i < str.length(); i++) {
+ if (!range_check_func(str[i])) return false;
+ }
return true;
}
-} // namespace
+bool IsAlpha(const std::string& str, size_t min, size_t max) {
+ return IsCheckRange(str, min, max, [](char c) -> bool {
+ return InRange(c, 'a', 'z') || InRange(c, 'A', 'Z');
+ });
+}
-MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate,
- Handle<JSLocale> locale_holder,
- Handle<String> locale,
- Handle<JSReceiver> options) {
- locale_holder->set_flags(0);
- static const char* const kMethod = "Intl.Locale";
- v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- UErrorCode status = U_ZERO_ERROR;
+bool IsDigit(const std::string& str, size_t min, size_t max) {
+ return IsCheckRange(str, min, max,
+ [](char c) -> bool { return InRange(c, '0', '9'); });
+}
+
+bool ValidateLanguageProduction(const std::string& value) {
+ // language = 2*3ALPHA ; shortest ISO 639 code
+ // ["-" extlang] ; sometimes followed by
+ // ; extended language subtags
+ // / 4ALPHA ; or reserved for future use
+ // / 5*8ALPHA ; or registered language subtag
+ //
+ // extlang = 3ALPHA ; selected ISO 639 codes
+ // *2("-" 3ALPHA) ; permanently reserved
+ // TODO(ftang) not handling the [extlang] yet
+ return IsAlpha(value, 2, 8);
+}
- // Get ICU locale format, and canonicalize it.
- char icu_result[ULOC_FULLNAME_CAPACITY];
+bool ValidateScriptProduction(const std::string& value) {
+ // script = 4ALPHA ; ISO 15924 code
+ return IsAlpha(value, 4, 4);
+}
- if (locale->length() == 0) {
- THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty),
- JSLocale);
+bool ValidateRegionProduction(const std::string& value) {
+ // region = 2ALPHA ; ISO 3166-1 code
+ // / 3DIGIT ; UN M.49 code
+ return IsAlpha(value, 2, 2) || IsDigit(value, 3, 3);
+}
+
+Maybe<icu::Locale> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag,
+ Handle<JSReceiver> options) {
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ if (tag->length() == 0) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty),
+ Nothing<icu::Locale>());
}
- v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale));
- CHECK_LT(0, bcp47_locale.length());
- CHECK_NOT_NULL(*bcp47_locale);
-
- int parsed_length = 0;
- int icu_length =
- uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
- &parsed_length, &status);
-
- if (U_FAILURE(status) ||
- parsed_length < static_cast<int>(bcp47_locale.length()) ||
- status == U_STRING_NOT_TERMINATED_WARNING || icu_length == 0) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
+ v8::String::Utf8Value bcp47_tag(v8_isolate, v8::Utils::ToLocal(tag));
+ CHECK_LT(0, bcp47_tag.length());
+ CHECK_NOT_NULL(*bcp47_tag);
+ // 2. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError
+ // exception.
+ UErrorCode status = U_ZERO_ERROR;
+ icu::Locale icu_locale =
+ icu::Locale::forLanguageTag({*bcp47_tag, bcp47_tag.length()}, status);
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
+ Nothing<icu::Locale>());
}
- Maybe<bool> error = InsertOptionsIntoLocale(isolate, options, icu_result);
- MAYBE_RETURN(error, MaybeHandle<JSLocale>());
- if (!error.FromJust()) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
+ // 3. Let language be ? GetOption(options, "language", "string", undefined,
+ // undefined).
+ const std::vector<const char*> empty_values = {};
+ std::unique_ptr<char[]> language_str = nullptr;
+ Maybe<bool> maybe_language =
+ Intl::GetStringOption(isolate, options, "language", empty_values,
+ "ApplyOptionsToTag", &language_str);
+ MAYBE_RETURN(maybe_language, Nothing<icu::Locale>());
+ // 4. If language is not undefined, then
+ if (maybe_language.FromJust()) {
+ // a. If language does not match the language production, throw a RangeError
+ // exception.
+ // b. If language matches the grandfathered production, throw a RangeError
+ // exception.
+ // Currently ValidateLanguageProduction only take 2*3ALPHA / 4ALPHA /
+ // 5*8ALPHA and won't take 2*3ALPHA "-" extlang so none of the grandfathered
+ // will be matched.
+ if (!ValidateLanguageProduction(language_str.get())) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
+ Nothing<icu::Locale>());
+ }
}
+ // 5. Let script be ? GetOption(options, "script", "string", undefined,
+ // undefined).
+ std::unique_ptr<char[]> script_str = nullptr;
+ Maybe<bool> maybe_script =
+ Intl::GetStringOption(isolate, options, "script", empty_values,
+ "ApplyOptionsToTag", &script_str);
+ MAYBE_RETURN(maybe_script, Nothing<icu::Locale>());
+ // 6. If script is not undefined, then
+ if (maybe_script.FromJust()) {
+ // a. If script does not match the script production, throw a RangeError
+ // exception.
+ if (!ValidateScriptProduction(script_str.get())) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
+ Nothing<icu::Locale>());
+ }
+ }
+ // 7. Let region be ? GetOption(options, "region", "string", undefined,
+ // undefined).
+ std::unique_ptr<char[]> region_str = nullptr;
+ Maybe<bool> maybe_region =
+ Intl::GetStringOption(isolate, options, "region", empty_values,
+ "ApplyOptionsToTag", &region_str);
+ MAYBE_RETURN(maybe_region, Nothing<icu::Locale>());
+ // 8. If region is not undefined, then
+ if (maybe_region.FromJust()) {
+ // a. If region does not match the region production, throw a RangeError
+ // exception.
+ if (!ValidateRegionProduction(region_str.get())) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
+ Nothing<icu::Locale>());
+ }
+ }
+ // 9. Set tag to CanonicalizeLanguageTag(tag).
+
+ // 10. If language is not undefined,
+ std::string locale_str;
+ if (maybe_language.FromJust()) {
+ // a. Assert: tag matches the langtag production.
+ // b. Set tag to tag with the substring corresponding to the language
+ // production replaced by the string language.
+ locale_str = language_str.get();
+ } else {
+ locale_str = icu_locale.getLanguage();
+ }
+ // 11. If script is not undefined, then
+ const char* script_ptr = nullptr;
+ if (maybe_script.FromJust()) {
+ // a. If tag does not contain a script production, then
+ // i. Set tag to the concatenation of the language production of tag, "-",
+ // script, and the rest of tag.
+ // i. Set tag to tag with the substring corresponding to the script
+ // production replaced by the string script.
+ script_ptr = script_str.get();
+ } else {
+ script_ptr = icu_locale.getScript();
+ }
+ if (script_ptr != nullptr && strlen(script_ptr) > 0) {
+ locale_str.append("-");
+ locale_str.append(script_ptr);
+ }
+ // 12. If region is not undefined, then
+ const char* region_ptr = nullptr;
+ if (maybe_region.FromJust()) {
+ // a. If tag does not contain a region production, then
+ //
+ // i. Set tag to the concatenation of the language production of tag, the
+ // substring corresponding to the "-" script production if present, "-",
+ // region, and the rest of tag.
+ //
+ // b. Else,
+ //
+ // i. Set tag to tag with the substring corresponding to the region
+ // production replaced by the string region.
+ region_ptr = region_str.get();
+ } else {
+ region_ptr = icu_locale.getCountry();
+ }
+
+ std::string without_options(icu_locale.getName());
- if (!PopulateLocaleWithUnicodeTags(isolate, icu_result, locale_holder)) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
+ // replace with values from options
+ icu_locale =
+ icu::Locale(locale_str.c_str(), region_ptr, icu_locale.getVariant());
+ locale_str = icu_locale.getName();
+
+ // Append extensions from tag
+ size_t others = without_options.find("@");
+ if (others != std::string::npos) {
+ locale_str += without_options.substr(others);
}
- // Extract language, script and region parts.
- char icu_language[ULOC_LANG_CAPACITY];
- uloc_getLanguage(icu_result, icu_language, ULOC_LANG_CAPACITY, &status);
+ // 13. Return CanonicalizeLanguageTag(tag).
+ icu_locale = icu::Locale::createCanonical(locale_str.c_str());
+ return Just(icu_locale);
+}
- char icu_script[ULOC_SCRIPT_CAPACITY];
- uloc_getScript(icu_result, icu_script, ULOC_SCRIPT_CAPACITY, &status);
+} // namespace
- char icu_region[ULOC_COUNTRY_CAPACITY];
- uloc_getCountry(icu_result, icu_region, ULOC_COUNTRY_CAPACITY, &status);
+MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate,
+ Handle<JSLocale> locale,
+ Handle<String> locale_str,
+ Handle<JSReceiver> options) {
+ Maybe<icu::Locale> maybe_locale =
+ ApplyOptionsToTag(isolate, locale_str, options);
+ MAYBE_RETURN(maybe_locale, MaybeHandle<JSLocale>());
+ icu::Locale icu_locale = maybe_locale.FromJust();
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
+ Maybe<bool> error = InsertOptionsIntoLocale(isolate, options, &icu_locale);
+ MAYBE_RETURN(error, MaybeHandle<JSLocale>());
+ if (!error.FromJust()) {
+ THROW_NEW_ERROR(isolate,
+ NewRangeError(MessageTemplate::kLocaleBadParameters),
+ JSLocale);
}
- Factory* factory = isolate->factory();
+ // 31. Set locale.[[Locale]] to r.[[locale]].
+ Handle<Managed<icu::Locale>> managed_locale =
+ Managed<icu::Locale>::FromRawPtr(isolate, 0, icu_locale.clone());
+ locale->set_icu_locale(*managed_locale);
- // NOTE: One shouldn't use temporary handles, because they can go out of
- // scope and be garbage collected before properly assigned.
- // DON'T DO THIS: locale_holder->set_language(*f->NewStringAscii...);
- Handle<String> language = factory->NewStringFromAsciiChecked(icu_language);
- locale_holder->set_language(*language);
+ return locale;
+}
- if (strlen(icu_script) != 0) {
- Handle<String> script = factory->NewStringFromAsciiChecked(icu_script);
- locale_holder->set_script(*script);
- }
+namespace {
+Handle<String> MorphLocale(Isolate* isolate, String locale,
+ void (*morph_func)(icu::Locale*, UErrorCode*)) {
+ UErrorCode status = U_ZERO_ERROR;
+ icu::Locale icu_locale =
+ icu::Locale::forLanguageTag(locale.ToCString().get(), status);
+ CHECK(U_SUCCESS(status));
+ CHECK(!icu_locale.isBogus());
+ (*morph_func)(&icu_locale, &status);
+ CHECK(U_SUCCESS(status));
+ CHECK(!icu_locale.isBogus());
+ std::string locale_str = Intl::ToLanguageTag(icu_locale).FromJust();
+ return isolate->factory()->NewStringFromAsciiChecked(locale_str.c_str());
+}
- if (strlen(icu_region) != 0) {
- Handle<String> region = factory->NewStringFromAsciiChecked(icu_region);
- locale_holder->set_region(*region);
- }
+} // namespace
- char icu_base_name[ULOC_FULLNAME_CAPACITY];
- uloc_getBaseName(icu_result, icu_base_name, ULOC_FULLNAME_CAPACITY, &status);
- // We need to convert it back to BCP47.
- char bcp47_result[ULOC_FULLNAME_CAPACITY];
- uloc_toLanguageTag(icu_base_name, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
- &status);
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
- }
- Handle<String> base_name = factory->NewStringFromAsciiChecked(bcp47_result);
- locale_holder->set_base_name(*base_name);
+Handle<String> JSLocale::Maximize(Isolate* isolate, String locale) {
+ return MorphLocale(isolate, locale,
+ [](icu::Locale* icu_locale, UErrorCode* status) {
+ icu_locale->addLikelySubtags(*status);
+ });
+}
- // Produce final representation of the locale string, for toString().
- uloc_toLanguageTag(icu_result, bcp47_result, ULOC_FULLNAME_CAPACITY, true,
- &status);
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
- THROW_NEW_ERROR(
- isolate,
- NewRangeError(MessageTemplate::kLocaleBadParameters,
- isolate->factory()->NewStringFromAsciiChecked(kMethod),
- locale_holder),
- JSLocale);
- }
- Handle<String> locale_handle =
- factory->NewStringFromAsciiChecked(bcp47_result);
- locale_holder->set_locale(*locale_handle);
+Handle<String> JSLocale::Minimize(Isolate* isolate, String locale) {
+ return MorphLocale(isolate, locale,
+ [](icu::Locale* icu_locale, UErrorCode* status) {
+ icu_locale->minimizeSubtags(*status);
+ });
+}
- return locale_holder;
+Handle<Object> JSLocale::Language(Isolate* isolate, Handle<JSLocale> locale) {
+ Factory* factory = isolate->factory();
+ const char* language = locale->icu_locale()->raw()->getLanguage();
+ if (strlen(language) == 0) return factory->undefined_value();
+ return factory->NewStringFromAsciiChecked(language);
}
-namespace {
+Handle<Object> JSLocale::Script(Isolate* isolate, Handle<JSLocale> locale) {
+ Factory* factory = isolate->factory();
+ const char* script = locale->icu_locale()->raw()->getScript();
+ if (strlen(script) == 0) return factory->undefined_value();
+ return factory->NewStringFromAsciiChecked(script);
+}
-Handle<String> MorphLocale(Isolate* isolate, String* language_tag,
- int32_t (*morph_func)(const char*, char*, int32_t,
- UErrorCode*)) {
+Handle<Object> JSLocale::Region(Isolate* isolate, Handle<JSLocale> locale) {
Factory* factory = isolate->factory();
- char localeBuffer[ULOC_FULLNAME_CAPACITY];
- char morphBuffer[ULOC_FULLNAME_CAPACITY];
+ const char* region = locale->icu_locale()->raw()->getCountry();
+ if (strlen(region) == 0) return factory->undefined_value();
+ return factory->NewStringFromAsciiChecked(region);
+}
- UErrorCode status = U_ZERO_ERROR;
- // Convert from language id to locale.
- int32_t parsed_length;
- int32_t length =
- uloc_forLanguageTag(language_tag->ToCString().get(), localeBuffer,
- ULOC_FULLNAME_CAPACITY, &parsed_length, &status);
- CHECK(parsed_length == language_tag->length());
- DCHECK(U_SUCCESS(status));
- DCHECK_GT(length, 0);
- DCHECK_NOT_NULL(morph_func);
- // Add the likely subtags or Minimize the subtags on the locale id
- length =
- (*morph_func)(localeBuffer, morphBuffer, ULOC_FULLNAME_CAPACITY, &status);
- DCHECK(U_SUCCESS(status));
- DCHECK_GT(length, 0);
- // Returns a well-formed language tag
- length = uloc_toLanguageTag(morphBuffer, localeBuffer, ULOC_FULLNAME_CAPACITY,
- false, &status);
- DCHECK(U_SUCCESS(status));
- DCHECK_GT(length, 0);
- std::string lang(localeBuffer, length);
- std::replace(lang.begin(), lang.end(), '_', '-');
-
- return factory->NewStringFromAsciiChecked(lang.c_str());
+Handle<String> JSLocale::BaseName(Isolate* isolate, Handle<JSLocale> locale) {
+ icu::Locale icu_locale =
+ icu::Locale::createFromName(locale->icu_locale()->raw()->getBaseName());
+ std::string base_name = Intl::ToLanguageTag(icu_locale).FromJust();
+ return isolate->factory()->NewStringFromAsciiChecked(base_name.c_str());
}
-} // namespace
+Handle<Object> JSLocale::Calendar(Isolate* isolate, Handle<JSLocale> locale) {
+ return UnicodeKeywordValue(isolate, locale, "ca");
+}
-Handle<String> JSLocale::Maximize(Isolate* isolate, String* locale) {
- return MorphLocale(isolate, locale, uloc_addLikelySubtags);
+Handle<Object> JSLocale::CaseFirst(Isolate* isolate, Handle<JSLocale> locale) {
+ return UnicodeKeywordValue(isolate, locale, "kf");
}
-Handle<String> JSLocale::Minimize(Isolate* isolate, String* locale) {
- return MorphLocale(isolate, locale, uloc_minimizeSubtags);
+Handle<Object> JSLocale::Collation(Isolate* isolate, Handle<JSLocale> locale) {
+ return UnicodeKeywordValue(isolate, locale, "co");
}
-Handle<String> JSLocale::CaseFirstAsString() const {
- switch (case_first()) {
- case CaseFirst::UPPER:
- return GetReadOnlyRoots().upper_string_handle();
- case CaseFirst::LOWER:
- return GetReadOnlyRoots().lower_string_handle();
- case CaseFirst::FALSE_VALUE:
- return GetReadOnlyRoots().false_string_handle();
- case CaseFirst::COUNT:
- UNREACHABLE();
- }
+Handle<Object> JSLocale::HourCycle(Isolate* isolate, Handle<JSLocale> locale) {
+ return UnicodeKeywordValue(isolate, locale, "hc");
}
-Handle<String> JSLocale::HourCycleAsString() const {
- switch (hour_cycle()) {
- case HourCycle::H11:
- return GetReadOnlyRoots().h11_string_handle();
- case HourCycle::H12:
- return GetReadOnlyRoots().h12_string_handle();
- case HourCycle::H23:
- return GetReadOnlyRoots().h23_string_handle();
- case HourCycle::H24:
- return GetReadOnlyRoots().h24_string_handle();
- case HourCycle::COUNT:
- UNREACHABLE();
- }
+Handle<Object> JSLocale::Numeric(Isolate* isolate, Handle<JSLocale> locale) {
+ Factory* factory = isolate->factory();
+ icu::Locale* icu_locale = locale->icu_locale()->raw();
+ UErrorCode status = U_ZERO_ERROR;
+ std::string numeric =
+ icu_locale->getUnicodeKeywordValue<std::string>("kn", status);
+ return (numeric == "true") ? factory->true_value() : factory->false_value();
}
-Handle<String> JSLocale::NumericAsString() const {
- switch (numeric()) {
- case Numeric::NOTSET:
- return GetReadOnlyRoots().undefined_string_handle();
- case Numeric::TRUE_VALUE:
- return GetReadOnlyRoots().true_string_handle();
- case Numeric::FALSE_VALUE:
- return GetReadOnlyRoots().false_string_handle();
- case Numeric::COUNT:
- UNREACHABLE();
- }
+Handle<Object> JSLocale::NumberingSystem(Isolate* isolate,
+ Handle<JSLocale> locale) {
+ return UnicodeKeywordValue(isolate, locale, "nu");
+}
+
+std::string JSLocale::ToString(Handle<JSLocale> locale) {
+ icu::Locale* icu_locale = locale->icu_locale()->raw();
+ return Intl::ToLanguageTag(*icu_locale).FromJust();
+}
+
+Handle<String> JSLocale::ToString(Isolate* isolate, Handle<JSLocale> locale) {
+ std::string locale_str = JSLocale::ToString(locale);
+ return isolate->factory()->NewStringFromAsciiChecked(locale_str.c_str());
}
} // namespace internal