1// Copyright 2019 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-display-names.h" 10 11#include <memory> 12#include <vector> 13 14#include "src/execution/isolate.h" 15#include "src/heap/factory.h" 16#include "src/objects/intl-objects.h" 17#include "src/objects/js-display-names-inl.h" 18#include "src/objects/managed-inl.h" 19#include "src/objects/objects-inl.h" 20#include "src/objects/option-utils.h" 21#include "unicode/dtfmtsym.h" 22#include "unicode/dtptngen.h" 23#include "unicode/localebuilder.h" 24#include "unicode/locdspnm.h" 25#include "unicode/measfmt.h" 26#include "unicode/timezone.h" 27#include "unicode/tznames.h" 28#include "unicode/uloc.h" 29#include "unicode/unistr.h" 30#include "unicode/uscript.h" 31 32namespace v8 { 33namespace internal { 34 35namespace { 36// Type: identifying the types of the display names. 37// 38// ecma402/#sec-properties-of-intl-displaynames-instances 39enum class Type { 40 kUndefined, 41 kLanguage, 42 kRegion, 43 kScript, 44 kCurrency, 45 kCalendar, 46 kDateTimeField 47}; 48 49bool IsUnicodeScriptSubtag(const std::string& value) { 50 UErrorCode status = U_ZERO_ERROR; 51 icu::LocaleBuilder builder; 52 builder.setScript(value).build(status); 53 return U_SUCCESS(status); 54} 55 56bool IsUnicodeRegionSubtag(const std::string& value) { 57 UErrorCode status = U_ZERO_ERROR; 58 icu::LocaleBuilder builder; 59 builder.setRegion(value).build(status); 60 return U_SUCCESS(status); 61} 62 63UDisplayContext ToUDisplayContext(JSDisplayNames::Style style) { 64 switch (style) { 65 case JSDisplayNames::Style::kLong: 66 return UDISPCTX_LENGTH_FULL; 67 case JSDisplayNames::Style::kShort: 68 case JSDisplayNames::Style::kNarrow: 69 return UDISPCTX_LENGTH_SHORT; 70 } 71} 72 73} // anonymous namespace 74 75// Abstract class for all different types. 76class DisplayNamesInternal { 77 public: 78 DisplayNamesInternal() = default; 79 virtual ~DisplayNamesInternal() = default; 80 virtual const char* type() const = 0; 81 virtual icu::Locale locale() const = 0; 82 virtual Maybe<icu::UnicodeString> of(Isolate* isolate, 83 const char* code) const = 0; 84}; 85 86namespace { 87 88class LocaleDisplayNamesCommon : public DisplayNamesInternal { 89 public: 90 LocaleDisplayNamesCommon(const icu::Locale& locale, 91 JSDisplayNames::Style style, bool fallback, 92 bool dialect) 93 : style_(style) { 94 UDisplayContext sub = 95 fallback ? UDISPCTX_SUBSTITUTE : UDISPCTX_NO_SUBSTITUTE; 96 UDisplayContext dialect_context = 97 dialect ? UDISPCTX_DIALECT_NAMES : UDISPCTX_STANDARD_NAMES; 98 UDisplayContext display_context[] = {ToUDisplayContext(style_), 99 dialect_context, 100 UDISPCTX_CAPITALIZATION_NONE, sub}; 101 ldn_.reset( 102 icu::LocaleDisplayNames::createInstance(locale, display_context, 4)); 103 } 104 105 ~LocaleDisplayNamesCommon() override = default; 106 107 icu::Locale locale() const override { return ldn_->getLocale(); } 108 109 protected: 110 icu::LocaleDisplayNames* locale_display_names() const { return ldn_.get(); } 111 112 private: 113 std::unique_ptr<icu::LocaleDisplayNames> ldn_; 114 JSDisplayNames::Style style_; 115}; 116 117class LanguageNames : public LocaleDisplayNamesCommon { 118 public: 119 LanguageNames(const icu::Locale& locale, JSDisplayNames::Style style, 120 bool fallback, bool dialect) 121 : LocaleDisplayNamesCommon(locale, style, fallback, dialect) {} 122 123 ~LanguageNames() override = default; 124 125 const char* type() const override { return "language"; } 126 127 Maybe<icu::UnicodeString> of(Isolate* isolate, 128 const char* code) const override { 129 UErrorCode status = U_ZERO_ERROR; 130 // 1.a If code does not match the unicode_language_id production, throw a 131 // RangeError exception. 132 133 // 1.b If IsStructurallyValidLanguageTag(code) is false, throw a RangeError 134 // exception. 135 icu::Locale l = 136 icu::Locale(icu::Locale::forLanguageTag(code, status).getBaseName()); 137 // 1.c Set code to CanonicalizeUnicodeLocaleId(code). 138 l.canonicalize(status); 139 std::string checked = l.toLanguageTag<std::string>(status); 140 141 if (U_FAILURE(status)) { 142 THROW_NEW_ERROR_RETURN_VALUE( 143 isolate, NewRangeError(MessageTemplate::kInvalidArgument), 144 Nothing<icu::UnicodeString>()); 145 } 146 147 icu::UnicodeString result; 148 locale_display_names()->localeDisplayName(checked.c_str(), result); 149 150 return Just(result); 151 } 152}; 153 154class RegionNames : public LocaleDisplayNamesCommon { 155 public: 156 RegionNames(const icu::Locale& locale, JSDisplayNames::Style style, 157 bool fallback, bool dialect) 158 : LocaleDisplayNamesCommon(locale, style, fallback, dialect) {} 159 160 ~RegionNames() override = default; 161 162 const char* type() const override { return "region"; } 163 164 Maybe<icu::UnicodeString> of(Isolate* isolate, 165 const char* code) const override { 166 std::string code_str(code); 167 if (!IsUnicodeRegionSubtag(code_str)) { 168 THROW_NEW_ERROR_RETURN_VALUE( 169 isolate, NewRangeError(MessageTemplate::kInvalidArgument), 170 Nothing<icu::UnicodeString>()); 171 } 172 173 icu::UnicodeString result; 174 locale_display_names()->regionDisplayName(code_str.c_str(), result); 175 return Just(result); 176 } 177}; 178 179class ScriptNames : public LocaleDisplayNamesCommon { 180 public: 181 ScriptNames(const icu::Locale& locale, JSDisplayNames::Style style, 182 bool fallback, bool dialect) 183 : LocaleDisplayNamesCommon(locale, style, fallback, dialect) {} 184 185 ~ScriptNames() override = default; 186 187 const char* type() const override { return "script"; } 188 189 Maybe<icu::UnicodeString> of(Isolate* isolate, 190 const char* code) const override { 191 std::string code_str(code); 192 if (!IsUnicodeScriptSubtag(code_str)) { 193 THROW_NEW_ERROR_RETURN_VALUE( 194 isolate, NewRangeError(MessageTemplate::kInvalidArgument), 195 Nothing<icu::UnicodeString>()); 196 } 197 198 icu::UnicodeString result; 199 locale_display_names()->scriptDisplayName(code_str.c_str(), result); 200 return Just(result); 201 } 202}; 203 204class KeyValueDisplayNames : public LocaleDisplayNamesCommon { 205 public: 206 KeyValueDisplayNames(const icu::Locale& locale, JSDisplayNames::Style style, 207 bool fallback, bool dialect, const char* key, 208 bool prevent_fallback) 209 : LocaleDisplayNamesCommon(locale, style, fallback, dialect), 210 key_(key), 211 prevent_fallback_(prevent_fallback) {} 212 213 ~KeyValueDisplayNames() override = default; 214 215 const char* type() const override { return key_.c_str(); } 216 217 Maybe<icu::UnicodeString> of(Isolate* isolate, 218 const char* code) const override { 219 std::string code_str(code); 220 icu::UnicodeString result; 221 locale_display_names()->keyValueDisplayName(key_.c_str(), code_str.c_str(), 222 result); 223 // Work around the issue that the keyValueDisplayNames ignore no 224 // substituion and always fallback. 225 if (prevent_fallback_ && (result.length() == 3) && 226 (code_str.length() == 3) && 227 (result == icu::UnicodeString(code_str.c_str(), -1, US_INV))) { 228 result.setToBogus(); 229 } 230 231 return Just(result); 232 } 233 234 private: 235 std::string key_; 236 bool prevent_fallback_; 237}; 238 239class CurrencyNames : public KeyValueDisplayNames { 240 public: 241 CurrencyNames(const icu::Locale& locale, JSDisplayNames::Style style, 242 bool fallback, bool dialect) 243 : KeyValueDisplayNames(locale, style, fallback, dialect, "currency", 244 fallback == false) {} 245 246 ~CurrencyNames() override = default; 247 248 Maybe<icu::UnicodeString> of(Isolate* isolate, 249 const char* code) const override { 250 std::string code_str(code); 251 if (!Intl::IsWellFormedCurrency(code_str)) { 252 THROW_NEW_ERROR_RETURN_VALUE( 253 isolate, NewRangeError(MessageTemplate::kInvalidArgument), 254 Nothing<icu::UnicodeString>()); 255 } 256 return KeyValueDisplayNames::of(isolate, code); 257 } 258}; 259 260class CalendarNames : public KeyValueDisplayNames { 261 public: 262 CalendarNames(const icu::Locale& locale, JSDisplayNames::Style style, 263 bool fallback, bool dialect) 264 : KeyValueDisplayNames(locale, style, fallback, dialect, "calendar", 265 false) {} 266 267 ~CalendarNames() override = default; 268 269 Maybe<icu::UnicodeString> of(Isolate* isolate, 270 const char* code) const override { 271 std::string code_str(code); 272 if (!Intl::IsWellFormedCalendar(code_str)) { 273 THROW_NEW_ERROR_RETURN_VALUE( 274 isolate, NewRangeError(MessageTemplate::kInvalidArgument), 275 Nothing<icu::UnicodeString>()); 276 } 277 return KeyValueDisplayNames::of(isolate, strcmp(code, "gregory") == 0 278 ? "gregorian" 279 : strcmp(code, "ethioaa") == 0 280 ? "ethiopic-amete-alem" 281 : code); 282 } 283}; 284 285UDateTimePGDisplayWidth StyleToUDateTimePGDisplayWidth( 286 JSDisplayNames::Style style) { 287 switch (style) { 288 case JSDisplayNames::Style::kLong: 289 return UDATPG_WIDE; 290 case JSDisplayNames::Style::kShort: 291 return UDATPG_ABBREVIATED; 292 case JSDisplayNames::Style::kNarrow: 293 return UDATPG_NARROW; 294 } 295} 296 297UDateTimePatternField StringToUDateTimePatternField(const char* code) { 298 switch (code[0]) { 299 case 'd': 300 if (strcmp(code, "day") == 0) return UDATPG_DAY_FIELD; 301 if (strcmp(code, "dayPeriod") == 0) return UDATPG_DAYPERIOD_FIELD; 302 break; 303 case 'e': 304 if (strcmp(code, "era") == 0) return UDATPG_ERA_FIELD; 305 break; 306 case 'h': 307 if (strcmp(code, "hour") == 0) return UDATPG_HOUR_FIELD; 308 break; 309 case 'm': 310 if (strcmp(code, "minute") == 0) return UDATPG_MINUTE_FIELD; 311 if (strcmp(code, "month") == 0) return UDATPG_MONTH_FIELD; 312 break; 313 case 'q': 314 if (strcmp(code, "quarter") == 0) return UDATPG_QUARTER_FIELD; 315 break; 316 case 's': 317 if (strcmp(code, "second") == 0) return UDATPG_SECOND_FIELD; 318 break; 319 case 't': 320 if (strcmp(code, "timeZoneName") == 0) return UDATPG_ZONE_FIELD; 321 break; 322 case 'w': 323 if (strcmp(code, "weekOfYear") == 0) return UDATPG_WEEK_OF_YEAR_FIELD; 324 if (strcmp(code, "weekday") == 0) return UDATPG_WEEKDAY_FIELD; 325 break; 326 case 'y': 327 if (strcmp(code, "year") == 0) return UDATPG_YEAR_FIELD; 328 break; 329 default: 330 break; 331 } 332 return UDATPG_FIELD_COUNT; 333} 334 335class DateTimeFieldNames : public DisplayNamesInternal { 336 public: 337 DateTimeFieldNames(const icu::Locale& locale, JSDisplayNames::Style style, 338 bool fallback) 339 : locale_(locale), width_(StyleToUDateTimePGDisplayWidth(style)) { 340 UErrorCode status = U_ZERO_ERROR; 341 generator_.reset( 342 icu::DateTimePatternGenerator::createInstance(locale_, status)); 343 DCHECK(U_SUCCESS(status)); 344 } 345 346 ~DateTimeFieldNames() override = default; 347 348 const char* type() const override { return "dateTimeField"; } 349 350 icu::Locale locale() const override { return locale_; } 351 352 Maybe<icu::UnicodeString> of(Isolate* isolate, 353 const char* code) const override { 354 UDateTimePatternField field = StringToUDateTimePatternField(code); 355 if (field == UDATPG_FIELD_COUNT) { 356 THROW_NEW_ERROR_RETURN_VALUE( 357 isolate, NewRangeError(MessageTemplate::kInvalidArgument), 358 Nothing<icu::UnicodeString>()); 359 } 360 return Just(generator_->getFieldDisplayName(field, width_)); 361 } 362 363 private: 364 icu::Locale locale_; 365 UDateTimePGDisplayWidth width_; 366 std::unique_ptr<icu::DateTimePatternGenerator> generator_; 367}; 368 369DisplayNamesInternal* CreateInternal(const icu::Locale& locale, 370 JSDisplayNames::Style style, Type type, 371 bool fallback, bool dialect) { 372 switch (type) { 373 case Type::kLanguage: 374 return new LanguageNames(locale, style, fallback, dialect); 375 case Type::kRegion: 376 return new RegionNames(locale, style, fallback, false); 377 case Type::kScript: 378 return new ScriptNames(locale, style, fallback, false); 379 case Type::kCurrency: 380 return new CurrencyNames(locale, style, fallback, false); 381 case Type::kCalendar: 382 return new CalendarNames(locale, style, fallback, false); 383 case Type::kDateTimeField: 384 return new DateTimeFieldNames(locale, style, fallback); 385 default: 386 UNREACHABLE(); 387 } 388} 389 390} // anonymous namespace 391 392// ecma402 #sec-Intl.DisplayNames 393MaybeHandle<JSDisplayNames> JSDisplayNames::New(Isolate* isolate, 394 Handle<Map> map, 395 Handle<Object> locales, 396 Handle<Object> input_options) { 397 const char* service = "Intl.DisplayNames"; 398 Factory* factory = isolate->factory(); 399 400 Handle<JSReceiver> options; 401 // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). 402 Maybe<std::vector<std::string>> maybe_requested_locales = 403 Intl::CanonicalizeLocaleList(isolate, locales); 404 MAYBE_RETURN(maybe_requested_locales, Handle<JSDisplayNames>()); 405 std::vector<std::string> requested_locales = 406 maybe_requested_locales.FromJust(); 407 408 // 4. Let options be ? GetOptionsObject(options). 409 ASSIGN_RETURN_ON_EXCEPTION(isolate, options, 410 GetOptionsObject(isolate, input_options, service), 411 JSDisplayNames); 412 413 // Note: No need to create a record. It's not observable. 414 // 5. Let opt be a new Record. 415 416 // 6. Let localeData be %DisplayNames%.[[LocaleData]]. 417 418 // 7. Let matcher be ? GetOption(options, "localeMatcher", "string", « 419 // "lookup", "best fit" », "best fit"). 420 Maybe<Intl::MatcherOption> maybe_locale_matcher = 421 Intl::GetLocaleMatcher(isolate, options, service); 422 MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSDisplayNames>()); 423 424 // 8. Set opt.[[localeMatcher]] to matcher. 425 Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); 426 427 // ecma402/#sec-Intl.DisplayNames-internal-slots 428 // The value of the [[RelevantExtensionKeys]] internal slot is 429 // « ». 430 std::set<std::string> relevant_extension_keys = {}; 431 // 9. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], 432 // requestedLocales, opt, %DisplayNames%.[[RelevantExtensionKeys]]). 433 Maybe<Intl::ResolvedLocale> maybe_resolve_locale = 434 Intl::ResolveLocale(isolate, JSDisplayNames::GetAvailableLocales(), 435 requested_locales, matcher, relevant_extension_keys); 436 if (maybe_resolve_locale.IsNothing()) { 437 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError), 438 JSDisplayNames); 439 } 440 Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); 441 442 icu::Locale icu_locale = r.icu_locale; 443 444 // 10. Let s be ? GetOption(options, "style", "string", 445 // «"long", "short", "narrow"», "long"). 446 Maybe<Style> maybe_style = GetStringOption<Style>( 447 isolate, options, "style", service, {"long", "short", "narrow"}, 448 {Style::kLong, Style::kShort, Style::kNarrow}, Style::kLong); 449 MAYBE_RETURN(maybe_style, MaybeHandle<JSDisplayNames>()); 450 Style style_enum = maybe_style.FromJust(); 451 452 // 11. Set displayNames.[[Style]] to style. 453 454 // 12. Let type be ? GetOption(options, "type", "string", « "language", 455 // "region", "script", "currency" , "calendar", "dateTimeField", "unit"», 456 // undefined). 457 Maybe<Type> maybe_type = GetStringOption<Type>( 458 isolate, options, "type", service, 459 {"language", "region", "script", "currency", "calendar", "dateTimeField"}, 460 {Type::kLanguage, Type::kRegion, Type::kScript, Type::kCurrency, 461 Type::kCalendar, Type::kDateTimeField}, 462 Type::kUndefined); 463 MAYBE_RETURN(maybe_type, MaybeHandle<JSDisplayNames>()); 464 Type type_enum = maybe_type.FromJust(); 465 466 // 13. If type is undefined, throw a TypeError exception. 467 if (type_enum == Type::kUndefined) { 468 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidArgument), 469 JSDisplayNames); 470 } 471 472 // 14. Set displayNames.[[Type]] to type. 473 474 // 15. Let fallback be ? GetOption(options, "fallback", "string", 475 // « "code", "none" », "code"). 476 Maybe<Fallback> maybe_fallback = GetStringOption<Fallback>( 477 isolate, options, "fallback", service, {"code", "none"}, 478 {Fallback::kCode, Fallback::kNone}, Fallback::kCode); 479 MAYBE_RETURN(maybe_fallback, MaybeHandle<JSDisplayNames>()); 480 Fallback fallback_enum = maybe_fallback.FromJust(); 481 482 // 16. Set displayNames.[[Fallback]] to fallback. 483 484 LanguageDisplay language_display_enum = LanguageDisplay::kDialect; 485 // 24. Let languageDisplay be ? GetOption(options, "languageDisplay", 486 // "string", « "dialect", "standard" », "dialect"). 487 Maybe<LanguageDisplay> maybe_language_display = 488 GetStringOption<LanguageDisplay>( 489 isolate, options, "languageDisplay", service, {"dialect", "standard"}, 490 {LanguageDisplay::kDialect, LanguageDisplay::kStandard}, 491 LanguageDisplay::kDialect); 492 MAYBE_RETURN(maybe_language_display, MaybeHandle<JSDisplayNames>()); 493 // 25. If type is "language", then 494 if (type_enum == Type::kLanguage) { 495 // a. Set displayNames.[[LanguageDisplay]] to languageDisplay. 496 language_display_enum = maybe_language_display.FromJust(); 497 } 498 499 // Set displayNames.[[Fallback]] to fallback. 500 501 // 17. Set displayNames.[[Locale]] to the value of r.[[Locale]]. 502 503 // Let dataLocale be r.[[dataLocale]]. 504 505 // Let dataLocaleData be localeData.[[<dataLocale>]]. 506 507 // Let types be dataLocaleData.[[types]]. 508 509 // Assert: types is a Record (see 1.3.3). 510 511 // Let typeFields be types.[[<type>]]. 512 513 // Assert: typeFields is a Record (see 1.3.3). 514 515 // Let styleFields be typeFields.[[<style>]]. 516 517 // Assert: styleFields is a Record (see 1.3.3). 518 519 // Set displayNames.[[Fields]] to styleFields. 520 521 DisplayNamesInternal* internal = CreateInternal( 522 icu_locale, style_enum, type_enum, fallback_enum == Fallback::kCode, 523 language_display_enum == LanguageDisplay::kDialect); 524 if (internal == nullptr) { 525 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), 526 JSDisplayNames); 527 } 528 529 Handle<Managed<DisplayNamesInternal>> managed_internal = 530 Managed<DisplayNamesInternal>::FromRawPtr(isolate, 0, internal); 531 532 Handle<JSDisplayNames> display_names = 533 Handle<JSDisplayNames>::cast(factory->NewFastOrSlowJSObjectFromMap(map)); 534 display_names->set_flags(0); 535 display_names->set_style(style_enum); 536 display_names->set_fallback(fallback_enum); 537 display_names->set_language_display(language_display_enum); 538 539 DisallowGarbageCollection no_gc; 540 display_names->set_internal(*managed_internal); 541 542 // Return displayNames. 543 return display_names; 544} 545 546// ecma402 #sec-Intl.DisplayNames.prototype.resolvedOptions 547Handle<JSObject> JSDisplayNames::ResolvedOptions( 548 Isolate* isolate, Handle<JSDisplayNames> display_names) { 549 Factory* factory = isolate->factory(); 550 // 4. Let options be ! ObjectCreate(%ObjectPrototype%). 551 Handle<JSObject> options = factory->NewJSObject(isolate->object_function()); 552 553 DisplayNamesInternal* internal = display_names->internal().raw(); 554 555 Maybe<std::string> maybe_locale = Intl::ToLanguageTag(internal->locale()); 556 DCHECK(maybe_locale.IsJust()); 557 Handle<String> locale = isolate->factory()->NewStringFromAsciiChecked( 558 maybe_locale.FromJust().c_str()); 559 Handle<String> style = display_names->StyleAsString(); 560 Handle<String> type = factory->NewStringFromAsciiChecked(internal->type()); 561 Handle<String> fallback = display_names->FallbackAsString(); 562 Handle<String> language_display = display_names->LanguageDisplayAsString(); 563 564 Maybe<bool> maybe_create_locale = JSReceiver::CreateDataProperty( 565 isolate, options, factory->locale_string(), locale, Just(kDontThrow)); 566 DCHECK(maybe_create_locale.FromJust()); 567 USE(maybe_create_locale); 568 569 Maybe<bool> maybe_create_style = JSReceiver::CreateDataProperty( 570 isolate, options, factory->style_string(), style, Just(kDontThrow)); 571 DCHECK(maybe_create_style.FromJust()); 572 USE(maybe_create_style); 573 574 Maybe<bool> maybe_create_type = JSReceiver::CreateDataProperty( 575 isolate, options, factory->type_string(), type, Just(kDontThrow)); 576 DCHECK(maybe_create_type.FromJust()); 577 USE(maybe_create_type); 578 579 Maybe<bool> maybe_create_fallback = JSReceiver::CreateDataProperty( 580 isolate, options, factory->fallback_string(), fallback, Just(kDontThrow)); 581 DCHECK(maybe_create_fallback.FromJust()); 582 USE(maybe_create_fallback); 583 584 if (std::strcmp("language", internal->type()) == 0) { 585 Maybe<bool> maybe_create_language_display = 586 JSReceiver::CreateDataProperty(isolate, options, 587 factory->languageDisplay_string(), 588 language_display, Just(kDontThrow)); 589 DCHECK(maybe_create_language_display.FromJust()); 590 USE(maybe_create_language_display); 591 } 592 593 return options; 594} 595 596// ecma402 #sec-Intl.DisplayNames.prototype.of 597MaybeHandle<Object> JSDisplayNames::Of(Isolate* isolate, 598 Handle<JSDisplayNames> display_names, 599 Handle<Object> code_obj) { 600 Handle<String> code; 601 ASSIGN_RETURN_ON_EXCEPTION(isolate, code, Object::ToString(isolate, code_obj), 602 Object); 603 DisplayNamesInternal* internal = display_names->internal().raw(); 604 Maybe<icu::UnicodeString> maybe_result = 605 internal->of(isolate, code->ToCString().get()); 606 MAYBE_RETURN(maybe_result, Handle<Object>()); 607 icu::UnicodeString result = maybe_result.FromJust(); 608 if (result.isBogus()) { 609 return isolate->factory()->undefined_value(); 610 } 611 return Intl::ToString(isolate, result).ToHandleChecked(); 612} 613 614namespace { 615 616struct CheckCalendar { 617 static const char* key() { return "calendar"; } 618 static const char* path() { return nullptr; } 619}; 620 621} // namespace 622 623const std::set<std::string>& JSDisplayNames::GetAvailableLocales() { 624 static base::LazyInstance<Intl::AvailableLocales<CheckCalendar>>::type 625 available_locales = LAZY_INSTANCE_INITIALIZER; 626 return available_locales.Pointer()->Get(); 627} 628 629Handle<String> JSDisplayNames::StyleAsString() const { 630 switch (style()) { 631 case Style::kLong: 632 return GetReadOnlyRoots().long_string_handle(); 633 case Style::kShort: 634 return GetReadOnlyRoots().short_string_handle(); 635 case Style::kNarrow: 636 return GetReadOnlyRoots().narrow_string_handle(); 637 } 638 UNREACHABLE(); 639} 640 641Handle<String> JSDisplayNames::FallbackAsString() const { 642 switch (fallback()) { 643 case Fallback::kCode: 644 return GetReadOnlyRoots().code_string_handle(); 645 case Fallback::kNone: 646 return GetReadOnlyRoots().none_string_handle(); 647 } 648 UNREACHABLE(); 649} 650 651Handle<String> JSDisplayNames::LanguageDisplayAsString() const { 652 switch (language_display()) { 653 case LanguageDisplay::kDialect: 654 return GetReadOnlyRoots().dialect_string_handle(); 655 case LanguageDisplay::kStandard: 656 return GetReadOnlyRoots().standard_string_handle(); 657 } 658 UNREACHABLE(); 659} 660 661} // namespace internal 662} // namespace v8 663