5 #ifndef V8_INTL_SUPPORT 6 #error Internationalization is expected to be enabled. 7 #endif // V8_INTL_SUPPORT 9 #include "src/objects/intl-objects.h" 16 #include "src/api-inl.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/js-collator-inl.h" 22 #include "src/objects/js-date-time-format-inl.h" 23 #include "src/objects/js-number-format-inl.h" 24 #include "src/objects/string.h" 25 #include "src/property-descriptor.h" 26 #include "src/string-case.h" 27 #include "unicode/basictz.h" 28 #include "unicode/brkiter.h" 29 #include "unicode/coll.h" 30 #include "unicode/decimfmt.h" 31 #include "unicode/locid.h" 32 #include "unicode/normalizer2.h" 33 #include "unicode/numfmt.h" 34 #include "unicode/numsys.h" 35 #include "unicode/timezone.h" 36 #include "unicode/ustring.h" 37 #include "unicode/uvernum.h" 39 #define XSTR(s) STR(s) 42 V8_MINIMUM_ICU_VERSION <= U_ICU_VERSION_MAJOR_NUM,
43 "v8 is required to build with ICU " XSTR(V8_MINIMUM_ICU_VERSION)
" and up");
51 inline bool IsASCIIUpper(uint16_t ch) {
return ch >=
'A' && ch <=
'Z'; }
53 const uint8_t kToLower[256] = {
54 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
55 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
56 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
57 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
58 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
59 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
60 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73,
61 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
62 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
63 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
64 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
65 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
66 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B,
67 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
68 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
69 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
70 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
71 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xD7,
72 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3,
73 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
74 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB,
75 0xFC, 0xFD, 0xFE, 0xFF,
78 inline uint16_t ToLatin1Lower(uint16_t ch) {
79 return static_cast<uint16_t
>(kToLower[ch]);
82 inline uint16_t ToASCIIUpper(uint16_t ch) {
83 return ch & ~((ch >=
'a' && ch <=
'z') << 5);
87 inline uint16_t ToLatin1Upper(uint16_t ch) {
88 DCHECK(ch != 0xDF && ch != 0xB5 && ch != 0xFF);
90 ~(((ch >=
'a' && ch <=
'z') || (((ch & 0xE0) == 0xE0) && ch != 0xF7))
94 template <
typename Char>
95 bool ToUpperFastASCII(
const Vector<const Char>& src,
96 Handle<SeqOneByteString> result) {
100 for (
auto it = src.begin(); it != src.end(); ++it) {
101 uint16_t ch =
static_cast<uint16_t
>(*it);
103 result->SeqOneByteStringSet(index++, ToASCIIUpper(ch));
105 return !(ored & ~0x7F);
108 const uint16_t sharp_s = 0xDF;
110 template <
typename Char>
111 bool ToUpperOneByte(
const Vector<const Char>& src, uint8_t* dest,
112 int* sharp_s_count) {
119 for (
auto it = src.begin(); it != src.end(); ++it) {
120 uint16_t ch =
static_cast<uint16_t
>(*it);
121 if (V8_UNLIKELY(ch == sharp_s)) {
125 if (V8_UNLIKELY(ch == 0xB5 || ch == 0xFF)) {
130 *dest++ = ToLatin1Upper(ch);
136 template <
typename Char>
137 void ToUpperWithSharpS(
const Vector<const Char>& src,
138 Handle<SeqOneByteString> result) {
139 int32_t dest_index = 0;
140 for (
auto it = src.begin(); it != src.end(); ++it) {
141 uint16_t ch =
static_cast<uint16_t
>(*it);
143 result->SeqOneByteStringSet(dest_index++,
'S');
144 result->SeqOneByteStringSet(dest_index++,
'S');
146 result->SeqOneByteStringSet(dest_index++, ToLatin1Upper(ch));
151 inline int FindFirstUpperOrNonAscii(String s,
int length) {
152 for (
int index = 0; index < length; ++index) {
153 uint16_t ch = s->Get(index);
154 if (V8_UNLIKELY(IsASCIIUpper(ch) || ch & ~0x7F)) {
161 const UChar* GetUCharBufferFromFlat(
const String::FlatContent& flat,
162 std::unique_ptr<uc16[]>* dest,
164 DCHECK(flat.IsFlat());
165 if (flat.IsOneByte()) {
167 dest->reset(NewArray<uc16>(length));
168 CopyChars(dest->get(), flat.ToOneByteVector().start(), length);
170 return reinterpret_cast<const UChar*
>(dest->get());
172 return reinterpret_cast<const UChar*
>(flat.ToUC16Vector().start());
176 template <
typename T>
177 MaybeHandle<T> New(Isolate* isolate, Handle<JSFunction> constructor,
178 Handle<Object> locales, Handle<Object> options) {
179 Handle<JSObject> result;
180 ASSIGN_RETURN_ON_EXCEPTION(
182 JSObject::New(constructor, constructor, Handle<AllocationSite>::null()),
184 return T::Initialize(isolate, Handle<T>::cast(result), locales, options);
188 const uint8_t* Intl::ToLatin1LowerTable() {
return &kToLower[0]; }
190 icu::UnicodeString Intl::ToICUUnicodeString(Isolate* isolate,
191 Handle<String>
string) {
192 string = String::Flatten(isolate,
string);
194 DisallowHeapAllocation no_gc;
195 std::unique_ptr<uc16[]> sap;
196 return icu::UnicodeString(GetUCharBufferFromFlat(string->GetFlatContent(),
197 &sap,
string->length()),
203 MaybeHandle<String> LocaleConvertCase(Isolate* isolate, Handle<String> s,
204 bool is_to_upper,
const char* lang) {
205 auto case_converter = is_to_upper ? u_strToUpper : u_strToLower;
206 int32_t src_length = s->length();
207 int32_t dest_length = src_length;
209 Handle<SeqTwoByteString> result;
210 std::unique_ptr<uc16[]> sap;
212 if (dest_length == 0)
return ReadOnlyRoots(isolate).empty_string_handle();
216 for (
int i = 0;
i < 2; ++
i) {
219 ASSIGN_RETURN_ON_EXCEPTION(
220 isolate, result, isolate->factory()->NewRawTwoByteString(dest_length),
222 DisallowHeapAllocation no_gc;
224 String::FlatContent flat = s->GetFlatContent();
225 const UChar* src = GetUCharBufferFromFlat(flat, &sap, src_length);
226 status = U_ZERO_ERROR;
227 dest_length = case_converter(reinterpret_cast<UChar*>(result->GetChars()),
228 dest_length, src, src_length, lang, &status);
229 if (status != U_BUFFER_OVERFLOW_ERROR)
break;
236 DCHECK(U_SUCCESS(status));
237 if (V8_LIKELY(status == U_STRING_NOT_TERMINATED_WARNING)) {
238 DCHECK(dest_length == result->length());
241 DCHECK(dest_length < result->length());
242 return SeqString::Truncate(result, dest_length);
251 String Intl::ConvertOneByteToLower(String src, String dst) {
252 DCHECK_EQ(src->length(), dst->length());
253 DCHECK(src->HasOnlyOneByteChars());
254 DCHECK(src->IsFlat());
255 DCHECK(dst->IsSeqOneByteString());
257 DisallowHeapAllocation no_gc;
259 const int length = src->length();
260 String::FlatContent src_flat = src->GetFlatContent();
261 uint8_t* dst_data = SeqOneByteString::cast(dst)->GetChars();
263 if (src_flat.IsOneByte()) {
264 const uint8_t* src_data = src_flat.ToOneByteVector().start();
266 bool has_changed_character =
false;
267 int index_to_first_unprocessed =
268 FastAsciiConvert<true>(
reinterpret_cast<char*
>(dst_data),
269 reinterpret_cast<const char*>(src_data), length,
270 &has_changed_character);
272 if (index_to_first_unprocessed == length) {
273 return has_changed_character ? dst : src;
278 for (
int index = index_to_first_unprocessed; index < length; ++index) {
279 dst_data[index] = ToLatin1Lower(static_cast<uint16_t>(src_data[index]));
282 DCHECK(src_flat.IsTwoByte());
283 int index_to_first_unprocessed = FindFirstUpperOrNonAscii(src, length);
284 if (index_to_first_unprocessed == length)
return src;
286 const uint16_t* src_data = src_flat.ToUC16Vector().start();
287 CopyChars(dst_data, src_data, index_to_first_unprocessed);
288 for (
int index = index_to_first_unprocessed; index < length; ++index) {
289 dst_data[index] = ToLatin1Lower(static_cast<uint16_t>(src_data[index]));
296 MaybeHandle<String> Intl::ConvertToLower(Isolate* isolate, Handle<String> s) {
297 if (!s->HasOnlyOneByteChars()) {
299 return LocaleConvertCase(isolate, s,
false,
"");
302 int length = s->length();
315 bool is_short = length < static_cast<int>(
sizeof(
uintptr_t));
317 bool is_lower_ascii = FindFirstUpperOrNonAscii(*s, length) == length;
318 if (is_lower_ascii)
return s;
321 Handle<SeqOneByteString> result =
322 isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
324 return Handle<String>(Intl::ConvertOneByteToLower(*s, *result), isolate);
327 MaybeHandle<String> Intl::ConvertToUpper(Isolate* isolate, Handle<String> s) {
328 int32_t length = s->length();
329 if (s->HasOnlyOneByteChars() && length > 0) {
330 Handle<SeqOneByteString> result =
331 isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
335 bool is_result_single_byte;
337 DisallowHeapAllocation no_gc;
338 String::FlatContent flat = s->GetFlatContent();
339 uint8_t* dest = result->GetChars();
340 if (flat.IsOneByte()) {
341 Vector<const uint8_t> src = flat.ToOneByteVector();
342 bool has_changed_character =
false;
343 int index_to_first_unprocessed =
344 FastAsciiConvert<false>(
reinterpret_cast<char*
>(result->GetChars()),
345 reinterpret_cast<const char*>(src.start()),
346 length, &has_changed_character);
347 if (index_to_first_unprocessed == length) {
348 return has_changed_character ? result : s;
352 is_result_single_byte =
353 ToUpperOneByte(src.SubVector(index_to_first_unprocessed, length),
354 dest + index_to_first_unprocessed, &sharp_s_count);
356 DCHECK(flat.IsTwoByte());
357 Vector<const uint16_t> src = flat.ToUC16Vector();
358 if (ToUpperFastASCII(src, result))
return result;
359 is_result_single_byte = ToUpperOneByte(src, dest, &sharp_s_count);
365 if (V8_UNLIKELY(!is_result_single_byte)) {
366 return LocaleConvertCase(isolate, s,
true,
"");
369 if (sharp_s_count == 0)
return result;
373 ASSIGN_RETURN_ON_EXCEPTION(
375 isolate->factory()->NewRawOneByteString(length + sharp_s_count),
377 DisallowHeapAllocation no_gc;
378 String::FlatContent flat = s->GetFlatContent();
379 if (flat.IsOneByte()) {
380 ToUpperWithSharpS(flat.ToOneByteVector(), result);
382 ToUpperWithSharpS(flat.ToUC16Vector(), result);
388 return LocaleConvertCase(isolate, s,
true,
"");
391 std::string Intl::GetNumberingSystem(
const icu::Locale& icu_locale) {
395 UErrorCode status = U_ZERO_ERROR;
396 std::unique_ptr<icu::NumberingSystem> numbering_system(
397 icu::NumberingSystem::createInstance(icu_locale, status));
398 if (U_SUCCESS(status))
return numbering_system->getName();
402 icu::Locale Intl::CreateICULocale(
const std::string& bcp47_locale) {
403 DisallowHeapAllocation no_gc;
406 UErrorCode status = U_ZERO_ERROR;
407 char icu_result[ULOC_FULLNAME_CAPACITY];
408 int parsed_length = 0;
412 uloc_forLanguageTag(bcp47_locale.c_str(), icu_result, ULOC_FULLNAME_CAPACITY,
413 &parsed_length, &status);
414 CHECK(U_SUCCESS(status));
418 size_t bcp47_length = bcp47_locale.length();
419 CHECK_EQ(bcp47_length, parsed_length);
421 icu::Locale icu_locale(icu_result);
422 if (icu_locale.isBogus()) {
423 FATAL(
"Failed to create ICU locale, are ICU data files missing?");
431 MaybeHandle<String> Intl::ToString(Isolate* isolate,
432 const icu::UnicodeString&
string) {
433 return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
434 reinterpret_cast<const uint16_t*>(
string.getBuffer()),
string.length()));
437 MaybeHandle<String> Intl::ToString(Isolate* isolate,
438 const icu::UnicodeString&
string,
439 int32_t begin, int32_t end) {
440 return Intl::ToString(isolate,
string.tempSubStringBetween(begin, end));
445 Handle<JSObject> InnerAddElement(Isolate* isolate, Handle<JSArray> array,
446 int index, Handle<String> field_type_string,
447 Handle<String> value) {
453 Factory* factory = isolate->factory();
454 Handle<JSObject> element = factory->NewJSObject(isolate->object_function());
455 JSObject::AddProperty(isolate, element, factory->type_string(),
456 field_type_string, NONE);
458 JSObject::AddProperty(isolate, element, factory->value_string(), value, NONE);
459 JSObject::AddDataElement(array, index, element, NONE);
465 void Intl::AddElement(Isolate* isolate, Handle<JSArray> array,
int index,
466 Handle<String> field_type_string, Handle<String> value) {
468 InnerAddElement(isolate, array, index, field_type_string, value);
471 void Intl::AddElement(Isolate* isolate, Handle<JSArray> array,
int index,
472 Handle<String> field_type_string, Handle<String> value,
473 Handle<String> additional_property_name,
474 Handle<String> additional_property_value) {
479 Handle<JSObject> element =
480 InnerAddElement(isolate, array, index, field_type_string, value);
481 JSObject::AddProperty(isolate, element, additional_property_name,
482 additional_property_value, NONE);
491 bool RemoveLocaleScriptTag(
const std::string& icu_locale,
492 std::string* locale_less_script) {
493 icu::Locale new_locale = icu::Locale::createCanonical(icu_locale.c_str());
494 const char* icu_script = new_locale.getScript();
495 if (icu_script ==
nullptr || strlen(icu_script) == 0) {
496 *locale_less_script = std::string();
500 const char* icu_language = new_locale.getLanguage();
501 const char* icu_country = new_locale.getCountry();
502 icu::Locale short_locale = icu::Locale(icu_language, icu_country);
503 *locale_less_script = short_locale.getName();
509 std::set<std::string> Intl::BuildLocaleSet(
510 const icu::Locale* icu_available_locales, int32_t count) {
511 std::set<std::string> locales;
512 UErrorCode error = U_ZERO_ERROR;
513 char result[ULOC_FULLNAME_CAPACITY];
515 for (int32_t
i = 0;
i < count; ++
i) {
516 const char* icu_name = icu_available_locales[
i].getName();
518 error = U_ZERO_ERROR;
520 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
521 if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
525 std::string locale(result);
526 locales.insert(locale);
528 std::string shortened_locale;
529 if (RemoveLocaleScriptTag(icu_name, &shortened_locale)) {
530 std::replace(shortened_locale.begin(), shortened_locale.end(),
'_',
'-');
531 locales.insert(shortened_locale);
538 std::string Intl::DefaultLocale(Isolate* isolate) {
539 if (isolate->default_locale().empty()) {
540 icu::Locale default_locale;
542 if (strcmp(default_locale.getName(),
"en_US_POSIX") == 0) {
543 isolate->set_default_locale(
"en-US");
546 char result[ULOC_FULLNAME_CAPACITY];
547 UErrorCode status = U_ZERO_ERROR;
549 uloc_toLanguageTag(default_locale.getName(), result,
550 ULOC_FULLNAME_CAPACITY, FALSE, &status);
551 isolate->set_default_locale(
552 U_SUCCESS(status) ? std::string(result, length) :
"und");
554 DCHECK(!isolate->default_locale().empty());
556 return isolate->default_locale();
560 MaybeHandle<Object> Intl::LegacyUnwrapReceiver(Isolate* isolate,
561 Handle<JSReceiver> receiver,
562 Handle<JSFunction> constructor,
563 bool has_initialized_slot) {
564 Handle<Object> obj_is_instance_of;
565 ASSIGN_RETURN_ON_EXCEPTION(isolate, obj_is_instance_of,
566 Object::InstanceOf(isolate, receiver, constructor),
568 bool is_instance_of = obj_is_instance_of->BooleanValue(isolate);
572 if (!has_initialized_slot && is_instance_of) {
574 Handle<Object> new_receiver;
575 ASSIGN_RETURN_ON_EXCEPTION(
576 isolate, new_receiver,
577 JSReceiver::GetProperty(isolate, receiver,
578 isolate->factory()->intl_fallback_symbol()),
586 Maybe<bool> Intl::GetStringOption(Isolate* isolate, Handle<JSReceiver> options,
587 const char* property,
588 std::vector<const char*> values,
590 std::unique_ptr<
char[]>* result) {
591 Handle<String> property_str =
592 isolate->factory()->NewStringFromAsciiChecked(property);
595 Handle<Object> value;
596 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
598 Object::GetPropertyOrElement(isolate, options, property_str),
601 if (value->IsUndefined(isolate)) {
606 Handle<String> value_str;
607 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
608 isolate, value_str, Object::ToString(isolate, value), Nothing<bool>());
609 std::unique_ptr<char[]> value_cstr = value_str->ToCString();
612 if (values.size() > 0) {
615 for (
size_t i = 0;
i < values.size();
i++) {
616 if (strcmp(values.at(
i), value_cstr.get()) == 0) {
618 *result = std::move(value_cstr);
623 Handle<String> service_str =
624 isolate->factory()->NewStringFromAsciiChecked(service);
625 THROW_NEW_ERROR_RETURN_VALUE(
627 NewRangeError(MessageTemplate::kValueOutOfRange, value, service_str,
633 *result = std::move(value_cstr);
637 V8_WARN_UNUSED_RESULT Maybe<bool> Intl::GetBoolOption(
638 Isolate* isolate, Handle<JSReceiver> options,
const char* property,
639 const char* service,
bool* result) {
640 Handle<String> property_str =
641 isolate->factory()->NewStringFromAsciiChecked(property);
644 Handle<Object> value;
645 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
647 Object::GetPropertyOrElement(isolate, options, property_str),
651 if (!value->IsUndefined(isolate)) {
653 *result = value->BooleanValue(isolate);
664 char AsciiToLower(
char c) {
665 if (c < 'A' || c >
'Z') {
671 bool IsLowerAscii(
char c) {
return c >=
'a' && c <
'z'; }
673 bool IsTwoLetterLanguage(
const std::string& locale) {
675 return locale.length() == 2 && IsLowerAscii(locale[0]) &&
676 IsLowerAscii(locale[1]);
679 bool IsDeprecatedLanguage(
const std::string& locale) {
681 return locale ==
"in" || locale ==
"iw" || locale ==
"ji" || locale ==
"jw";
686 bool IsGrandfatheredTagWithoutPreferredVaule(
const std::string& locale) {
687 if (V8_UNLIKELY(locale ==
"zh-min" || locale ==
"cel-gaulish"))
return true;
688 if (locale.length() > 6 &&
689 V8_UNLIKELY(locale[0] ==
'i' && locale[1] ==
'-')) {
690 return locale.substr(2) ==
"default" || locale.substr(2) ==
"enochian" ||
691 locale.substr(2) ==
"mingo";
698 Maybe<std::string> Intl::CanonicalizeLanguageTag(Isolate* isolate,
699 Handle<Object> locale_in) {
700 Handle<String> locale_str;
708 if (locale_in->IsString()) {
709 locale_str = Handle<String>::cast(locale_in);
710 }
else if (locale_in->IsJSReceiver()) {
711 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, locale_str,
712 Object::ToString(isolate, locale_in),
713 Nothing<std::string>());
715 THROW_NEW_ERROR_RETURN_VALUE(isolate,
716 NewTypeError(MessageTemplate::kLanguageID),
717 Nothing<std::string>());
719 std::string locale(locale_str->ToCString().get());
721 if (locale.length() == 0 ||
722 !String::IsAscii(locale.data(),
static_cast<int>(locale.length()))) {
723 THROW_NEW_ERROR_RETURN_VALUE(
725 NewRangeError(MessageTemplate::kInvalidLanguageTag, locale_str),
726 Nothing<std::string>());
734 if ((IsTwoLetterLanguage(locale) && !IsDeprecatedLanguage(locale)) ||
741 std::transform(locale.begin(), locale.end(), locale.begin(), AsciiToLower);
746 if (IsGrandfatheredTagWithoutPreferredVaule(locale)) {
757 UErrorCode error = U_ZERO_ERROR;
758 char icu_result[ULOC_FULLNAME_CAPACITY];
764 uloc_forLanguageTag(locale.c_str(), icu_result, ULOC_FULLNAME_CAPACITY,
765 &parsed_length, &error);
766 if (U_FAILURE(error) ||
767 static_cast<size_t>(parsed_length) < locale.length() ||
768 error == U_STRING_NOT_TERMINATED_WARNING) {
769 THROW_NEW_ERROR_RETURN_VALUE(
771 NewRangeError(MessageTemplate::kInvalidLanguageTag, locale_str),
772 Nothing<std::string>());
776 char result[ULOC_FULLNAME_CAPACITY];
777 int32_t result_len = uloc_toLanguageTag(icu_result, result,
778 ULOC_FULLNAME_CAPACITY, TRUE, &error);
780 if (U_FAILURE(error)) {
781 THROW_NEW_ERROR_RETURN_VALUE(
783 NewRangeError(MessageTemplate::kInvalidLanguageTag, locale_str),
784 Nothing<std::string>());
787 return Just(std::string(result, result_len));
790 Maybe<std::vector<std::string>> Intl::CanonicalizeLocaleList(
791 Isolate* isolate, Handle<Object> locales,
bool only_return_one_result) {
793 if (locales->IsUndefined(isolate)) {
795 return Just(std::vector<std::string>());
798 std::vector<std::string> seen;
800 if (locales->IsString()) {
804 std::string canonicalized_tag;
805 if (!CanonicalizeLanguageTag(isolate, locales).To(&canonicalized_tag)) {
806 return Nothing<std::vector<std::string>>();
808 seen.push_back(canonicalized_tag);
813 Handle<JSReceiver> o;
814 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, o,
815 Object::ToObject(isolate, locales),
816 Nothing<std::vector<std::string>>());
818 Handle<Object> length_obj;
819 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, length_obj,
820 Object::GetLengthFromArrayLike(isolate, o),
821 Nothing<std::vector<std::string>>());
826 double raw_length = length_obj->Number();
828 raw_length >= kMaxUInt32 ? kMaxUInt32 :
static_cast<uint32_t>(raw_length);
831 for (
uint32_t k = 0; k < len; k++) {
834 LookupIterator it(isolate, o, k);
835 Maybe<bool> maybe_found = JSReceiver::HasProperty(&it);
836 MAYBE_RETURN(maybe_found, Nothing<std::vector<std::string>>());
838 if (!maybe_found.FromJust())
continue;
840 Handle<Object> k_value;
841 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, k_value, Object::GetProperty(&it),
842 Nothing<std::vector<std::string>>());
849 std::string canonicalized_tag;
850 if (!CanonicalizeLanguageTag(isolate, k_value).To(&canonicalized_tag)) {
851 return Nothing<std::vector<std::string>>();
855 if (std::find(seen.begin(), seen.end(), canonicalized_tag) == seen.end()) {
856 seen.push_back(canonicalized_tag);
860 if (only_return_one_result)
return Just(seen);
868 MaybeHandle<String> Intl::StringLocaleConvertCase(Isolate* isolate,
871 Handle<Object> locales) {
872 std::vector<std::string> requested_locales;
873 if (!CanonicalizeLocaleList(isolate, locales,
true).To(&requested_locales)) {
874 return MaybeHandle<String>();
876 std::string requested_locale = requested_locales.size() == 0
877 ? Intl::DefaultLocale(isolate)
878 : requested_locales[0];
879 size_t dash = requested_locale.find(
'-');
880 if (dash != std::string::npos) {
881 requested_locale = requested_locale.substr(0, dash);
886 DCHECK_LE(requested_locale.length(), 8);
887 s = String::Flatten(isolate, s);
893 if (V8_UNLIKELY(requested_locale.length() != 2)) {
895 return ConvertToUpper(isolate, s);
897 return ConvertToLower(isolate, s);
903 if (V8_UNLIKELY((requested_locale ==
"tr") || (requested_locale ==
"el") ||
904 (requested_locale ==
"lt") || (requested_locale ==
"az"))) {
905 return LocaleConvertCase(isolate, s, to_upper, requested_locale.c_str());
908 return ConvertToUpper(isolate, s);
910 return ConvertToLower(isolate, s);
914 MaybeHandle<Object> Intl::StringLocaleCompare(Isolate* isolate,
915 Handle<String> string1,
916 Handle<String> string2,
917 Handle<Object> locales,
918 Handle<Object> options) {
923 locales->IsUndefined(isolate) && options->IsUndefined(isolate);
926 icu::Collator* cached_icu_collator =
927 static_cast<icu::Collator*
>(isolate->get_cached_icu_object(
928 Isolate::ICUObjectCacheType::kDefaultCollator));
930 if (cached_icu_collator !=
nullptr) {
931 return Intl::CompareStrings(isolate, *cached_icu_collator, string1,
936 Handle<JSFunction> constructor = Handle<JSFunction>(
938 isolate->context()->native_context()->intl_collator_function()),
941 Handle<JSCollator> collator;
942 ASSIGN_RETURN_ON_EXCEPTION(
944 New<JSCollator>(isolate, constructor, locales, options), Object);
946 isolate->set_icu_object_in_cache(
947 Isolate::ICUObjectCacheType::kDefaultCollator,
948 std::static_pointer_cast<icu::UObject>(
949 collator->icu_collator()->get()));
951 return Intl::CompareStrings(isolate, *(collator->icu_collator()->raw()),
956 Handle<Object> Intl::CompareStrings(Isolate* isolate,
957 const icu::Collator& icu_collator,
958 Handle<String> string1,
959 Handle<String> string2) {
960 Factory* factory = isolate->factory();
962 string1 = String::Flatten(isolate, string1);
963 string2 = String::Flatten(isolate, string2);
965 UCollationResult result;
966 UErrorCode status = U_ZERO_ERROR;
967 icu::UnicodeString string_val1 = Intl::ToICUUnicodeString(isolate, string1);
968 icu::UnicodeString string_val2 = Intl::ToICUUnicodeString(isolate, string2);
969 result = icu_collator.compare(string_val1, string_val2, status);
970 DCHECK(U_SUCCESS(status));
972 return factory->NewNumberFromInt(result);
976 MaybeHandle<String> Intl::NumberToLocaleString(Isolate* isolate,
978 Handle<Object> locales,
979 Handle<Object> options) {
980 Handle<Object> number_obj;
981 ASSIGN_RETURN_ON_EXCEPTION(isolate, number_obj,
982 Object::ToNumber(isolate, num), String);
985 double number = number_obj->Number() + 0;
991 locales->IsUndefined(isolate) && options->IsUndefined(isolate);
993 icu::NumberFormat* cached_number_format =
994 static_cast<icu::NumberFormat*
>(isolate->get_cached_icu_object(
995 Isolate::ICUObjectCacheType::kDefaultNumberFormat));
997 if (cached_number_format !=
nullptr) {
998 return JSNumberFormat::FormatNumber(isolate, *cached_number_format,
1003 Handle<JSFunction> constructor = Handle<JSFunction>(
1005 isolate->context()->native_context()->intl_number_format_function()),
1007 Handle<JSNumberFormat> number_format;
1009 ASSIGN_RETURN_ON_EXCEPTION(
1010 isolate, number_format,
1011 New<JSNumberFormat>(isolate, constructor, locales, options), String);
1014 isolate->set_icu_object_in_cache(
1015 Isolate::ICUObjectCacheType::kDefaultNumberFormat,
1016 std::static_pointer_cast<icu::UObject>(
1017 number_format->icu_number_format()->get()));
1021 return JSNumberFormat::FormatNumber(
1022 isolate, *(number_format->icu_number_format()->raw()), number);
1028 Maybe<int> DefaultNumberOption(Isolate* isolate, Handle<Object> value,
int min,
1029 int max,
int fallback, Handle<String> property) {
1031 if (value->IsUndefined())
return Just(fallback);
1035 Handle<Object> value_num;
1036 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1037 isolate, value_num, Object::ToNumber(isolate, value), Nothing<int>());
1038 DCHECK(value_num->IsNumber());
1042 if (value_num->IsNaN() || value_num->Number() < min ||
1043 value_num->Number() > max) {
1044 THROW_NEW_ERROR_RETURN_VALUE(
1046 NewRangeError(MessageTemplate::kPropertyValueOutOfRange, property),
1055 return Just(FastD2I(floor(value_num->Number())));
1059 Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
1060 Handle<String> property,
int min,
int max,
1063 Handle<Object> value;
1064 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1065 isolate, value, JSReceiver::GetProperty(isolate, options, property),
1069 return DefaultNumberOption(isolate, value, min, max, fallback, property);
1072 Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options,
1073 const char* property,
int min,
int max,
1075 Handle<String> property_str =
1076 isolate->factory()->NewStringFromAsciiChecked(property);
1077 return GetNumberOption(isolate, options, property_str, min, max, fallback);
1082 Maybe<bool> Intl::SetNumberFormatDigitOptions(Isolate* isolate,
1083 icu::DecimalFormat* number_format,
1084 Handle<JSReceiver> options,
1087 CHECK_NOT_NULL(number_format);
1092 if (!GetNumberOption(isolate, options,
"minimumIntegerDigits", 1, 21, 1)
1094 return Nothing<bool>();
1100 if (!GetNumberOption(isolate, options,
"minimumFractionDigits", 0, 20,
1103 return Nothing<bool>();
1107 int mxfd_actual_default = std::max(mnfd, mxfd_default);
1112 if (!GetNumberOption(isolate, options,
"maximumFractionDigits", mnfd, 20,
1113 mxfd_actual_default)
1115 return Nothing<bool>();
1119 Handle<Object> mnsd_obj;
1120 Handle<String> mnsd_str =
1121 isolate->factory()->minimumSignificantDigits_string();
1122 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1123 isolate, mnsd_obj, JSReceiver::GetProperty(isolate, options, mnsd_str),
1127 Handle<Object> mxsd_obj;
1128 Handle<String> mxsd_str =
1129 isolate->factory()->maximumSignificantDigits_string();
1130 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1131 isolate, mxsd_obj, JSReceiver::GetProperty(isolate, options, mxsd_str),
1135 number_format->setMinimumIntegerDigits(mnid);
1138 number_format->setMinimumFractionDigits(mnfd);
1141 number_format->setMaximumFractionDigits(mxfd);
1143 bool significant_digits_used =
false;
1145 if (!mnsd_obj->IsUndefined(isolate) || !mxsd_obj->IsUndefined(isolate)) {
1148 if (!DefaultNumberOption(isolate, mnsd_obj, 1, 21, 1, mnsd_str).To(&mnsd)) {
1149 return Nothing<bool>();
1154 if (!DefaultNumberOption(isolate, mxsd_obj, mnsd, 21, 21, mxsd_str)
1156 return Nothing<bool>();
1159 significant_digits_used =
true;
1162 number_format->setMinimumSignificantDigits(mnsd);
1165 number_format->setMaximumSignificantDigits(mxsd);
1168 number_format->setSignificantDigitsUsed(significant_digits_used);
1169 number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
1176 std::string BestAvailableLocale(
const std::set<std::string>& available_locales,
1177 const std::string& locale) {
1179 std::string candidate = locale;
1185 if (available_locales.find(candidate) != available_locales.end()) {
1192 size_t pos = candidate.rfind(
'-');
1193 if (pos == std::string::npos) {
1194 return std::string();
1199 if (pos >= 2 && candidate[pos - 2] ==
'-') {
1205 candidate = candidate.substr(0, pos);
1209 struct ParsedLocale {
1210 std::string no_extensions_locale;
1211 std::string extension;
1219 ParsedLocale ParseBCP47Locale(
const std::string& locale) {
1220 size_t length = locale.length();
1221 ParsedLocale parsed_locale;
1224 if ((length > 1) && (locale[1] ==
'-')) {
1228 CHECK(locale[0] ==
'x' || locale[0] ==
'i');
1229 parsed_locale.no_extensions_locale = locale;
1230 return parsed_locale;
1233 size_t unicode_extension_start = locale.find(
"-u-");
1236 if (unicode_extension_start == std::string::npos) {
1237 parsed_locale.no_extensions_locale = locale;
1238 return parsed_locale;
1241 size_t private_extension_start = locale.find(
"-x-");
1244 if (private_extension_start != std::string::npos &&
1245 private_extension_start < unicode_extension_start) {
1246 parsed_locale.no_extensions_locale = locale;
1247 return parsed_locale;
1250 const std::string beginning = locale.substr(0, unicode_extension_start);
1251 size_t unicode_extension_end = length;
1252 DCHECK_GT(length, 2);
1256 for (
size_t i = unicode_extension_start + 1;
i < length - 2;
i++) {
1257 if (locale[
i] !=
'-')
continue;
1259 if (locale[
i + 2] ==
'-') {
1260 unicode_extension_end =
i;
1267 const std::string end = locale.substr(unicode_extension_end);
1268 parsed_locale.no_extensions_locale = beginning + end;
1269 parsed_locale.extension = locale.substr(
1270 unicode_extension_start, unicode_extension_end - unicode_extension_start);
1271 return parsed_locale;
1275 std::vector<std::string> LookupSupportedLocales(
1276 const std::set<std::string>& available_locales,
1277 const std::vector<std::string>& requested_locales) {
1279 std::vector<std::string> subset;
1282 for (
const std::string& locale : requested_locales) {
1285 std::string no_extension_locale =
1286 ParseBCP47Locale(locale).no_extensions_locale;
1290 std::string available_locale =
1291 BestAvailableLocale(available_locales, no_extension_locale);
1295 if (!available_locale.empty()) {
1296 subset.push_back(locale);
1306 std::vector<std::string> BestFitSupportedLocales(
1307 const std::set<std::string>& available_locales,
1308 const std::vector<std::string>& requested_locales) {
1309 return LookupSupportedLocales(available_locales, requested_locales);
1313 Handle<JSArray> CreateArrayFromList(Isolate* isolate,
1314 std::vector<std::string> elements,
1315 PropertyAttributes attr) {
1316 Factory* factory = isolate->factory();
1318 Handle<JSArray> array = factory->NewJSArray(0);
1325 const std::string& part = elements[
i];
1326 Handle<String> value =
1327 factory->NewStringFromUtf8(CStrVector(part.c_str())).ToHandleChecked();
1328 JSObject::AddDataElement(array,
i, value, attr);
1337 MaybeHandle<JSObject> CreateReadOnlyArray(Isolate* isolate,
1338 std::vector<std::string> elements) {
1339 if (elements.size() >= kMaxUInt32) {
1341 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength), JSObject);
1344 PropertyAttributes attr =
1345 static_cast<PropertyAttributes
>(READ_ONLY | DONT_DELETE);
1348 Handle<JSArray> subset = CreateArrayFromList(isolate, elements, attr);
1354 PropertyDescriptor desc;
1355 desc.set_writable(
false);
1356 desc.set_configurable(
false);
1359 JSArray::ArraySetLength(isolate, subset, &desc, kThrowOnError).ToChecked();
1365 MaybeHandle<JSObject> SupportedLocales(
1366 Isolate* isolate,
const char* method,
1367 const std::set<std::string>& available_locales,
1368 const std::vector<std::string>& requested_locales, Handle<Object> options) {
1369 std::vector<std::string> supported_locales;
1372 Intl::MatcherOption matcher = Intl::MatcherOption::kBestFit;
1375 if (!options->IsUndefined(isolate)) {
1377 Handle<JSReceiver> options_obj;
1378 ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
1379 Object::ToObject(isolate, options), JSObject);
1383 Maybe<Intl::MatcherOption> maybe_locale_matcher =
1384 Intl::GetLocaleMatcher(isolate, options_obj, method);
1385 MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSObject>());
1386 matcher = maybe_locale_matcher.FromJust();
1392 if (matcher == Intl::MatcherOption::kBestFit) {
1394 BestFitSupportedLocales(available_locales, requested_locales);
1399 DCHECK_EQ(matcher, Intl::MatcherOption::kLookup);
1401 LookupSupportedLocales(available_locales, requested_locales);
1414 MaybeHandle<JSObject> subset =
1415 CreateReadOnlyArray(isolate, supported_locales);
1423 MaybeHandle<JSArray> Intl::GetCanonicalLocales(Isolate* isolate,
1424 Handle<Object> locales) {
1426 Maybe<std::vector<std::string>> maybe_ll =
1427 CanonicalizeLocaleList(isolate, locales,
false);
1428 MAYBE_RETURN(maybe_ll, MaybeHandle<JSArray>());
1431 PropertyAttributes attr =
static_cast<PropertyAttributes
>(NONE);
1432 return CreateArrayFromList(isolate, maybe_ll.FromJust(), attr);
1436 MaybeHandle<JSObject> Intl::SupportedLocalesOf(
1437 Isolate* isolate,
const char* method,
1438 const std::set<std::string>& available_locales, Handle<Object> locales,
1439 Handle<Object> options) {
1443 Maybe<std::vector<std::string>> requested_locales =
1444 CanonicalizeLocaleList(isolate, locales,
false);
1445 MAYBE_RETURN(requested_locales, MaybeHandle<JSObject>());
1448 return SupportedLocales(isolate, method, available_locales,
1449 requested_locales.FromJust(), options);
1454 std::map<std::string, std::string> LookupAndValidateUnicodeExtensions(
1455 icu::Locale* icu_locale,
const std::set<std::string>& relevant_keys) {
1456 std::map<std::string, std::string> extensions;
1458 UErrorCode status = U_ZERO_ERROR;
1459 std::unique_ptr<icu::StringEnumeration> keywords(
1460 icu_locale->createKeywords(status));
1461 if (U_FAILURE(status))
return extensions;
1463 if (!keywords)
return extensions;
1464 char value[ULOC_FULLNAME_CAPACITY];
1467 status = U_ZERO_ERROR;
1468 for (
const char* keyword = keywords->next(&length, status);
1469 keyword !=
nullptr; keyword = keywords->next(&length, status)) {
1473 if (U_FAILURE(status)) {
1474 status = U_ZERO_ERROR;
1478 icu_locale->getKeywordValue(keyword, value, ULOC_FULLNAME_CAPACITY, status);
1483 if (U_FAILURE(status)) {
1484 status = U_ZERO_ERROR;
1488 const char* bcp47_key = uloc_toUnicodeLocaleKey(keyword);
1490 if (bcp47_key && (relevant_keys.find(bcp47_key) != relevant_keys.end())) {
1491 const char* bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
1493 std::pair<std::string, std::string>(bcp47_key, bcp47_value));
1495 status = U_ZERO_ERROR;
1496 icu_locale->setKeywordValue(keyword,
nullptr, status);
1497 CHECK(U_SUCCESS(status));
1505 std::string LookupMatcher(Isolate* isolate,
1506 const std::set<std::string>& available_locales,
1507 const std::vector<std::string>& requested_locales) {
1512 for (
const std::string& locale : requested_locales) {
1515 ParsedLocale parsed_locale = ParseBCP47Locale(locale);
1516 std::string no_extensions_locale = parsed_locale.no_extensions_locale;
1520 std::string available_locale =
1521 BestAvailableLocale(available_locales, no_extensions_locale);
1525 if (!available_locale.empty()) {
1542 return available_locale + parsed_locale.extension;
1549 return Intl::DefaultLocale(isolate);
1564 Intl::ResolvedLocale Intl::ResolveLocale(
1565 Isolate* isolate,
const std::set<std::string>& available_locales,
1566 const std::vector<std::string>& requested_locales, MatcherOption matcher,
1567 const std::set<std::string>& relevant_extension_keys) {
1569 if (matcher == Intl::MatcherOption::kLookup) {
1570 locale = LookupMatcher(isolate, available_locales, requested_locales);
1571 }
else if (matcher == Intl::MatcherOption::kBestFit) {
1573 locale = LookupMatcher(isolate, available_locales, requested_locales);
1576 icu::Locale icu_locale = CreateICULocale(locale);
1577 std::map<std::string, std::string> extensions =
1578 LookupAndValidateUnicodeExtensions(&icu_locale, relevant_extension_keys);
1580 char canonicalized_locale[ULOC_FULLNAME_CAPACITY];
1581 UErrorCode status = U_ZERO_ERROR;
1582 uloc_toLanguageTag(icu_locale.getName(), canonicalized_locale,
1583 ULOC_FULLNAME_CAPACITY,
true, &status);
1584 CHECK(U_SUCCESS(status));
1588 return Intl::ResolvedLocale{canonicalized_locale, icu_locale, extensions};
1591 Managed<icu::UnicodeString>* Intl::SetTextToBreakIterator(
1592 Isolate* isolate, Handle<String> text, icu::BreakIterator* break_iterator) {
1593 icu::UnicodeString* u_text =
1594 (icu::UnicodeString*)(Intl::ToICUUnicodeString(isolate, text).clone());
1596 Handle<Managed<icu::UnicodeString>> new_u_text =
1597 Managed<icu::UnicodeString>::FromRawPtr(isolate, 0, u_text);
1599 break_iterator->setText(*u_text);
1604 MaybeHandle<String> Intl::Normalize(Isolate* isolate, Handle<String>
string,
1605 Handle<Object> form_input) {
1606 const char* form_name;
1607 UNormalization2Mode form_mode;
1608 if (form_input->IsUndefined(isolate)) {
1611 form_mode = UNORM2_COMPOSE;
1613 Handle<String> form;
1614 ASSIGN_RETURN_ON_EXCEPTION(isolate, form,
1615 Object::ToString(isolate, form_input), String);
1617 if (String::Equals(isolate, form, isolate->factory()->NFC_string())) {
1619 form_mode = UNORM2_COMPOSE;
1620 }
else if (String::Equals(isolate, form,
1621 isolate->factory()->NFD_string())) {
1623 form_mode = UNORM2_DECOMPOSE;
1624 }
else if (String::Equals(isolate, form,
1625 isolate->factory()->NFKC_string())) {
1627 form_mode = UNORM2_COMPOSE;
1628 }
else if (String::Equals(isolate, form,
1629 isolate->factory()->NFKD_string())) {
1631 form_mode = UNORM2_DECOMPOSE;
1633 Handle<String> valid_forms =
1634 isolate->factory()->NewStringFromStaticChars(
"NFC, NFD, NFKC, NFKD");
1637 NewRangeError(MessageTemplate::kNormalizationForm, valid_forms),
1642 int length =
string->length();
1643 string = String::Flatten(isolate,
string);
1644 icu::UnicodeString result;
1645 std::unique_ptr<uc16[]> sap;
1646 UErrorCode status = U_ZERO_ERROR;
1647 icu::UnicodeString input = ToICUUnicodeString(isolate,
string);
1649 const icu::Normalizer2* normalizer =
1650 icu::Normalizer2::getInstance(
nullptr, form_name, form_mode, status);
1651 DCHECK(U_SUCCESS(status));
1652 CHECK_NOT_NULL(normalizer);
1653 int32_t normalized_prefix_length =
1654 normalizer->spanQuickCheckYes(input, status);
1656 if (length == normalized_prefix_length)
return string;
1657 icu::UnicodeString unnormalized =
1658 input.tempSubString(normalized_prefix_length);
1660 result.setTo(
false, input.getBuffer(), normalized_prefix_length);
1662 normalizer->normalizeSecondAndAppend(result, unnormalized, status);
1664 if (U_FAILURE(status)) {
1665 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), String);
1668 return Intl::ToString(isolate, result);
1679 const char* LocalTimezone(
double time_ms)
override;
1681 double DaylightSavingsOffset(
double time_ms)
override;
1683 double LocalTimeOffset(
double time_ms,
bool is_utc)
override;
1685 void Clear()
override;
1688 icu::TimeZone* GetTimeZone();
1690 bool GetOffsets(
double time_ms,
bool is_utc, int32_t* raw_offset,
1691 int32_t* dst_offset);
1693 icu::TimeZone* timezone_;
1695 std::string timezone_name_;
1696 std::string dst_timezone_name_;
1699 const char* ICUTimezoneCache::LocalTimezone(
double time_ms) {
1700 bool is_dst = DaylightSavingsOffset(time_ms) != 0;
1701 std::string* name = is_dst ? &dst_timezone_name_ : &timezone_name_;
1702 if (name->empty()) {
1703 icu::UnicodeString result;
1704 GetTimeZone()->getDisplayName(is_dst, icu::TimeZone::LONG, result);
1707 icu::StringByteSink<std::string> byte_sink(name);
1708 result.toUTF8(byte_sink);
1710 DCHECK(!name->empty());
1711 return name->c_str();
1714 icu::TimeZone* ICUTimezoneCache::GetTimeZone() {
1715 if (timezone_ ==
nullptr) {
1716 timezone_ = icu::TimeZone::createDefault();
1721 bool ICUTimezoneCache::GetOffsets(
double time_ms,
bool is_utc,
1722 int32_t* raw_offset, int32_t* dst_offset) {
1723 UErrorCode status = U_ZERO_ERROR;
1735 GetTimeZone()->getOffset(time_ms,
false, *raw_offset, *dst_offset, status);
1737 static_cast<const icu::BasicTimeZone*
>(GetTimeZone())
1738 ->getOffsetFromLocal(time_ms, icu::BasicTimeZone::kFormer,
1739 icu::BasicTimeZone::kFormer, *raw_offset,
1740 *dst_offset, status);
1743 return U_SUCCESS(status);
1746 double ICUTimezoneCache::DaylightSavingsOffset(
double time_ms) {
1747 int32_t raw_offset, dst_offset;
1748 if (!GetOffsets(time_ms,
true, &raw_offset, &dst_offset))
return 0;
1752 double ICUTimezoneCache::LocalTimeOffset(
double time_ms,
bool is_utc) {
1753 int32_t raw_offset, dst_offset;
1754 if (!GetOffsets(time_ms, is_utc, &raw_offset, &dst_offset))
return 0;
1755 return raw_offset + dst_offset;
1758 void ICUTimezoneCache::Clear() {
1760 timezone_ =
nullptr;
1761 timezone_name_.clear();
1762 dst_timezone_name_.clear();
1765 base::TimezoneCache* Intl::CreateTimeZoneCache() {
1766 return FLAG_icu_timezone_data ?
new ICUTimezoneCache()
1767 : base::OS::CreateTimezoneCache();
1770 Maybe<Intl::CaseFirst> Intl::GetCaseFirst(Isolate* isolate,
1771 Handle<JSReceiver> options,
1772 const char* method) {
1773 return Intl::GetStringOption<Intl::CaseFirst>(
1774 isolate, options,
"caseFirst", method, {
"upper",
"lower",
"false"},
1775 {Intl::CaseFirst::kUpper, Intl::CaseFirst::kLower,
1776 Intl::CaseFirst::kFalse},
1777 Intl::CaseFirst::kUndefined);
1780 Maybe<Intl::HourCycle> Intl::GetHourCycle(Isolate* isolate,
1781 Handle<JSReceiver> options,
1782 const char* method) {
1783 return Intl::GetStringOption<Intl::HourCycle>(
1784 isolate, options,
"hourCycle", method, {
"h11",
"h12",
"h23",
"h24"},
1785 {Intl::HourCycle::kH11, Intl::HourCycle::kH12, Intl::HourCycle::kH23,
1786 Intl::HourCycle::kH24},
1787 Intl::HourCycle::kUndefined);
1790 Maybe<Intl::MatcherOption> Intl::GetLocaleMatcher(Isolate* isolate,
1791 Handle<JSReceiver> options,
1792 const char* method) {
1793 return Intl::GetStringOption<Intl::MatcherOption>(
1794 isolate, options,
"localeMatcher", method, {
"best fit",
"lookup"},
1795 {Intl::MatcherOption::kLookup, Intl::MatcherOption::kBestFit},
1796 Intl::MatcherOption::kLookup);