mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 03:55:24 +00:00
LibJS: Define constructor slots for describing how to read options
This is an editorial change in the ECMA-402 spec. See: https://github.com/tc39/ecma402/commit/a2beb66 We implement this change by introducing a virtual interface that all Intl "service" objects must implement. A future patch will make use of the virtualized RelevantExtensionKeys and ResolutionOptionDescriptors accessors, and we will need to be able to use those slots from a generic instance type.
This commit is contained in:
parent
ba56fbde62
commit
5898248b6b
29 changed files with 284 additions and 116 deletions
|
@ -274,11 +274,14 @@ JS_ENUMERATE_INTL_OBJECTS
|
|||
#undef __JS_ENUMERATE
|
||||
|
||||
class Intl;
|
||||
class IntlObject;
|
||||
class MathematicalValue;
|
||||
|
||||
// Not included in JS_ENUMERATE_INTL_OBJECTS due to missing distinct constructor
|
||||
class Segments;
|
||||
class SegmentsPrototype;
|
||||
|
||||
struct ResolutionOptionDescriptor;
|
||||
};
|
||||
|
||||
namespace Temporal {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@ GC_DEFINE_ALLOCATOR(Collator);
|
|||
|
||||
// 10 Collator Objects, https://tc39.es/ecma402/#collator-objects
|
||||
Collator::Collator(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -22,4 +22,27 @@ void Collator::visit_edges(Visitor& visitor)
|
|||
visitor.visit(m_bound_compare);
|
||||
}
|
||||
|
||||
// 10.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl-collator-internal-slots
|
||||
ReadonlySpan<StringView> Collator::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is a List that must include the element "co", may include any or all of the elements "kf" and "kn", and must not include any other elements.
|
||||
static constexpr AK::Array keys { "co"sv, "kf"sv, "kn"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
// 10.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl-collator-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> Collator::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "co", [[Property]]: "collation" }, { [[Key]]: "kn", [[Property]]: "numeric", [[Type]]: boolean }, { [[Key]]: "kf", [[Property]]: "caseFirst", [[Values]]: « "upper", "lower", "false" » } ».
|
||||
static constexpr AK::Array case_first_values { "upper"sv, "lower"sv, "false"sv };
|
||||
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "co"sv, .property = vm.names.collation },
|
||||
{ .key = "kn"sv, .property = vm.names.numeric, .type = OptionType::Boolean },
|
||||
{ .key = "kf"sv, .property = vm.names.caseFirst, .values = case_first_values },
|
||||
});
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,34 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <LibJS/Runtime/Intl/CollatorCompareFunction.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/Collator.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class Collator final : public Object {
|
||||
JS_OBJECT(Collator, Object);
|
||||
class Collator final : public IntlObject {
|
||||
JS_OBJECT(Collator, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(Collator);
|
||||
|
||||
public:
|
||||
static constexpr auto relevant_extension_keys()
|
||||
{
|
||||
// 10.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl-collator-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is a List that must include the element "co", may include any or all of the elements "kf" and "kn", and must not include any other elements.
|
||||
return AK::Array { "co"sv, "kf"sv, "kn"sv };
|
||||
}
|
||||
|
||||
virtual ~Collator() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -113,7 +113,7 @@ ThrowCompletionOr<GC::Ref<Object>> CollatorConstructor::construct(FunctionObject
|
|||
opt.kf = locale_key_from_value(case_first);
|
||||
|
||||
// 21. Let r be ResolveLocale(%Intl.Collator%.[[AvailableLocales]], requestedLocales, opt, %Intl.Collator%.[[RelevantExtensionKeys]], localeData).
|
||||
auto result = resolve_locale(requested_locales, opt, Collator::relevant_extension_keys());
|
||||
auto result = resolve_locale(requested_locales, opt, collator->relevant_extension_keys());
|
||||
|
||||
// 22. Set collator.[[Locale]] to r.[[Locale]].
|
||||
collator->set_locale(move(result.locale));
|
||||
|
|
|
@ -24,7 +24,7 @@ GC_DEFINE_ALLOCATOR(DateTimeFormat);
|
|||
|
||||
// 11 DateTimeFormat Objects, https://tc39.es/ecma402/#datetimeformat-objects
|
||||
DateTimeFormat::DateTimeFormat(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,30 @@ void DateTimeFormat::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(m_bound_format);
|
||||
}
|
||||
|
||||
// 11.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.datetimeformat-internal-slots
|
||||
ReadonlySpan<StringView> DateTimeFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "hc", "nu" ».
|
||||
static constexpr AK::Array keys { "ca"sv, "hc"sv, "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
// 11.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.datetimeformat-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> DateTimeFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "ca", [[Property]]: "calendar" }, { [[Key]]: "nu", [[Property]]: "numberingSystem" }, { [[Key]]: "hour12", [[Property]]: "hour12", [[Type]]: boolean }, { [[Key]]: "hc", [[Property]]: "hourCycle", [[Values]]: « "h11", "h12", "h23", "h24" » } ».
|
||||
static constexpr AK::Array hour_cycle_values { "h11"sv, "h12"sv, "h23"sv, "h24"sv };
|
||||
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "ca"sv, .property = vm.names.calendar },
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
{ .key = "hour12"sv, .property = vm.names.hour12, .type = OptionType::Boolean },
|
||||
{ .key = "hc"sv, .property = vm.names.hourCycle, .values = hour_cycle_values },
|
||||
});
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
static Optional<Unicode::DateTimeFormat const&> get_or_create_formatter(StringView locale, StringView time_zone, OwnPtr<Unicode::DateTimeFormat>& formatter, Optional<Unicode::CalendarPattern> const& format)
|
||||
{
|
||||
if (formatter)
|
||||
|
|
|
@ -13,28 +13,24 @@
|
|||
#include <AK/Vector.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Intl/DateTimeFormatConstructor.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibUnicode/DateTimeFormat.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class DateTimeFormat final : public Object {
|
||||
JS_OBJECT(DateTimeFormat, Object);
|
||||
class DateTimeFormat final : public IntlObject {
|
||||
JS_OBJECT(DateTimeFormat, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(DateTimeFormat);
|
||||
|
||||
using Patterns = Unicode::CalendarPattern;
|
||||
|
||||
public:
|
||||
static constexpr auto relevant_extension_keys()
|
||||
{
|
||||
// 11.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.datetimeformat-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "hc", "nu" ».
|
||||
return AK::Array { "ca"sv, "hc"sv, "nu"sv };
|
||||
}
|
||||
|
||||
virtual ~DateTimeFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
|
||||
|
@ -90,7 +86,7 @@ public:
|
|||
void set_temporal_time_zone(String temporal_time_zone) { m_temporal_time_zone = move(temporal_time_zone); }
|
||||
|
||||
private:
|
||||
DateTimeFormat(Object& prototype);
|
||||
explicit DateTimeFormat(Object& prototype);
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
* Copyright (c) 2021-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -145,7 +145,7 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
opt.hc = locale_key_from_value(hour_cycle);
|
||||
|
||||
// 17. Let r be ResolveLocale(%Intl.DateTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.DateTimeFormat%.[[RelevantExtensionKeys]], %Intl.DateTimeFormat%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, DateTimeFormat::relevant_extension_keys());
|
||||
auto result = resolve_locale(requested_locales, opt, date_time_format->relevant_extension_keys());
|
||||
|
||||
// 18. Set dateTimeFormat.[[Locale]] to r.[[Locale]].
|
||||
date_time_format->set_locale(move(result.locale));
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Intl/DisplayNames.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
|
@ -14,10 +14,24 @@ GC_DEFINE_ALLOCATOR(DisplayNames);
|
|||
|
||||
// 12 DisplayNames Objects, https://tc39.es/ecma402/#intl-displaynames-objects
|
||||
DisplayNames::DisplayNames(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
// 12.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DisplayNames-internal-slots
|
||||
ReadonlySpan<StringView> DisplayNames::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 12.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DisplayNames-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> DisplayNames::resolution_option_descriptors(VM&) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
void DisplayNames::set_type(StringView type)
|
||||
{
|
||||
if (type == "language"sv)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2021-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -9,14 +9,14 @@
|
|||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/DisplayNames.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class DisplayNames final : public Object {
|
||||
JS_OBJECT(DisplayNames, Object);
|
||||
class DisplayNames final : public IntlObject {
|
||||
JS_OBJECT(DisplayNames, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(DisplayNames);
|
||||
|
||||
enum class Type {
|
||||
|
@ -38,6 +38,9 @@ class DisplayNames final : public Object {
|
|||
public:
|
||||
virtual ~DisplayNames() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
|
||||
|
@ -59,7 +62,7 @@ public:
|
|||
StringView language_display_string() const { return Unicode::language_display_to_string(*m_language_display); }
|
||||
|
||||
private:
|
||||
DisplayNames(Object& prototype);
|
||||
explicit DisplayNames(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
Unicode::Style m_style { Unicode::Style::Long }; // [[Style]]
|
||||
|
|
|
@ -75,7 +75,7 @@ ThrowCompletionOr<GC::Ref<Object>> DisplayNamesConstructor::construct(FunctionOb
|
|||
opt.locale_matcher = matcher;
|
||||
|
||||
// 9. Let r be ResolveLocale(%Intl.DisplayNames%.[[AvailableLocales]], requestedLocales, opt, %Intl.DisplayNames%.[[RelevantExtensionKeys]], %Intl.DisplayNames%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, {});
|
||||
auto result = resolve_locale(requested_locales, opt, display_names->relevant_extension_keys());
|
||||
|
||||
// 10. Let style be ? GetOption(options, "style", string, « "narrow", "short", "long" », "long").
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "narrow"sv, "short"sv, "long"sv }, "long"sv));
|
||||
|
|
|
@ -8,15 +8,12 @@
|
|||
#include <AK/GenericShorthands.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Intl/DurationFormat.h>
|
||||
#include <LibJS/Runtime/Intl/ListFormat.h>
|
||||
#include <LibJS/Runtime/Intl/ListFormatConstructor.h>
|
||||
#include <LibJS/Runtime/Intl/MathematicalValue.h>
|
||||
#include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
|
||||
#include <LibJS/Runtime/Intl/PluralRules.h>
|
||||
#include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
|
||||
#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
@ -25,10 +22,29 @@ GC_DEFINE_ALLOCATOR(DurationFormat);
|
|||
|
||||
// 13 DurationFormat Objects, https://tc39.es/ecma402/#durationformat-objects
|
||||
DurationFormat::DurationFormat(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
// 13.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DurationFormat-internal-slots
|
||||
ReadonlySpan<StringView> DurationFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
static constexpr AK::Array keys { "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
// 13.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DurationFormat-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> DurationFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
DurationFormat::Style DurationFormat::style_from_string(StringView style)
|
||||
{
|
||||
if (style == "long"sv)
|
||||
|
|
|
@ -10,15 +10,14 @@
|
|||
#include <AK/Array.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibCrypto/BigFraction/BigFraction.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class DurationFormat final : public Object {
|
||||
JS_OBJECT(DurationFormat, Object);
|
||||
class DurationFormat final : public IntlObject {
|
||||
JS_OBJECT(DurationFormat, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(DurationFormat);
|
||||
|
||||
public:
|
||||
|
@ -72,15 +71,11 @@ public:
|
|||
Display display { Display::Auto };
|
||||
};
|
||||
|
||||
static constexpr auto relevant_extension_keys()
|
||||
{
|
||||
// 13.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DurationFormat-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
return AK::Array { "nu"sv };
|
||||
}
|
||||
|
||||
virtual ~DurationFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
String const& locale() const { return m_locale; }
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ ThrowCompletionOr<GC::Ref<Object>> DurationFormatConstructor::construct(Function
|
|||
opt.nu = locale_key_from_value(numbering_system);
|
||||
|
||||
// 9. Let r be ResolveLocale(%Intl.DurationFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.DurationFormat%.[[RelevantExtensionKeys]], %Intl.DurationFormat%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, DurationFormat::relevant_extension_keys());
|
||||
auto result = resolve_locale(requested_locales, opt, duration_format->relevant_extension_keys());
|
||||
|
||||
// 10. Set durationFormat.[[Locale]] to r.[[Locale]].
|
||||
duration_format->set_locale(move(result.locale));
|
||||
|
|
36
Libraries/LibJS/Runtime/Intl/IntlObject.h
Normal file
36
Libraries/LibJS/Runtime/Intl/IntlObject.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Span.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/PropertyKey.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
// https://tc39.es/ecma402/#resolution-option-descriptor
|
||||
struct ResolutionOptionDescriptor {
|
||||
StringView key;
|
||||
PropertyKey property;
|
||||
OptionType type { OptionType::String };
|
||||
ReadonlySpan<StringView> values {};
|
||||
};
|
||||
|
||||
class IntlObject : public Object {
|
||||
JS_OBJECT(IntlObject, Object);
|
||||
|
||||
public:
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const = 0;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const = 0;
|
||||
|
||||
protected:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
}
|
|
@ -4,11 +4,10 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Intl/ListFormat.h>
|
||||
#include <LibJS/Runtime/Iterator.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibUnicode/ListFormat.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
@ -17,10 +16,24 @@ GC_DEFINE_ALLOCATOR(ListFormat);
|
|||
|
||||
// 14 ListFormat Objects, https://tc39.es/ecma402/#listformat-objects
|
||||
ListFormat::ListFormat(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
// 14.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.ListFormat-internal-slots
|
||||
ReadonlySpan<StringView> ListFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 14.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.ListFormat-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> ListFormat::resolution_option_descriptors(VM&) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 14.5.2 CreatePartsFromList ( listFormat, list ), https://tc39.es/ecma402/#sec-createpartsfromlist
|
||||
Vector<Unicode::ListFormat::Partition> create_parts_from_list(ListFormat const& list_format, ReadonlySpan<String> list)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2021-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -9,15 +9,14 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/ListFormat.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class ListFormat final : public Object {
|
||||
JS_OBJECT(ListFormat, Object);
|
||||
class ListFormat final : public IntlObject {
|
||||
JS_OBJECT(ListFormat, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(ListFormat);
|
||||
|
||||
public:
|
||||
|
@ -30,6 +29,9 @@ public:
|
|||
|
||||
virtual ~ListFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ ThrowCompletionOr<GC::Ref<Object>> ListFormatConstructor::construct(FunctionObje
|
|||
opt.locale_matcher = matcher;
|
||||
|
||||
// 8. Let r be ResolveLocale(%Intl.ListFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.ListFormat%.[[RelevantExtensionKeys]], %Intl.ListFormat%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, {});
|
||||
auto result = resolve_locale(requested_locales, opt, list_format->relevant_extension_keys());
|
||||
|
||||
// 9. Set listFormat.[[Locale]] to r.[[Locale]].
|
||||
list_format->set_locale(move(result.locale));
|
||||
|
|
|
@ -4,22 +4,15 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Checked.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Intl/NumberFormat.h>
|
||||
#include <LibJS/Runtime/Intl/NumberFormatFunction.h>
|
||||
#include <LibJS/Runtime/Intl/PluralRules.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
#include <LibUnicode/CurrencyCode.h>
|
||||
#include <LibUnicode/DisplayNames.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
|
@ -27,7 +20,7 @@ GC_DEFINE_ALLOCATOR(NumberFormatBase);
|
|||
GC_DEFINE_ALLOCATOR(NumberFormat);
|
||||
|
||||
NumberFormatBase::NumberFormatBase(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,6 +37,25 @@ void NumberFormat::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(m_bound_format);
|
||||
}
|
||||
|
||||
// 16.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.numberformat-internal-slots
|
||||
ReadonlySpan<StringView> NumberFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
static constexpr AK::Array keys { "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
// 16.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.numberformat-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> NumberFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
StringView NumberFormatBase::computed_rounding_priority_string() const
|
||||
{
|
||||
switch (m_computed_rounding_priority) {
|
||||
|
|
|
@ -6,19 +6,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibJS/Runtime/Intl/MathematicalValue.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
#include <LibUnicode/NumberFormat.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class NumberFormatBase : public Object {
|
||||
JS_OBJECT(NumberFormatBase, Object);
|
||||
class NumberFormatBase : public IntlObject {
|
||||
JS_OBJECT(NumberFormatBase, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(NumberFormatBase);
|
||||
|
||||
public:
|
||||
|
@ -102,15 +101,11 @@ class NumberFormat final : public NumberFormatBase {
|
|||
GC_DECLARE_ALLOCATOR(NumberFormat);
|
||||
|
||||
public:
|
||||
static constexpr auto relevant_extension_keys()
|
||||
{
|
||||
// 16.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.numberformat-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
return AK::Array { "nu"sv };
|
||||
}
|
||||
|
||||
virtual ~NumberFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
|
|||
opt.nu = locale_key_from_value(numbering_system);
|
||||
|
||||
// 11. Let r be ResolveLocale(%Intl.NumberFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.NumberFormat%.[[RelevantExtensionKeys]], %Intl.NumberFormat%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, NumberFormat::relevant_extension_keys());
|
||||
auto result = resolve_locale(requested_locales, opt, number_format->relevant_extension_keys());
|
||||
|
||||
// 12. Set numberFormat.[[Locale]] to r.[[Locale]].
|
||||
number_format->set_locale(move(result.locale));
|
||||
|
|
|
@ -17,6 +17,20 @@ PluralRules::PluralRules(Object& prototype)
|
|||
{
|
||||
}
|
||||
|
||||
// 17.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.pluralrules-internal-slots
|
||||
ReadonlySpan<StringView> PluralRules::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 17.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.pluralrules-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> PluralRules::resolution_option_descriptors(VM&) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 17.5.2 ResolvePlural ( pluralRules, n ), https://tc39.es/ecma402/#sec-resolveplural
|
||||
Unicode::PluralCategory resolve_plural(PluralRules const& plural_rules, Value number)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2022-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -21,6 +21,9 @@ class PluralRules final : public NumberFormatBase {
|
|||
public:
|
||||
virtual ~PluralRules() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
Unicode::PluralForm type() const { return m_type; }
|
||||
StringView type_string() const { return Unicode::plural_form_to_string(m_type); }
|
||||
void set_type(StringView type) { m_type = Unicode::plural_form_from_string(type); }
|
||||
|
|
|
@ -71,7 +71,7 @@ ThrowCompletionOr<GC::Ref<Object>> PluralRulesConstructor::construct(FunctionObj
|
|||
opt.locale_matcher = matcher;
|
||||
|
||||
// 8. Let r be ResolveLocale(%Intl.PluralRules%.[[AvailableLocales]], requestedLocales, opt, %Intl.PluralRules%.[[RelevantExtensionKeys]], %Intl.PluralRules%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, {});
|
||||
auto result = resolve_locale(requested_locales, opt, plural_rules->relevant_extension_keys());
|
||||
|
||||
// 9. Set pluralRules.[[Locale]] to r.[[locale]].
|
||||
plural_rules->set_locale(move(result.locale));
|
||||
|
|
|
@ -5,14 +5,9 @@
|
|||
*/
|
||||
|
||||
#include <AK/Enumerate.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Intl/NumberFormat.h>
|
||||
#include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
|
||||
#include <LibJS/Runtime/Intl/PluralRules.h>
|
||||
#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
|
@ -20,10 +15,29 @@ GC_DEFINE_ALLOCATOR(RelativeTimeFormat);
|
|||
|
||||
// 18 RelativeTimeFormat Objects, https://tc39.es/ecma402/#relativetimeformat-objects
|
||||
RelativeTimeFormat::RelativeTimeFormat(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
// 18.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat-internal-slots
|
||||
ReadonlySpan<StringView> RelativeTimeFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
static constexpr AK::Array keys { "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
// 18.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> RelativeTimeFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
// 18.5.1 SingularRelativeTimeUnit ( unit ), https://tc39.es/ecma402/#sec-singularrelativetimeunit
|
||||
ThrowCompletionOr<Unicode::TimeUnit> singular_relative_time_unit(VM& vm, StringView unit)
|
||||
{
|
||||
|
|
|
@ -6,32 +6,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
#include <LibUnicode/NumberFormat.h>
|
||||
#include <LibUnicode/RelativeTimeFormat.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class RelativeTimeFormat final : public Object {
|
||||
JS_OBJECT(RelativeTimeFormat, Object);
|
||||
class RelativeTimeFormat final : public IntlObject {
|
||||
JS_OBJECT(RelativeTimeFormat, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(RelativeTimeFormat);
|
||||
|
||||
public:
|
||||
static constexpr auto relevant_extension_keys()
|
||||
{
|
||||
// 18.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
return AK::Array { "nu"sv };
|
||||
}
|
||||
|
||||
virtual ~RelativeTimeFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ ThrowCompletionOr<GC::Ref<Object>> RelativeTimeFormatConstructor::construct(Func
|
|||
opt.nu = locale_key_from_value(numbering_system);
|
||||
|
||||
// 11. Let r be ResolveLocale(%Intl.RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.RelativeTimeFormat%.[[RelevantExtensionKeys]], %Intl.RelativeTimeFormat%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, RelativeTimeFormat::relevant_extension_keys());
|
||||
auto result = resolve_locale(requested_locales, opt, relative_time_format->relevant_extension_keys());
|
||||
|
||||
// 12. Let locale be r.[[Locale]].
|
||||
auto locale = move(result.locale);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Intl/Segmenter.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
|
@ -15,10 +15,24 @@ GC_DEFINE_ALLOCATOR(Segmenter);
|
|||
|
||||
// 19 Segmenter Objects, https://tc39.es/ecma402/#segmenter-objects
|
||||
Segmenter::Segmenter(Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
: IntlObject(ConstructWithPrototypeTag::Tag, prototype)
|
||||
{
|
||||
}
|
||||
|
||||
// 19.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.segmenter-internal-slots
|
||||
ReadonlySpan<StringView> Segmenter::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 19.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.segmenter-internal-slots
|
||||
ReadonlySpan<ResolutionOptionDescriptor> Segmenter::resolution_option_descriptors(VM&) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « ».
|
||||
return {};
|
||||
}
|
||||
|
||||
// 19.7.1 CreateSegmentDataObject ( segmenter, string, startIndex, endIndex ), https://tc39.es/ecma402/#sec-createsegmentdataobject
|
||||
ThrowCompletionOr<GC::Ref<Object>> create_segment_data_object(VM& vm, Unicode::Segmenter const& segmenter, Utf16View const& string, size_t start_index, size_t end_index)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2023-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -8,18 +8,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/Segmenter.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
class Segmenter final : public Object {
|
||||
JS_OBJECT(Segmenter, Object);
|
||||
class Segmenter final : public IntlObject {
|
||||
JS_OBJECT(Segmenter, IntlObject);
|
||||
GC_DECLARE_ALLOCATOR(Segmenter);
|
||||
|
||||
public:
|
||||
virtual ~Segmenter() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ ThrowCompletionOr<GC::Ref<Object>> SegmenterConstructor::construct(FunctionObjec
|
|||
opt.locale_matcher = matcher;
|
||||
|
||||
// 9. Let r be ResolveLocale(%Intl.Segmenter%.[[AvailableLocales]], requestedLocales, opt, %Intl.Segmenter%.[[RelevantExtensionKeys]], %Intl.Segmenter%.[[LocaleData]]).
|
||||
auto result = resolve_locale(requested_locales, opt, {});
|
||||
auto result = resolve_locale(requested_locales, opt, segmenter->relevant_extension_keys());
|
||||
|
||||
// 10. Set segmenter.[[Locale]] to r.[[locale]].
|
||||
segmenter->set_locale(move(result.locale));
|
||||
|
|
Loading…
Add table
Reference in a new issue