diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 4de5b802e1..4ecb28b846 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -294,6 +294,7 @@ namespace JS { P(keyFor) \ P(keys) \ P(language) \ + P(languageDisplay) \ P(largestUnit) \ P(lastIndex) \ P(lastIndexOf) \ diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.cpp index b6769a4a94..2804f31c24 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.cpp @@ -53,6 +53,10 @@ void DisplayNames::set_type(StringView type) m_type = Type::Script; else if (type == "currency"sv) m_type = Type::Currency; + else if (type == "calendar"sv) + m_type = Type::Calendar; + else if (type == "dateTimeField"sv) + m_type = Type::DateTimeField; else VERIFY_NOT_REACHED(); } @@ -68,6 +72,10 @@ StringView DisplayNames::type_string() const return "script"sv; case Type::Currency: return "currency"sv; + case Type::Calendar: + return "calendar"sv; + case Type::DateTimeField: + return "dateTimeField"sv; default: VERIFY_NOT_REACHED(); } @@ -95,6 +103,30 @@ StringView DisplayNames::fallback_string() const } } +void DisplayNames::set_language_display(StringView language_display) +{ + if (language_display == "dialect"sv) + m_language_display = LanguageDisplay::Dialect; + else if (language_display == "standard"sv) + m_language_display = LanguageDisplay::Standard; + else + VERIFY_NOT_REACHED(); +} + +StringView DisplayNames::language_display_string() const +{ + VERIFY(m_language_display.has_value()); + + switch (*m_language_display) { + case LanguageDisplay::Dialect: + return "dialect"sv; + case LanguageDisplay::Standard: + return "standard"sv; + default: + VERIFY_NOT_REACHED(); + } +} + // 12.1.1 CanonicalCodeForDisplayNames ( type, code ), https://tc39.es/ecma402/#sec-canonicalcodefordisplaynames ThrowCompletionOr canonical_code_for_display_names(GlobalObject& global_object, DisplayNames::Type type, StringView code) { diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.h b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.h index 10e62bc522..22fdbfa488 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNames.h @@ -1,11 +1,12 @@ /* - * Copyright (c) 2021, Tim Flynn + * Copyright (c) 2021-2022, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include #include #include #include @@ -28,6 +29,8 @@ class DisplayNames final : public Object { Region, Script, Currency, + Calendar, + DateTimeField, }; enum class Fallback { @@ -36,6 +39,11 @@ class DisplayNames final : public Object { Code, }; + enum class LanguageDisplay { + Dialect, + Standard, + }; + public: DisplayNames(Object& prototype); virtual ~DisplayNames() override = default; @@ -55,11 +63,17 @@ public: void set_fallback(StringView fallback); StringView fallback_string() const; + bool has_language_display() const { return m_language_display.has_value(); } + LanguageDisplay language_display() const { return *m_language_display; } + void set_language_display(StringView language_display); + StringView language_display_string() const; + private: - String m_locale; // [[Locale]] - Style m_style { Style::Invalid }; // [[Style]] - Type m_type { Type::Invalid }; // [[Type]] - Fallback m_fallback { Fallback::Invalid }; // [[Fallback]] + String m_locale; // [[Locale]] + Style m_style { Style::Invalid }; // [[Style]] + Type m_type { Type::Invalid }; // [[Type]] + Fallback m_fallback { Fallback::Invalid }; // [[Fallback]] + Optional m_language_display {}; // [[LanguageDisplay]] }; ThrowCompletionOr canonical_code_for_display_names(GlobalObject& global_object, DisplayNames::Type type, StringView code); diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp index 24856e7058..875b97293e 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DisplayNamesConstructor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Tim Flynn + * Copyright (c) 2021-2022, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -52,7 +52,7 @@ ThrowCompletionOr DisplayNamesConstructor::construct(FunctionObject& ne auto locale_value = vm.argument(0); auto options_value = vm.argument(1); - // 2. Let displayNames be ? OrdinaryCreateFromConstructor(NewTarget, "%DisplayNames.prototype%", « [[InitializedDisplayNames]], [[Locale]], [[Style]], [[Type]], [[Fallback]], [[Fields]] »). + // 2. Let displayNames be ? OrdinaryCreateFromConstructor(NewTarget, "%DisplayNames.prototype%", « [[InitializedDisplayNames]], [[Locale]], [[Style]], [[Type]], [[Fallback]], [[LanguageDisplay]], [[Fields]] »). auto* display_names = TRY(ordinary_create_from_constructor(global_object, new_target, &GlobalObject::intl_display_names_prototype)); // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). @@ -85,8 +85,8 @@ ThrowCompletionOr DisplayNamesConstructor::construct(FunctionObject& ne // 12. Set displayNames.[[Style]] to style. display_names->set_style(style.as_string().string()); - // 13. Let type be ? GetOption(options, "type", "string", « "language", "region", "script", "currency" », undefined). - auto type = TRY(get_option(global_object, *options, vm.names.type, Value::Type::String, { "language"sv, "region"sv, "script"sv, "currency"sv }, Empty {})); + // 13. Let type be ? GetOption(options, "type", "string", « "language", "region", "script", "currency", "calendar", "dateTimeField" », undefined). + auto type = TRY(get_option(global_object, *options, vm.names.type, Value::Type::String, { "language"sv, "region"sv, "script"sv, "currency"sv, "calendar"sv, "dateTimeField"sv }, Empty {})); // 14. If type is undefined, throw a TypeError exception. if (type.is_undefined()) @@ -104,10 +104,33 @@ ThrowCompletionOr DisplayNamesConstructor::construct(FunctionObject& ne // 18. Set displayNames.[[Locale]] to r.[[locale]]. display_names->set_locale(move(result.locale)); - // Note: The remaining steps are skipped in favor of deferring to LibUnicode. We could copy - // the data from LibUnicode to the DisplayNames object, but for now we do not do that. + // Note: Several of the steps below are skipped in favor of deferring to LibUnicode. - // 28. Return displayNames. + // 19. Let dataLocale be r.[[dataLocale]]. + // 20. Let dataLocaleData be localeData.[[]]. + // 21. Let types be dataLocaleData.[[types]]. + // 22. Assert: types is a Record (see 12.4.3). + + // 23. Let languageDisplay be ? GetOption(options, "languageDisplay", "string", « "dialect", "standard" », "dialect"). + auto language_display = TRY(get_option(global_object, *options, vm.names.languageDisplay, Value::Type::String, { "dialect"sv, "standard"sv }, "dialect"sv)); + + // 24. Let typeFields be types.[[]]. + // 25. Assert: typeFields is a Record (see 12.4.3). + + // 26. If type is "language", then + if (display_names->type() == DisplayNames::Type::Language) { + // a. Set displayNames.[[LanguageDisplay]] to languageDisplay. + display_names->set_language_display(language_display.as_string().string()); + + // b. Let typeFields be typeFields.[[]]. + // c. Assert: typeFields is a Record (see 12.4.3). + } + + // 27. Let styleFields be typeFields.[[