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
32 namespace v8 {
33 namespace internal {
34
35 namespace {
36 // Type: identifying the types of the display names.
37 //
38 // ecma402/#sec-properties-of-intl-displaynames-instances
39 enum class Type {
40 kUndefined,
41 kLanguage,
42 kRegion,
43 kScript,
44 kCurrency,
45 kCalendar,
46 kDateTimeField
47 };
48
IsUnicodeScriptSubtag(const std::string& value)49 bool 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
IsUnicodeRegionSubtag(const std::string& value)56 bool 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
ToUDisplayContext(JSDisplayNames::Style style)63 UDisplayContext 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.
76 class 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
86 namespace {
87
88 class LocaleDisplayNamesCommon : public DisplayNamesInternal {
89 public:
LocaleDisplayNamesCommon(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect)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:
locale_display_names() const110 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
117 class LanguageNames : public LocaleDisplayNamesCommon {
118 public:
LanguageNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect)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
154 class RegionNames : public LocaleDisplayNamesCommon {
155 public:
RegionNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect)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
179 class ScriptNames : public LocaleDisplayNamesCommon {
180 public:
ScriptNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect)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
204 class KeyValueDisplayNames : public LocaleDisplayNamesCommon {
205 public:
KeyValueDisplayNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect, const char* key, bool prevent_fallback)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
239 class CurrencyNames : public KeyValueDisplayNames {
240 public:
CurrencyNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect)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
260 class CalendarNames : public KeyValueDisplayNames {
261 public:
CalendarNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback, bool dialect)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
StyleToUDateTimePGDisplayWidth( JSDisplayNames::Style style)285 UDateTimePGDisplayWidth 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
StringToUDateTimePatternField(const char* code)297 UDateTimePatternField 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
335 class DateTimeFieldNames : public DisplayNamesInternal {
336 public:
DateTimeFieldNames(const icu::Locale& locale, JSDisplayNames::Style style, bool fallback)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
CreateInternal(const icu::Locale& locale, JSDisplayNames::Style style, Type type, bool fallback, bool dialect)369 DisplayNamesInternal* 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
New(Isolate* isolate, Handle<Map> map, Handle<Object> locales, Handle<Object> input_options)393 MaybeHandle<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
ResolvedOptions( Isolate* isolate, Handle<JSDisplayNames> display_names)547 Handle<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
Of(Isolate* isolate, Handle<JSDisplayNames> display_names, Handle<Object> code_obj)597 MaybeHandle<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
614 namespace {
615
616 struct CheckCalendar {
keyv8::internal::__anon14836::CheckCalendar617 static const char* key() { return "calendar"; }
pathv8::internal::__anon14836::CheckCalendar618 static const char* path() { return nullptr; }
619 };
620
621 } // namespace
622
GetAvailableLocales()623 const 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
StyleAsString() const629 Handle<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
FallbackAsString() const641 Handle<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
LanguageDisplayAsString() const651 Handle<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