// Copyright 2019 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_INTL_SUPPORT #error Internationalization is expected to be enabled. #endif // V8_INTL_SUPPORT #include <memory> #include <vector> #include "src/objects/js-display-names-inl.h" #include "src/objects/js-display-names.h" #include "src/execution/isolate.h" #include "src/heap/factory.h" #include "src/objects/intl-objects.h" #include "src/objects/managed.h" #include "src/objects/objects-inl.h" #include "unicode/dtfmtsym.h" #include "unicode/dtptngen.h" #include "unicode/localebuilder.h" #include "unicode/locdspnm.h" #include "unicode/timezone.h" #include "unicode/tznames.h" #include "unicode/uloc.h" #include "unicode/unistr.h" #include "unicode/uscript.h" namespace v8 { namespace internal { namespace { // Type: identifying the types of the display names. // // ecma402/#sec-properties-of-intl-displaynames-instances enum class Type { kUndefined, kLanguage, kRegion, kScript, kCurrency, kWeekday, kMonth, kQuarter, kDayPeriod, kDateTimeField }; bool IsUnicodeScriptSubtag(const std::string& value) { UErrorCode status = U_ZERO_ERROR; icu::LocaleBuilder builder; builder.setScript(value).build(status); return U_SUCCESS(status); } bool IsUnicodeRegionSubtag(const std::string& value) { UErrorCode status = U_ZERO_ERROR; icu::LocaleBuilder builder; builder.setRegion(value).build(status); return U_SUCCESS(status); } UDisplayContext ToUDisplayContext(JSDisplayNames::Style style) { switch (style) { case JSDisplayNames::Style::kLong: return UDISPCTX_LENGTH_FULL; case JSDisplayNames::Style::kShort: case JSDisplayNames::Style::kNarrow: return UDISPCTX_LENGTH_SHORT; } } } // anonymous namespace // Abstract class for all different types. class DisplayNamesInternal { public: DisplayNamesInternal() = default; virtual ~DisplayNamesInternal() = default; virtual const char* type() const = 0; virtual icu::Locale locale() const = 0; virtual Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const = 0; virtual const char* calendar() const { return nullptr; } }; namespace { class LocaleDisplayNamesCommon : public DisplayNamesInternal { public: LocaleDisplayNamesCommon(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback) : style_(style) { UDisplayContext sub = fallback ? UDISPCTX_SUBSTITUTE : UDISPCTX_NO_SUBSTITUTE; UDisplayContext display_context[] = {ToUDisplayContext(style_), UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_NONE, sub}; ldn_.reset( icu::LocaleDisplayNames::createInstance(locale, display_context, 4)); } ~LocaleDisplayNamesCommon() override = default; icu::Locale locale() const override { return ldn_->getLocale(); } protected: icu::LocaleDisplayNames* locale_display_names() const { return ldn_.get(); } private: std::unique_ptr<icu::LocaleDisplayNames> ldn_; JSDisplayNames::Style style_; }; class LanguageNames : public LocaleDisplayNamesCommon { public: LanguageNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback) : LocaleDisplayNamesCommon(locale, style, fallback) {} ~LanguageNames() override = default; const char* type() const override { return "language"; } Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const override { UErrorCode status = U_ZERO_ERROR; icu::Locale l = icu::Locale(icu::Locale::forLanguageTag(code, status).getBaseName()); std::string checked = l.toLanguageTag<std::string>(status); if (U_FAILURE(status)) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kInvalidArgument), Nothing<icu::UnicodeString>()); } icu::UnicodeString result; locale_display_names()->localeDisplayName(checked.c_str(), result); return Just(result); } }; class RegionNames : public LocaleDisplayNamesCommon { public: RegionNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback) : LocaleDisplayNamesCommon(locale, style, fallback) {} ~RegionNames() override = default; const char* type() const override { return "region"; } Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const override { std::string code_str(code); if (!IsUnicodeRegionSubtag(code_str)) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kInvalidArgument), Nothing<icu::UnicodeString>()); } icu::UnicodeString result; locale_display_names()->regionDisplayName(code_str.c_str(), result); return Just(result); } }; class ScriptNames : public LocaleDisplayNamesCommon { public: ScriptNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback) : LocaleDisplayNamesCommon(locale, style, fallback) {} ~ScriptNames() override = default; const char* type() const override { return "script"; } Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const override { std::string code_str(code); if (!IsUnicodeScriptSubtag(code_str)) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kInvalidArgument), Nothing<icu::UnicodeString>()); } icu::UnicodeString result; locale_display_names()->scriptDisplayName(code_str.c_str(), result); return Just(result); } }; class CurrencyNames : public LocaleDisplayNamesCommon { public: CurrencyNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback) : LocaleDisplayNamesCommon(locale, style, fallback) {} ~CurrencyNames() override = default; const char* type() const override { return "currency"; } Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const override { std::string code_str(code); if (!Intl::IsWellFormedCurrency(code_str)) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kInvalidArgument), Nothing<icu::UnicodeString>()); } icu::UnicodeString result; locale_display_names()->keyValueDisplayName("currency", code_str.c_str(), result); return Just(result); } }; UDateTimePGDisplayWidth StyleToUDateTimePGDisplayWidth( JSDisplayNames::Style style) { switch (style) { case JSDisplayNames::Style::kLong: return UDATPG_WIDE; case JSDisplayNames::Style::kShort: return UDATPG_ABBREVIATED; case JSDisplayNames::Style::kNarrow: return UDATPG_NARROW; } } UDateTimePatternField StringToUDateTimePatternField(const char* code) { switch (code[0]) { case 'd': if (strcmp(code, "day") == 0) return UDATPG_DAY_FIELD; if (strcmp(code, "dayPeriod") == 0) return UDATPG_DAYPERIOD_FIELD; break; case 'e': if (strcmp(code, "era") == 0) return UDATPG_ERA_FIELD; break; case 'h': if (strcmp(code, "hour") == 0) return UDATPG_HOUR_FIELD; break; case 'm': if (strcmp(code, "minute") == 0) return UDATPG_MINUTE_FIELD; if (strcmp(code, "month") == 0) return UDATPG_MONTH_FIELD; break; case 'q': if (strcmp(code, "quarter") == 0) return UDATPG_QUARTER_FIELD; break; case 's': if (strcmp(code, "second") == 0) return UDATPG_SECOND_FIELD; break; case 't': if (strcmp(code, "timeZoneName") == 0) return UDATPG_ZONE_FIELD; break; case 'w': if (strcmp(code, "weekOfYear") == 0) return UDATPG_WEEK_OF_YEAR_FIELD; if (strcmp(code, "weekday") == 0) return UDATPG_WEEKDAY_FIELD; break; case 'y': if (strcmp(code, "year") == 0) return UDATPG_YEAR_FIELD; break; default: break; } UNREACHABLE(); } class DateTimeFieldNames : public DisplayNamesInternal { public: DateTimeFieldNames(const icu::Locale& locale, JSDisplayNames::Style style) : locale_(locale), width_(StyleToUDateTimePGDisplayWidth(style)) { UErrorCode status = U_ZERO_ERROR; generator_.reset( icu::DateTimePatternGenerator::createInstance(locale_, status)); DCHECK(U_SUCCESS(status)); } ~DateTimeFieldNames() override = default; const char* type() const override { return "dateTimeField"; } icu::Locale locale() const override { return locale_; } Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const override { UDateTimePatternField field = StringToUDateTimePatternField(code); if (field == UDATPG_FIELD_COUNT) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kInvalidArgument), Nothing<icu::UnicodeString>()); } return Just(generator_->getFieldDisplayName(field, width_)); } private: icu::Locale locale_; UDateTimePGDisplayWidth width_; std::unique_ptr<icu::DateTimePatternGenerator> generator_; }; icu::DateFormatSymbols::DtWidthType StyleToDtWidthType( JSDisplayNames::Style style, Type type) { switch (style) { case JSDisplayNames::Style::kLong: return icu::DateFormatSymbols::WIDE; case JSDisplayNames::Style::kShort: return icu::DateFormatSymbols::SHORT; case JSDisplayNames::Style::kNarrow: if (type == Type::kQuarter) { return icu::DateFormatSymbols::ABBREVIATED; } else { return icu::DateFormatSymbols::NARROW; } } } class DateFormatSymbolsNames : public DisplayNamesInternal { public: DateFormatSymbolsNames(const char* type, const icu::Locale& locale, const icu::UnicodeString* array, int32_t length, const char* calendar) : type_(type), locale_(locale), array_(array), length_(length), calendar_(calendar) {} ~DateFormatSymbolsNames() override = default; const char* type() const override { return type_; } icu::Locale locale() const override { return locale_; } const char* calendar() const override { if (calendar_.empty()) { return nullptr; } return calendar_.c_str(); } virtual int32_t ComputeIndex(const char* code) const = 0; Maybe<icu::UnicodeString> of(Isolate* isolate, const char* code) const override { int32_t index = ComputeIndex(code); if (index < 0 || index >= length_) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kInvalidArgument), Nothing<icu::UnicodeString>()); } return Just(array_[index]); } private: const char* type_; icu::Locale locale_; const icu::UnicodeString* array_; int32_t length_; std::string calendar_; }; class WeekdayNames : public DateFormatSymbolsNames { public: WeekdayNames(const char* type, const icu::Locale& locale, const icu::UnicodeString* array, int32_t length, const char* calendar) : DateFormatSymbolsNames(type, locale, array, length, calendar) {} ~WeekdayNames() override = default; int32_t ComputeIndex(const char* code) const override { int32_t i = atoi(code); if (i == 7) return 1; if (i > 0 && i < 7) return i + 1; return -1; } }; class MonthNames : public DateFormatSymbolsNames { public: MonthNames(const char* type, const icu::Locale& locale, const icu::UnicodeString* array, int32_t length, const char* calendar) : DateFormatSymbolsNames(type, locale, array, length, calendar) {} ~MonthNames() override = default; int32_t ComputeIndex(const char* code) const override { return atoi(code) - 1; } }; class QuarterNames : public DateFormatSymbolsNames { public: QuarterNames(const char* type, const icu::Locale& locale, const icu::UnicodeString* array, int32_t length, const char* calendar) : DateFormatSymbolsNames(type, locale, array, length, calendar) {} ~QuarterNames() override = default; int32_t ComputeIndex(const char* code) const override { return atoi(code) - 1; } }; class DayPeriodNames : public DateFormatSymbolsNames { public: DayPeriodNames(const char* type, const icu::Locale& locale, const icu::UnicodeString* array, int32_t length, const char* calendar) : DateFormatSymbolsNames(type, locale, array, length, calendar) {} ~DayPeriodNames() override = default; int32_t ComputeIndex(const char* code) const override { if (strcmp("am", code) == 0) { return 0; } else if (strcmp("pm", code) == 0) { return 1; } else { return -1; } } }; const char* gWeekday = "weekday"; const char* gMonth = "month"; const char* gQuarter = "quarter"; const char* gDayPeriod = "dayPeriod"; DateFormatSymbolsNames* CreateDateFormatSymbolsNames( const icu::Locale& locale, JSDisplayNames::Style style, Type type) { UErrorCode status = U_ZERO_ERROR; std::unique_ptr<icu::DateFormatSymbols> symbols( icu::DateFormatSymbols::createForLocale(locale, status)); if (U_FAILURE(status)) { return nullptr; } icu::DateFormatSymbols::DtWidthType width_type = StyleToDtWidthType(style, type); int32_t count = 0; std::string calendar = locale.getUnicodeKeywordValue<std::string>("ca", status); switch (type) { case Type::kMonth: return new MonthNames( gMonth, locale, symbols->getMonths(count, icu::DateFormatSymbols::STANDALONE, width_type), count, calendar.c_str()); case Type::kWeekday: return new WeekdayNames( gWeekday, locale, symbols->getWeekdays(count, icu::DateFormatSymbols::STANDALONE, width_type), count, calendar.c_str()); case Type::kQuarter: return new QuarterNames( gQuarter, locale, symbols->getQuarters(count, icu::DateFormatSymbols::STANDALONE, width_type), count, calendar.c_str()); case Type::kDayPeriod: return new DayPeriodNames(gDayPeriod, locale, symbols->getAmPmStrings(count), count, calendar.c_str()); default: UNREACHABLE(); } } DisplayNamesInternal* CreateInternal(const icu::Locale& locale, JSDisplayNames::Style style, Type type, bool fallback) { switch (type) { case Type::kLanguage: return new LanguageNames(locale, style, fallback); case Type::kRegion: return new RegionNames(locale, style, fallback); case Type::kScript: return new ScriptNames(locale, style, fallback); case Type::kCurrency: return new CurrencyNames(locale, style, fallback); case Type::kDateTimeField: return new DateTimeFieldNames(locale, style); case Type::kMonth: case Type::kWeekday: case Type::kQuarter: case Type::kDayPeriod: return CreateDateFormatSymbolsNames(locale, style, type); default: UNREACHABLE(); } } } // anonymous namespace // ecma402 #sec-Intl.DisplayNames MaybeHandle<JSDisplayNames> JSDisplayNames::New(Isolate* isolate, Handle<Map> map, Handle<Object> locales, Handle<Object> input_options) { const char* service = "Intl.DisplayNames"; Factory* factory = isolate->factory(); Handle<JSReceiver> options; // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); MAYBE_RETURN(maybe_requested_locales, Handle<JSDisplayNames>()); std::vector<std::string> requested_locales = maybe_requested_locales.FromJust(); // 4. Let options be ? ToObject(options). ASSIGN_RETURN_ON_EXCEPTION(isolate, options, Object::ToObject(isolate, input_options), JSDisplayNames); // Note: No need to create a record. It's not observable. // 5. Let opt be a new Record. // 6. Let localeData be %DisplayNames%.[[LocaleData]]. // 7. Let matcher be ? GetOption(options, "localeMatcher", "string", « // "lookup", "best fit" », "best fit"). Maybe<Intl::MatcherOption> maybe_locale_matcher = Intl::GetLocaleMatcher(isolate, options, "Intl.DisplayNames"); MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSDisplayNames>()); // 8. Set opt.[[localeMatcher]] to matcher. Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); std::unique_ptr<char[]> calendar_str = nullptr; if (FLAG_harmony_intl_displaynames_date_types) { const std::vector<const char*> empty_values = {}; // Let calendar be ? GetOption(options, "calendar", // "string", undefined, undefined). Maybe<bool> maybe_calendar = Intl::GetStringOption( isolate, options, "calendar", empty_values, service, &calendar_str); MAYBE_RETURN(maybe_calendar, MaybeHandle<JSDisplayNames>()); // If calendar is not undefined, then if (maybe_calendar.FromJust() && calendar_str != nullptr) { // a. If calendar does not match the (3*8alphanum) *("-" (3*8alphanum)) // sequence, throw a RangeError exception. if (!Intl::IsWellFormedCalendar(calendar_str.get())) { THROW_NEW_ERROR( isolate, NewRangeError( MessageTemplate::kInvalid, factory->calendar_string(), factory->NewStringFromAsciiChecked(calendar_str.get())), JSDisplayNames); } } } // Set opt.[[ca]] to calendar. // ecma402/#sec-Intl.DisplayNames-internal-slots // The value of the [[RelevantExtensionKeys]] internal slot is // « "ca" ». std::set<std::string> relevant_extension_keys_ca = {"ca"}; std::set<std::string> relevant_extension_keys = {}; // 9. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], // requestedLocales, opt, %DisplayNames%.[[RelevantExtensionKeys]]). Maybe<Intl::ResolvedLocale> maybe_resolve_locale = Intl::ResolveLocale( isolate, JSDisplayNames::GetAvailableLocales(), requested_locales, matcher, FLAG_harmony_intl_displaynames_date_types ? relevant_extension_keys_ca : relevant_extension_keys); if (maybe_resolve_locale.IsNothing()) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError), JSDisplayNames); } Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); icu::Locale icu_locale = r.icu_locale; UErrorCode status = U_ZERO_ERROR; if (calendar_str != nullptr && Intl::IsValidCalendar(icu_locale, calendar_str.get())) { icu_locale.setUnicodeKeywordValue("ca", calendar_str.get(), status); DCHECK(U_SUCCESS(status)); } // 10. Let s be ? GetOption(options, "style", "string", // «"long", "short", "narrow"», "long"). Maybe<Style> maybe_style = Intl::GetStringOption<Style>( isolate, options, "style", "Intl.DisplayNames", {"long", "short", "narrow"}, {Style::kLong, Style::kShort, Style::kNarrow}, Style::kLong); MAYBE_RETURN(maybe_style, MaybeHandle<JSDisplayNames>()); Style style_enum = maybe_style.FromJust(); // 11. Set displayNames.[[Style]] to style. // 12. Let type be ? GetOption(options, "type", "string", « "language", // "region", "script", "currency", "weekday", "month", "quarter", // "dayPeriod", "dateTimeField" », undefined). Maybe<Type> maybe_type = FLAG_harmony_intl_displaynames_date_types ? Intl::GetStringOption<Type>( isolate, options, "type", "Intl.DisplayNames", {"language", "region", "script", "currency", "weekday", "month", "quarter", "dayPeriod", "dateTimeField"}, { Type::kLanguage, Type::kRegion, Type::kScript, Type::kCurrency, Type::kWeekday, Type::kMonth, Type::kQuarter, Type::kDayPeriod, Type::kDateTimeField, }, Type::kUndefined) : Intl::GetStringOption<Type>( isolate, options, "type", "Intl.DisplayNames", {"language", "region", "script", "currency"}, { Type::kLanguage, Type::kRegion, Type::kScript, Type::kCurrency, }, Type::kUndefined); MAYBE_RETURN(maybe_type, MaybeHandle<JSDisplayNames>()); Type type_enum = maybe_type.FromJust(); // 13. If type is undefined, throw a TypeError exception. if (type_enum == Type::kUndefined) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kInvalidArgument), JSDisplayNames); } // 14. Set displayNames.[[Type]] to type. // 15. Let fallback be ? GetOption(options, "fallback", "string", // « "code", "none" », "code"). Maybe<Fallback> maybe_fallback = Intl::GetStringOption<Fallback>( isolate, options, "fallback", "Intl.DisplayNames", {"code", "none"}, {Fallback::kCode, Fallback::kNone}, Fallback::kCode); MAYBE_RETURN(maybe_fallback, MaybeHandle<JSDisplayNames>()); Fallback fallback_enum = maybe_fallback.FromJust(); // 16. Set displayNames.[[Fallback]] to fallback. // 17. Set displayNames.[[Locale]] to the value of r.[[Locale]]. // Let calendar be r.[[ca]]. // Set displayNames.[[Calendar]] to calendar. // Let dataLocale be r.[[dataLocale]]. // Let dataLocaleData be localeData.[[<dataLocale>]]. // Let types be dataLocaleData.[[types]]. // Assert: types is a Record (see 1.3.3). // Let typeFields be types.[[<type>]]. // Assert: typeFields is a Record (see 1.3.3). // Let styleFields be typeFields.[[<style>]]. // Assert: styleFields is a Record (see 1.3.3). // Set displayNames.[[Fields]] to styleFields. DisplayNamesInternal* internal = CreateInternal( icu_locale, style_enum, type_enum, fallback_enum == Fallback::kCode); if (internal == nullptr) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), JSDisplayNames); } Handle<Managed<DisplayNamesInternal>> managed_internal = Managed<DisplayNamesInternal>::FromRawPtr(isolate, 0, internal); Handle<JSDisplayNames> display_names = Handle<JSDisplayNames>::cast(factory->NewFastOrSlowJSObjectFromMap(map)); display_names->set_flags(0); display_names->set_style(style_enum); display_names->set_fallback(fallback_enum); DisallowHeapAllocation no_gc; display_names->set_internal(*managed_internal); // Return displayNames. return display_names; } // ecma402 #sec-Intl.DisplayNames.prototype.resolvedOptions Handle<JSObject> JSDisplayNames::ResolvedOptions( Isolate* isolate, Handle<JSDisplayNames> display_names) { Factory* factory = isolate->factory(); // 4. Let options be ! ObjectCreate(%ObjectPrototype%). Handle<JSObject> options = factory->NewJSObject(isolate->object_function()); DisplayNamesInternal* internal = display_names->internal().raw(); Maybe<std::string> maybe_locale = Intl::ToLanguageTag(internal->locale()); DCHECK(maybe_locale.IsJust()); Handle<String> locale = isolate->factory()->NewStringFromAsciiChecked( maybe_locale.FromJust().c_str()); Handle<String> style = display_names->StyleAsString(); Handle<String> type = factory->NewStringFromAsciiChecked(internal->type()); Handle<String> fallback = display_names->FallbackAsString(); Maybe<bool> maybe_create_locale = JSReceiver::CreateDataProperty( isolate, options, factory->locale_string(), locale, Just(kDontThrow)); DCHECK(maybe_create_locale.FromJust()); USE(maybe_create_locale); if (internal->calendar() != nullptr) { Maybe<bool> maybe_create_calendar = JSReceiver::CreateDataProperty( isolate, options, factory->calendar_string(), factory->NewStringFromAsciiChecked(internal->calendar()), Just(kDontThrow)); DCHECK(maybe_create_calendar.FromJust()); USE(maybe_create_calendar); } Maybe<bool> maybe_create_style = JSReceiver::CreateDataProperty( isolate, options, factory->style_string(), style, Just(kDontThrow)); DCHECK(maybe_create_style.FromJust()); USE(maybe_create_style); Maybe<bool> maybe_create_type = JSReceiver::CreateDataProperty( isolate, options, factory->type_string(), type, Just(kDontThrow)); DCHECK(maybe_create_type.FromJust()); USE(maybe_create_type); Maybe<bool> maybe_create_fallback = JSReceiver::CreateDataProperty( isolate, options, factory->fallback_string(), fallback, Just(kDontThrow)); DCHECK(maybe_create_fallback.FromJust()); USE(maybe_create_fallback); return options; } // ecma402 #sec-Intl.DisplayNames.prototype.of MaybeHandle<Object> JSDisplayNames::Of(Isolate* isolate, Handle<JSDisplayNames> display_names, Handle<Object> code_obj) { Handle<String> code; ASSIGN_RETURN_ON_EXCEPTION(isolate, code, Object::ToString(isolate, code_obj), Object); DisplayNamesInternal* internal = display_names->internal().raw(); Maybe<icu::UnicodeString> maybe_result = internal->of(isolate, code->ToCString().get()); MAYBE_RETURN(maybe_result, Handle<Object>()); icu::UnicodeString result = maybe_result.FromJust(); if (result.isBogus()) { return isolate->factory()->undefined_value(); } return Intl::ToString(isolate, result).ToHandleChecked(); } namespace { struct CheckCalendar { static const char* key() { return "calendar"; } static const char* path() { return nullptr; } }; } // namespace const std::set<std::string>& JSDisplayNames::GetAvailableLocales() { static base::LazyInstance<Intl::AvailableLocales<CheckCalendar>>::type available_locales = LAZY_INSTANCE_INITIALIZER; return available_locales.Pointer()->Get(); } Handle<String> JSDisplayNames::StyleAsString() const { switch (style()) { case Style::kLong: return GetReadOnlyRoots().long_string_handle(); case Style::kShort: return GetReadOnlyRoots().short_string_handle(); case Style::kNarrow: return GetReadOnlyRoots().narrow_string_handle(); } UNREACHABLE(); } Handle<String> JSDisplayNames::FallbackAsString() const { switch (fallback()) { case Fallback::kCode: return GetReadOnlyRoots().code_string_handle(); case Fallback::kNone: return GetReadOnlyRoots().none_string_handle(); } UNREACHABLE(); } } // namespace internal } // namespace v8