summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-07-05 13:41:08 -0400
committerLinus Groh <mail@linusgroh.de>2022-07-06 16:56:42 +0200
commitee2be5895fc41e3fcd9b7bc71ab51ed0588b8a43 (patch)
treefdae159dc8c7c0737dc363b48dce3f84c63c33e9 /Userland
parent4d32f38a76f81f77d6a19d39df3303c813c31f96 (diff)
downloadserenity-ee2be5895fc41e3fcd9b7bc71ab51ed0588b8a43.zip
LibJS: Implement Intl.Locale.prototype.hourCycles property
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp19
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/Locale.h1
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp5
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h1
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.hourCycles.js29
6 files changed, 55 insertions, 1 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
index f3ef49871c..bf6f945a9f 100644
--- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
+++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
@@ -258,6 +258,7 @@ namespace JS {
P(hour) \
P(hour12) \
P(hourCycle) \
+ P(hourCycles) \
P(hours) \
P(hoursDisplay) \
P(hoursInDay) \
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp b/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp
index 27dd2fafb5..287ee78473 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/Locale.cpp
@@ -107,4 +107,23 @@ Array* collations_of_locale(GlobalObject& global_object, Locale const& locale_ob
return create_array_from_list_or_restricted(global_object, move(list), move(restricted));
}
+// 1.1.4 HourCyclesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-hour-cycles-of-locale
+Array* hour_cycles_of_locale(GlobalObject& global_object, Locale const& locale_object)
+{
+ // 1. Let restricted be loc.[[HourCycle]].
+ Optional<String> restricted = locale_object.has_hour_cycle() ? locale_object.hour_cycle() : Optional<String> {};
+
+ // 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 hour cycle identifiers, which must be lower case String values indicating either the 12-hour format ("h11", "h12") or the 24-hour format ("h23", "h24"), sorted in descending preference of those in common use for date and time formatting in locale.
+ auto list = Unicode::get_keywords_for_locale(locale, "hc"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 1e8430e33e..e83ba1f0c6 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/Locale.h
+++ b/Userland/Libraries/LibJS/Runtime/Intl/Locale.h
@@ -76,5 +76,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);
}
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp
index 099598de8a..ab552447e8 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.cpp
@@ -40,6 +40,7 @@ void LocalePrototype::initialize(GlobalObject& global_object)
define_native_accessor(vm.names.collation, collation, {}, Attribute::Configurable);
define_native_accessor(vm.names.collations, collations, {}, Attribute::Configurable);
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.numeric, numeric, {}, Attribute::Configurable);
define_native_accessor(vm.names.language, language, {}, Attribute::Configurable);
@@ -204,10 +205,12 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
#define JS_ENUMERATE_LOCALE_INFO_PROPERTIES \
__JS_ENUMERATE(calendars) \
- __JS_ENUMERATE(collations)
+ __JS_ENUMERATE(collations) \
+ __JS_ENUMERATE(hour_cycles)
// 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
#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 6c304d3a83..c999a7422b 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h
+++ b/Userland/Libraries/LibJS/Runtime/Intl/LocalePrototype.h
@@ -31,6 +31,7 @@ private:
JS_DECLARE_NATIVE_FUNCTION(collation);
JS_DECLARE_NATIVE_FUNCTION(collations);
JS_DECLARE_NATIVE_FUNCTION(hour_cycle);
+ JS_DECLARE_NATIVE_FUNCTION(hour_cycles);
JS_DECLARE_NATIVE_FUNCTION(numbering_system);
JS_DECLARE_NATIVE_FUNCTION(numeric);
JS_DECLARE_NATIVE_FUNCTION(language);
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.hourCycles.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.hourCycles.js
new file mode 100644
index 0000000000..ba6620a118
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/Locale/Locale.prototype.hourCycles.js
@@ -0,0 +1,29 @@
+describe("errors", () => {
+ test("called on non-Locale object", () => {
+ expect(() => {
+ Intl.Locale.prototype.hourCycles;
+ }).toThrowWithMessage(TypeError, "Not an object of type Intl.Locale");
+ });
+});
+
+describe("normal behavior", () => {
+ test("basic functionality", () => {
+ expect(Array.isArray(new Intl.Locale("en").hourCycles)).toBeTrue();
+ expect(new Intl.Locale("en").hourCycles).toContain("h12");
+
+ expect(Array.isArray(new Intl.Locale("ha").hourCycles)).toBeTrue();
+ expect(new Intl.Locale("ha").hourCycles).toContain("h23");
+ });
+
+ test("extension keyword overrides default data", () => {
+ expect(new Intl.Locale("en-u-hc-h24").hourCycles).toEqual(["h24"]);
+ expect(new Intl.Locale("en", { hourCycle: "h24" }).hourCycles).toEqual(["h24"]);
+
+ expect(new Intl.Locale("ar-u-hc-h24").hourCycles).toEqual(["h24"]);
+ expect(new Intl.Locale("ar", { hourCycle: "h24" }).hourCycles).toEqual(["h24"]);
+
+ // Invalid hourCycles also take precedence when specified in the locale string. Unlike other
+ // properties, Locale("en", { hourCycle: "ladybird" }) will explictly throw.
+ expect(new Intl.Locale("en-u-hc-ladybird").hourCycles).toEqual(["ladybird"]);
+ });
+});