LCOV - code coverage report
Current view: top level - src/objects - js-locale.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 169 192 88.0 %
Date: 2019-03-21 Functions: 32 34 94.1 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_INTL_SUPPORT
       6             : #error Internationalization is expected to be enabled.
       7             : #endif  // V8_INTL_SUPPORT
       8             : 
       9             : #include "src/objects/js-locale.h"
      10             : 
      11             : #include <map>
      12             : #include <memory>
      13             : #include <string>
      14             : #include <vector>
      15             : 
      16             : #include "src/api.h"
      17             : #include "src/global-handles.h"
      18             : #include "src/heap/factory.h"
      19             : #include "src/isolate.h"
      20             : #include "src/objects-inl.h"
      21             : #include "src/objects/intl-objects.h"
      22             : #include "src/objects/js-locale-inl.h"
      23             : #include "unicode/char16ptr.h"
      24             : #include "unicode/locid.h"
      25             : #include "unicode/uloc.h"
      26             : #include "unicode/unistr.h"
      27             : 
      28             : namespace v8 {
      29             : namespace internal {
      30             : 
      31             : namespace {
      32             : 
      33             : // Helper function to check a locale is valid. It will return false if
      34             : // the length of the extension fields are incorrect. For example, en-u-a or
      35             : // en-u-co-b will return false.
      36       52821 : bool IsValidLocale(const icu::Locale& locale) {
      37             :   // icu::Locale::toLanguageTag won't return U_STRING_NOT_TERMINATED_WARNING for
      38             :   // incorrect locale yet. So we still need the following uloc_toLanguageTag
      39             :   // TODO(ftang): Change to use icu::Locale::toLanguageTag once it indicate
      40             :   // error.
      41             :   char result[ULOC_FULLNAME_CAPACITY];
      42       52821 :   UErrorCode status = U_ZERO_ERROR;
      43             :   uloc_toLanguageTag(locale.getName(), result, ULOC_FULLNAME_CAPACITY, true,
      44       52821 :                      &status);
      45       52821 :   return U_SUCCESS(status) && status != U_STRING_NOT_TERMINATED_WARNING;
      46             : }
      47             : 
      48             : struct OptionData {
      49             :   const char* name;
      50             :   const char* key;
      51             :   const std::vector<const char*>* possible_values;
      52             :   bool is_bool_value;
      53             : };
      54             : 
      55             : // Inserts tags from options into locale string.
      56       52884 : Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
      57             :                                     Handle<JSReceiver> options,
      58             :                                     icu::Locale* icu_locale) {
      59       52884 :   CHECK(isolate);
      60       52884 :   CHECK(!icu_locale->isBogus());
      61             : 
      62             :   const std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23",
      63             :                                                       "h24"};
      64             :   const std::vector<const char*> case_first_values = {"upper", "lower",
      65             :                                                       "false"};
      66             :   const std::vector<const char*> empty_values = {};
      67             :   const std::array<OptionData, 6> kOptionToUnicodeTagMap = {
      68             :       {{"calendar", "ca", &empty_values, false},
      69             :        {"collation", "co", &empty_values, false},
      70             :        {"hourCycle", "hc", &hour_cycle_values, false},
      71             :        {"caseFirst", "kf", &case_first_values, false},
      72             :        {"numeric", "kn", &empty_values, true},
      73       52884 :        {"numberingSystem", "nu", &empty_values, false}}};
      74             : 
      75             :   // TODO(cira): Pass in values as per the spec to make this to be
      76             :   // spec compliant.
      77             : 
      78       52884 :   UErrorCode status = U_ZERO_ERROR;
      79      687096 :   for (const auto& option_to_bcp47 : kOptionToUnicodeTagMap) {
      80             :     std::unique_ptr<char[]> value_str = nullptr;
      81      317169 :     bool value_bool = false;
      82             :     Maybe<bool> maybe_found =
      83      317169 :         option_to_bcp47.is_bool_value
      84       52848 :             ? Intl::GetBoolOption(isolate, options, option_to_bcp47.name,
      85             :                                   "locale", &value_bool)
      86      264321 :             : Intl::GetStringOption(isolate, options, option_to_bcp47.name,
      87      264321 :                                     *(option_to_bcp47.possible_values),
      88     1162980 :                                     "locale", &value_str);
      89      317169 :     MAYBE_RETURN(maybe_found, Nothing<bool>());
      90             : 
      91             :     // TODO(cira): Use fallback value if value is not found to make
      92             :     // this spec compliant.
      93      317115 :     if (!maybe_found.FromJust()) continue;
      94             : 
      95         162 :     if (option_to_bcp47.is_bool_value) {
      96          81 :       value_str = value_bool ? isolate->factory()->true_string()->ToCString()
      97             :                              : isolate->factory()->false_string()->ToCString();
      98             :     }
      99             :     DCHECK_NOT_NULL(value_str.get());
     100             : 
     101             :     // Convert bcp47 key and value into legacy ICU format so we can use
     102             :     // uloc_setKeywordValue.
     103         162 :     const char* key = uloc_toLegacyKey(option_to_bcp47.key);
     104             :     DCHECK_NOT_NULL(key);
     105             : 
     106             :     // Overwrite existing, or insert new key-value to the locale string.
     107         162 :     const char* value = uloc_toLegacyType(key, value_str.get());
     108         162 :     if (value) {
     109         162 :       icu_locale->setKeywordValue(key, value, status);
     110         162 :       if (U_FAILURE(status)) {
     111             :         return Just(false);
     112             :       }
     113             :     } else {
     114             :       return Just(false);
     115             :     }
     116             :   }
     117             : 
     118             :   // Check all the unicode extension fields are in the right length.
     119       52821 :   if (!IsValidLocale(*icu_locale)) {
     120           0 :     THROW_NEW_ERROR_RETURN_VALUE(
     121             :         isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
     122             :         Nothing<bool>());
     123             :   }
     124             : 
     125             :   return Just(true);
     126             : }
     127             : 
     128          90 : Handle<Object> UnicodeKeywordValue(Isolate* isolate, Handle<JSLocale> locale,
     129             :                                    const char* key) {
     130             :   icu::Locale* icu_locale = locale->icu_locale()->raw();
     131          90 :   UErrorCode status = U_ZERO_ERROR;
     132             :   std::string value =
     133          90 :       icu_locale->getUnicodeKeywordValue<std::string>(key, status);
     134         135 :   if (status == U_ILLEGAL_ARGUMENT_ERROR || value == "") {
     135          45 :     return isolate->factory()->undefined_value();
     136             :   }
     137          45 :   if (value == "yes") {
     138             :     value = "true";
     139             :   }
     140          45 :   return isolate->factory()->NewStringFromAsciiChecked(value.c_str());
     141             : }
     142             : 
     143             : bool InRange(size_t value, size_t start, size_t end) {
     144      172521 :   return (start <= value) && (value <= end);
     145             : }
     146             : 
     147             : bool InRange(char value, char start, char end) {
     148      394362 :   return (start <= value) && (value <= end);
     149             : }
     150             : 
     151             : bool IsCheckRange(const std::string& str, size_t min, size_t max,
     152             :                   bool(range_check_func)(char)) {
     153      172521 :   if (!InRange(str.length(), min, max)) return false;
     154      703368 :   for (size_t i = 0; i < str.length(); i++) {
     155      293310 :     if (!range_check_func(str[i])) return false;
     156             :   }
     157             :   return true;
     158             : }
     159      131661 : bool IsAlpha(const std::string& str, size_t min, size_t max) {
     160      291042 :   return IsCheckRange(str, min, max, [](char c) -> bool {
     161      392094 :     return InRange(c, 'a', 'z') || InRange(c, 'A', 'Z');
     162      422703 :   });
     163             : }
     164             : 
     165         621 : bool IsDigit(const std::string& str, size_t min, size_t max) {
     166             :   return IsCheckRange(str, min, max,
     167        4077 :                       [](char c) -> bool { return InRange(c, '0', '9'); });
     168             : }
     169             : 
     170       40239 : bool IsAlphanum(const std::string& str, size_t min, size_t max) {
     171         540 :   return IsCheckRange(str, min, max, [](char c) -> bool {
     172         540 :     return InRange(c, 'a', 'z') || InRange(c, 'A', 'Z') || InRange(c, '0', '9');
     173       40779 :   });
     174             : }
     175             : 
     176       52920 : bool IsUnicodeLanguageSubtag(const std::string& value) {
     177             :   // unicode_language_subtag = alpha{2,3} | alpha{5,8};
     178       52920 :   return IsAlpha(value, 2, 3) || IsAlpha(value, 5, 8);
     179             : }
     180             : 
     181             : bool IsUnicodeScriptSubtag(const std::string& value) {
     182             :   // unicode_script_subtag = alpha{4} ;
     183       39699 :   return IsAlpha(value, 4, 4);
     184             : }
     185             : 
     186       39033 : bool IsUnicodeRegionSubtag(const std::string& value) {
     187             :   // unicode_region_subtag = (alpha{2} | digit{3});
     188       39033 :   return IsAlpha(value, 2, 2) || IsDigit(value, 3, 3);
     189             : }
     190             : 
     191           0 : bool IsDigitAlphanum3(const std::string& value) {
     192           0 :   return value.length() == 4 && InRange(value[0], '0', '9') &&
     193           0 :          IsAlphanum(value.substr(1), 3, 3);
     194             : }
     195             : 
     196           0 : bool IsUnicodeVariantSubtag(const std::string& value) {
     197             :   // unicode_variant_subtag = (alphanum{5,8} | digit alphanum{3}) ;
     198           0 :   return IsAlphanum(value, 5, 8) || IsDigitAlphanum3(value);
     199             : }
     200             : 
     201             : bool IsExtensionSingleton(const std::string& value) {
     202       40239 :   return IsAlphanum(value, 1, 1);
     203             : }
     204             : 
     205             : // TODO(ftang) Replace the following check w/ icu::LocaleBuilder
     206             : // once ICU64 land in March 2019.
     207       52920 : bool StartsWithUnicodeLanguageId(const std::string& value) {
     208             :   // unicode_language_id =
     209             :   // unicode_language_subtag (sep unicode_script_subtag)?
     210             :   //   (sep unicode_region_subtag)? (sep unicode_variant_subtag)* ;
     211       52920 :   std::vector<std::string> tokens;
     212             :   std::string token;
     213      105840 :   std::istringstream token_stream(value);
     214      459783 :   while (std::getline(token_stream, token, '-')) {
     215      117981 :     tokens.push_back(token);
     216             :   }
     217       52920 :   if (tokens.size() == 0) return false;
     218             : 
     219             :   // length >= 1
     220       52920 :   if (!IsUnicodeLanguageSubtag(tokens[0])) return false;
     221             : 
     222       52911 :   if (tokens.size() == 1) return true;
     223             : 
     224             :   // length >= 2
     225       39789 :   if (IsExtensionSingleton(tokens[1])) return true;
     226             : 
     227             :   size_t index = 1;
     228       39699 :   if (IsUnicodeScriptSubtag(tokens[index])) {
     229             :     index++;
     230       24309 :     if (index == tokens.size()) return true;
     231             :   }
     232       39033 :   if (IsUnicodeRegionSubtag(tokens[index])) {
     233       38988 :     index++;
     234             :   }
     235       39033 :   while (index < tokens.size()) {
     236         450 :     if (IsExtensionSingleton(tokens[index])) return true;
     237           0 :     if (!IsUnicodeVariantSubtag(tokens[index])) return false;
     238           0 :     index++;
     239             :   }
     240             :   return true;
     241             : }
     242             : 
     243       52929 : Maybe<std::string> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag,
     244             :                                      Handle<JSReceiver> options) {
     245             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     246       52929 :   if (tag->length() == 0) {
     247          18 :     THROW_NEW_ERROR_RETURN_VALUE(
     248             :         isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty),
     249             :         Nothing<std::string>());
     250             :   }
     251             : 
     252      105840 :   v8::String::Utf8Value bcp47_tag(v8_isolate, v8::Utils::ToLocal(tag));
     253       52920 :   CHECK_LT(0, bcp47_tag.length());
     254       52920 :   CHECK_NOT_NULL(*bcp47_tag);
     255             :   // 2. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError
     256             :   // exception.
     257      105840 :   if (!StartsWithUnicodeLanguageId(*bcp47_tag)) {
     258          18 :     THROW_NEW_ERROR_RETURN_VALUE(
     259             :         isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
     260             :         Nothing<std::string>());
     261             :   }
     262       52911 :   UErrorCode status = U_ZERO_ERROR;
     263             :   icu::Locale icu_locale =
     264      105822 :       icu::Locale::forLanguageTag({*bcp47_tag, bcp47_tag.length()}, status);
     265       52911 :   if (U_FAILURE(status)) {
     266           0 :     THROW_NEW_ERROR_RETURN_VALUE(
     267             :         isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
     268             :         Nothing<std::string>());
     269             :   }
     270             : 
     271             :   // 3. Let language be ? GetOption(options, "language", "string", undefined,
     272             :   // undefined).
     273             :   const std::vector<const char*> empty_values = {};
     274             :   std::unique_ptr<char[]> language_str = nullptr;
     275             :   Maybe<bool> maybe_language =
     276             :       Intl::GetStringOption(isolate, options, "language", empty_values,
     277      105822 :                             "ApplyOptionsToTag", &language_str);
     278       52911 :   MAYBE_RETURN(maybe_language, Nothing<std::string>());
     279             :   // 4. If language is not undefined, then
     280       52902 :   if (maybe_language.FromJust()) {
     281             :     // a. If language does not match the unicode_language_subtag production,
     282             :     //    throw a RangeError exception.
     283           0 :     if (!IsUnicodeLanguageSubtag(language_str.get())) {
     284           0 :       THROW_NEW_ERROR_RETURN_VALUE(
     285             :           isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
     286             :           Nothing<std::string>());
     287             :     }
     288             :   }
     289             :   // 5. Let script be ? GetOption(options, "script", "string", undefined,
     290             :   // undefined).
     291             :   std::unique_ptr<char[]> script_str = nullptr;
     292             :   Maybe<bool> maybe_script =
     293             :       Intl::GetStringOption(isolate, options, "script", empty_values,
     294      105804 :                             "ApplyOptionsToTag", &script_str);
     295       52902 :   MAYBE_RETURN(maybe_script, Nothing<std::string>());
     296             :   // 6. If script is not undefined, then
     297       52893 :   if (maybe_script.FromJust()) {
     298             :     // a. If script does not match the unicode_script_subtag production, throw
     299             :     //    a RangeError exception.
     300           0 :     if (!IsUnicodeScriptSubtag(script_str.get())) {
     301           0 :       THROW_NEW_ERROR_RETURN_VALUE(
     302             :           isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
     303             :           Nothing<std::string>());
     304             :     }
     305             :   }
     306             :   // 7. Let region be ? GetOption(options, "region", "string", undefined,
     307             :   // undefined).
     308             :   std::unique_ptr<char[]> region_str = nullptr;
     309             :   Maybe<bool> maybe_region =
     310             :       Intl::GetStringOption(isolate, options, "region", empty_values,
     311      105786 :                             "ApplyOptionsToTag", &region_str);
     312       52893 :   MAYBE_RETURN(maybe_region, Nothing<std::string>());
     313             :   // 8. If region is not undefined, then
     314       52884 :   if (maybe_region.FromJust()) {
     315             :     // a. If region does not match the region production, throw a RangeError
     316             :     // exception.
     317           0 :     if (!IsUnicodeRegionSubtag(region_str.get())) {
     318           0 :       THROW_NEW_ERROR_RETURN_VALUE(
     319             :           isolate, NewRangeError(MessageTemplate::kLocaleBadParameters),
     320             :           Nothing<std::string>());
     321             :     }
     322             :   }
     323             :   // 9. Set tag to CanonicalizeLanguageTag(tag).
     324             :   Maybe<std::string> maybe_canonicalized =
     325       52884 :       Intl::CanonicalizeLanguageTag(isolate, tag);
     326       52884 :   MAYBE_RETURN(maybe_canonicalized, Nothing<std::string>());
     327             : 
     328       52884 :   std::vector<std::string> tokens;
     329             :   std::string token;
     330      158652 :   std::istringstream token_stream(maybe_canonicalized.FromJust());
     331      459522 :   while (std::getline(token_stream, token, '-')) {
     332      117918 :     tokens.push_back(token);
     333             :   }
     334             : 
     335             :   // 10.  If language is not undefined,
     336             :   std::string locale_str;
     337       52884 :   if (maybe_language.FromJust()) {
     338             :     // a. Assert: tag matches the unicode_locale_id production.
     339             :     // b. Set tag to tag with the substring corresponding to the
     340             :     //    unicode_language_subtag production replaced by the string language.
     341             :     tokens[0] = language_str.get();
     342             :   }
     343             : 
     344             :   // 11. If script is not undefined, then
     345       52884 :   if (maybe_script.FromJust()) {
     346             :     // a. If tag does not contain a unicode_script_subtag production, then
     347           0 :     if (tokens.size() < 2 || !IsUnicodeScriptSubtag(tokens[1])) {
     348             :       // i. Set tag to the concatenation of the unicode_language_subtag
     349             :       //    production of tag, "-", script, and the rest of tag.
     350           0 :       tokens.insert(tokens.begin() + 1, script_str.get());
     351             :       // b. Else,
     352             :     } else {
     353             :       // i. Set tag to tag with the substring corresponding to the
     354             :       //    unicode_script_subtag production replaced by the string script.
     355             :       tokens[1] = script_str.get();
     356             :     }
     357             :   }
     358             :   // 12. If region is not undefined, then
     359       52884 :   if (maybe_region.FromJust()) {
     360             :     // a. If tag does not contain a unicode_region_subtag production, then
     361             :     //   i. Set tag to the concatenation of the unicode_language_subtag
     362             :     //      production of tag, the substring corresponding to the  "-"
     363             :     //      unicode_script_subtag production if present, "-", region, and
     364             :     //      the rest of tag.
     365             :     // b. Else,
     366             :     // i. Set tag to tag with the substring corresponding to the
     367             :     //    unicode_region_subtag production replaced by the string region.
     368           0 :     if (tokens.size() > 1 && IsUnicodeRegionSubtag(tokens[1])) {
     369             :       tokens[1] = region_str.get();
     370           0 :     } else if (tokens.size() > 1 && IsUnicodeScriptSubtag(tokens[1])) {
     371           0 :       if (tokens.size() > 2 && IsUnicodeRegionSubtag(tokens[2])) {
     372             :         tokens[2] = region_str.get();
     373             :       } else {
     374           0 :         tokens.insert(tokens.begin() + 2, region_str.get());
     375             :       }
     376             :     } else {
     377           0 :       tokens.insert(tokens.begin() + 1, region_str.get());
     378             :     }
     379             :   }
     380             : 
     381             :   std::string replaced;
     382      170802 :   for (auto it = tokens.begin(); it != tokens.end(); it++) {
     383             :     replaced += *it;
     384      117918 :     if (it + 1 != tokens.end()) {
     385             :       replaced += '-';
     386             :     }
     387             :   }
     388             : 
     389             :   // 13.  Return CanonicalizeLanguageTag(tag).
     390       52884 :   return Intl::CanonicalizeLanguageTag(isolate, replaced);
     391             : }
     392             : 
     393             : }  // namespace
     394             : 
     395       52929 : MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate,
     396             :                                            Handle<JSLocale> locale,
     397             :                                            Handle<String> locale_str,
     398             :                                            Handle<JSReceiver> options) {
     399             :   Maybe<std::string> maybe_locale =
     400       52929 :       ApplyOptionsToTag(isolate, locale_str, options);
     401       52929 :   MAYBE_RETURN(maybe_locale, MaybeHandle<JSLocale>());
     402       52884 :   UErrorCode status = U_ZERO_ERROR;
     403             :   icu::Locale icu_locale =
     404      158652 :       icu::Locale::forLanguageTag(maybe_locale.FromJust().c_str(), status);
     405       52884 :   if (U_FAILURE(status)) {
     406           0 :     THROW_NEW_ERROR(isolate,
     407             :                     NewRangeError(MessageTemplate::kLocaleBadParameters),
     408             :                     JSLocale);
     409             :   }
     410             : 
     411       52884 :   Maybe<bool> error = InsertOptionsIntoLocale(isolate, options, &icu_locale);
     412       52884 :   MAYBE_RETURN(error, MaybeHandle<JSLocale>());
     413       52830 :   if (!error.FromJust()) {
     414          18 :     THROW_NEW_ERROR(isolate,
     415             :                     NewRangeError(MessageTemplate::kLocaleBadParameters),
     416             :                     JSLocale);
     417             :   }
     418             : 
     419             :   // 31. Set locale.[[Locale]] to r.[[locale]].
     420             :   Handle<Managed<icu::Locale>> managed_locale =
     421       52821 :       Managed<icu::Locale>::FromRawPtr(isolate, 0, icu_locale.clone());
     422       52821 :   locale->set_icu_locale(*managed_locale);
     423             : 
     424       52821 :   return locale;
     425             : }
     426             : 
     427             : namespace {
     428       45837 : Handle<String> MorphLocale(Isolate* isolate, String locale,
     429             :                            void (*morph_func)(icu::Locale*, UErrorCode*)) {
     430       45837 :   UErrorCode status = U_ZERO_ERROR;
     431             :   icu::Locale icu_locale =
     432      183348 :       icu::Locale::forLanguageTag(locale.ToCString().get(), status);
     433             :   // TODO(ftang): Remove the following lines after ICU-8420 fixed.
     434             :   // Due to ICU-8420 "und" is turn into "" by forLanguageTag,
     435             :   // we have to work around to use icu::Locale("und") directly
     436       45837 :   if (icu_locale.getName()[0] == '\0') icu_locale = icu::Locale("und");
     437       45837 :   CHECK(U_SUCCESS(status));
     438       45837 :   CHECK(!icu_locale.isBogus());
     439       45837 :   (*morph_func)(&icu_locale, &status);
     440       45837 :   CHECK(U_SUCCESS(status));
     441       45837 :   CHECK(!icu_locale.isBogus());
     442       91674 :   std::string locale_str = Intl::ToLanguageTag(icu_locale).FromJust();
     443       91674 :   return isolate->factory()->NewStringFromAsciiChecked(locale_str.c_str());
     444             : }
     445             : 
     446             : }  // namespace
     447             : 
     448       22905 : Handle<String> JSLocale::Maximize(Isolate* isolate, String locale) {
     449             :   return MorphLocale(isolate, locale,
     450       22905 :                      [](icu::Locale* icu_locale, UErrorCode* status) {
     451       22905 :                        icu_locale->addLikelySubtags(*status);
     452       45810 :                      });
     453             : }
     454             : 
     455       22932 : Handle<String> JSLocale::Minimize(Isolate* isolate, String locale) {
     456             :   return MorphLocale(isolate, locale,
     457       22932 :                      [](icu::Locale* icu_locale, UErrorCode* status) {
     458       22932 :                        icu_locale->minimizeSubtags(*status);
     459       45864 :                      });
     460             : }
     461             : 
     462          18 : Handle<Object> JSLocale::Language(Isolate* isolate, Handle<JSLocale> locale) {
     463             :   Factory* factory = isolate->factory();
     464          36 :   const char* language = locale->icu_locale()->raw()->getLanguage();
     465          18 :   if (strlen(language) == 0) return factory->undefined_value();
     466          18 :   return factory->NewStringFromAsciiChecked(language);
     467             : }
     468             : 
     469          27 : Handle<Object> JSLocale::Script(Isolate* isolate, Handle<JSLocale> locale) {
     470             :   Factory* factory = isolate->factory();
     471          54 :   const char* script = locale->icu_locale()->raw()->getScript();
     472          45 :   if (strlen(script) == 0) return factory->undefined_value();
     473           9 :   return factory->NewStringFromAsciiChecked(script);
     474             : }
     475             : 
     476          18 : Handle<Object> JSLocale::Region(Isolate* isolate, Handle<JSLocale> locale) {
     477             :   Factory* factory = isolate->factory();
     478          36 :   const char* region = locale->icu_locale()->raw()->getCountry();
     479          27 :   if (strlen(region) == 0) return factory->undefined_value();
     480           9 :   return factory->NewStringFromAsciiChecked(region);
     481             : }
     482             : 
     483          18 : Handle<String> JSLocale::BaseName(Isolate* isolate, Handle<JSLocale> locale) {
     484             :   icu::Locale icu_locale =
     485          36 :       icu::Locale::createFromName(locale->icu_locale()->raw()->getBaseName());
     486          36 :   std::string base_name = Intl::ToLanguageTag(icu_locale).FromJust();
     487          36 :   return isolate->factory()->NewStringFromAsciiChecked(base_name.c_str());
     488             : }
     489             : 
     490          18 : Handle<Object> JSLocale::Calendar(Isolate* isolate, Handle<JSLocale> locale) {
     491          18 :   return UnicodeKeywordValue(isolate, locale, "ca");
     492             : }
     493             : 
     494          18 : Handle<Object> JSLocale::CaseFirst(Isolate* isolate, Handle<JSLocale> locale) {
     495          18 :   return UnicodeKeywordValue(isolate, locale, "kf");
     496             : }
     497             : 
     498          18 : Handle<Object> JSLocale::Collation(Isolate* isolate, Handle<JSLocale> locale) {
     499          18 :   return UnicodeKeywordValue(isolate, locale, "co");
     500             : }
     501             : 
     502          18 : Handle<Object> JSLocale::HourCycle(Isolate* isolate, Handle<JSLocale> locale) {
     503          18 :   return UnicodeKeywordValue(isolate, locale, "hc");
     504             : }
     505             : 
     506          18 : Handle<Object> JSLocale::Numeric(Isolate* isolate, Handle<JSLocale> locale) {
     507             :   Factory* factory = isolate->factory();
     508             :   icu::Locale* icu_locale = locale->icu_locale()->raw();
     509          18 :   UErrorCode status = U_ZERO_ERROR;
     510             :   std::string numeric =
     511          18 :       icu_locale->getUnicodeKeywordValue<std::string>("kn", status);
     512          54 :   return (numeric == "true") ? factory->true_value() : factory->false_value();
     513             : }
     514             : 
     515          18 : Handle<Object> JSLocale::NumberingSystem(Isolate* isolate,
     516             :                                          Handle<JSLocale> locale) {
     517          18 :   return UnicodeKeywordValue(isolate, locale, "nu");
     518             : }
     519             : 
     520      119961 : std::string JSLocale::ToString(Handle<JSLocale> locale) {
     521             :   icu::Locale* icu_locale = locale->icu_locale()->raw();
     522      239922 :   return Intl::ToLanguageTag(*icu_locale).FromJust();
     523             : }
     524             : 
     525      119889 : Handle<String> JSLocale::ToString(Isolate* isolate, Handle<JSLocale> locale) {
     526      119889 :   std::string locale_str = JSLocale::ToString(locale);
     527      239778 :   return isolate->factory()->NewStringFromAsciiChecked(locale_str.c_str());
     528             : }
     529             : 
     530             : }  // namespace internal
     531      120216 : }  // namespace v8

Generated by: LCOV version 1.10