diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index bf6f945a9fe..0fb65be1a3e 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -355,6 +355,7 @@ namespace JS { P(notation) \ P(now) \ P(numberingSystem) \ + P(numberingSystems) \ P(numeric) \ P(of) \ P(offset) \ diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp index 287ee784731..7b032afc46e 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp @@ -126,4 +126,23 @@ Array* hour_cycles_of_locale(GlobalObject& global_object, Locale const& locale_o return create_array_from_list_or_restricted(global_object, move(list), move(restricted)); } +// 1.1.5 NumberingSystemsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-numbering-systems-of-locale +Array* numbering_systems_of_locale(GlobalObject& global_object, Locale const& locale_object) +{ + // 1. Let restricted be loc.[[NumberingSystem]]. + Optional restricted = locale_object.has_numbering_system() ? locale_object.numbering_system() : Optional {}; + + // 2. Let locale be loc.[[Locale]]. + auto const& locale = locale_object.locale(); + + // 3. Assert: locale matches the unicode_locale_id production. + VERIFY(Unicode::parse_unicode_locale_id(locale).has_value()); + + // 4. Let list be a List of 1 or more unique canonical numbering system identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, sorted in descending preference of those in common use for formatting numeric values in locale. + auto list = Unicode::get_keywords_for_locale(locale, "nu"sv); + + // 5. Return ! CreateArrayFromListOrRestricted( list, restricted ). + return create_array_from_list_or_restricted(global_object, move(list), move(restricted)); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Locale.h b/Userland/Libraries/LibJS/Runtime/Intl/Locale.h index e83ba1f0c63..6db49aa405d 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/Locale.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/Locale.h @@ -77,5 +77,6 @@ private: Array* calendars_of_locale(GlobalObject& global_object, Locale const& locale); Array* collations_of_locale(GlobalObject& global_object, Locale const& locale); Array* hour_cycles_of_locale(GlobalObject& global_object, Locale const& locale); +Array* numbering_systems_of_locale(GlobalObject& global_object, Locale const& locale); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp index ab552447e81..768595b67c1 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp @@ -42,6 +42,7 @@ void LocalePrototype::initialize(GlobalObject& global_object) define_native_accessor(vm.names.hourCycle, hour_cycle, {}, Attribute::Configurable); define_native_accessor(vm.names.hourCycles, hour_cycles, {}, Attribute::Configurable); define_native_accessor(vm.names.numberingSystem, numbering_system, {}, Attribute::Configurable); + define_native_accessor(vm.names.numberingSystems, numbering_systems, {}, Attribute::Configurable); define_native_accessor(vm.names.numeric, numeric, {}, Attribute::Configurable); define_native_accessor(vm.names.language, language, {}, Attribute::Configurable); define_native_accessor(vm.names.script, script, {}, Attribute::Configurable); @@ -206,11 +207,13 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region) #define JS_ENUMERATE_LOCALE_INFO_PROPERTIES \ __JS_ENUMERATE(calendars) \ __JS_ENUMERATE(collations) \ - __JS_ENUMERATE(hour_cycles) + __JS_ENUMERATE(hour_cycles) \ + __JS_ENUMERATE(numbering_systems) // 1.4.16 get Intl.Locale.prototype.calendars, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.calendars // 1.4.17 get Intl.Locale.prototype.collations, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.collations // 1.4.18 get Intl.Locale.prototype.hourCycles, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.hourCycles +// 1.4.19 get Intl.Locale.prototype.numberingSystems, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.numberingSystems #define __JS_ENUMERATE(keyword) \ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \ { \ diff --git a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h index c999a7422ba..5e3af11f973 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h +++ b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h @@ -33,6 +33,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(hour_cycle); JS_DECLARE_NATIVE_FUNCTION(hour_cycles); JS_DECLARE_NATIVE_FUNCTION(numbering_system); + JS_DECLARE_NATIVE_FUNCTION(numbering_systems); JS_DECLARE_NATIVE_FUNCTION(numeric); JS_DECLARE_NATIVE_FUNCTION(language); JS_DECLARE_NATIVE_FUNCTION(script); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.numberingSystems.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.numberingSystems.js new file mode 100644 index 00000000000..473f596937b --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.numberingSystems.js @@ -0,0 +1,35 @@ +describe("errors", () => { + test("called on non-Locale object", () => { + expect(() => { + Intl.Locale.prototype.numberingSystems; + }).toThrowWithMessage(TypeError, "Not an object of type Intl.Locale"); + }); +}); + +describe("normal behavior", () => { + test("basic functionality", () => { + expect(Array.isArray(new Intl.Locale("en").numberingSystems)).toBeTrue(); + expect(new Intl.Locale("en").numberingSystems).toEqual(["latn"]); + + expect(Array.isArray(new Intl.Locale("ar").numberingSystems)).toBeTrue(); + expect(new Intl.Locale("ar").numberingSystems).toEqual(["arab", "latn"]); + }); + + test("extension keyword overrides default data", () => { + expect(new Intl.Locale("en-u-nu-deva").numberingSystems).toEqual(["deva"]); + expect(new Intl.Locale("en", { numberingSystem: "deva" }).numberingSystems).toEqual([ + "deva", + ]); + + expect(new Intl.Locale("ar-u-nu-bali").numberingSystems).toEqual(["bali"]); + expect(new Intl.Locale("ar", { numberingSystem: "bali" }).numberingSystems).toEqual([ + "bali", + ]); + + // Invalid numberingSystems also take precedence. + expect(new Intl.Locale("en-u-nu-ladybird").numberingSystems).toEqual(["ladybird"]); + expect(new Intl.Locale("en", { numberingSystem: "ladybird" }).numberingSystems).toEqual([ + "ladybird", + ]); + }); +});