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