blob: 6532b0c25e1158e24c7e73f1b0ecffc52c018558 [file] [log] [blame]
// 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