mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:58:11 +00:00
LibLocale+LibJS: Make locale data APIs infallible
These APIs only perform small allocations, and are only used by LibJS. Callers which could only have failed from these APIs are also made to be infallible here.
This commit is contained in:
parent
a98201f889
commit
cd526813e6
20 changed files with 340 additions and 364 deletions
|
@ -2091,7 +2091,7 @@ Optional<@return_type@> get_regional_@lookup_type@(StringView region)
|
||||||
append_regional_lookup("Weekday"sv, "weekend_end"sv);
|
append_regional_lookup("Weekday"sv, "weekend_end"sv);
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
static ErrorOr<CalendarData const*> find_calendar_data(StringView locale, StringView calendar)
|
static CalendarData const* find_calendar_data(StringView locale, StringView calendar)
|
||||||
{
|
{
|
||||||
auto locale_value = locale_from_string(locale);
|
auto locale_value = locale_from_string(locale);
|
||||||
if (!locale_value.has_value())
|
if (!locale_value.has_value())
|
||||||
|
@ -2118,7 +2118,7 @@ static ErrorOr<CalendarData const*> find_calendar_data(StringView locale, String
|
||||||
if (auto const* calendar_data = lookup_calendar(calendar))
|
if (auto const* calendar_data = lookup_calendar(calendar))
|
||||||
return calendar_data;
|
return calendar_data;
|
||||||
|
|
||||||
auto default_calendar = TRY(get_preferred_keyword_value_for_locale(locale, "ca"sv));
|
auto default_calendar = get_preferred_keyword_value_for_locale(locale, "ca"sv);
|
||||||
if (!default_calendar.has_value())
|
if (!default_calendar.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -2127,7 +2127,7 @@ static ErrorOr<CalendarData const*> find_calendar_data(StringView locale, String
|
||||||
|
|
||||||
ErrorOr<Optional<CalendarFormat>> get_calendar_date_format(StringView locale, StringView calendar)
|
ErrorOr<Optional<CalendarFormat>> get_calendar_date_format(StringView locale, StringView calendar)
|
||||||
{
|
{
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& formats = s_calendar_formats.at(data->date_formats);
|
auto const& formats = s_calendar_formats.at(data->date_formats);
|
||||||
return TRY(formats.to_unicode_calendar_format());
|
return TRY(formats.to_unicode_calendar_format());
|
||||||
}
|
}
|
||||||
|
@ -2136,7 +2136,7 @@ ErrorOr<Optional<CalendarFormat>> get_calendar_date_format(StringView locale, St
|
||||||
|
|
||||||
ErrorOr<Optional<CalendarFormat>> get_calendar_time_format(StringView locale, StringView calendar)
|
ErrorOr<Optional<CalendarFormat>> get_calendar_time_format(StringView locale, StringView calendar)
|
||||||
{
|
{
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& formats = s_calendar_formats.at(data->time_formats);
|
auto const& formats = s_calendar_formats.at(data->time_formats);
|
||||||
return TRY(formats.to_unicode_calendar_format());
|
return TRY(formats.to_unicode_calendar_format());
|
||||||
}
|
}
|
||||||
|
@ -2145,7 +2145,7 @@ ErrorOr<Optional<CalendarFormat>> get_calendar_time_format(StringView locale, St
|
||||||
|
|
||||||
ErrorOr<Optional<CalendarFormat>> get_calendar_date_time_format(StringView locale, StringView calendar)
|
ErrorOr<Optional<CalendarFormat>> get_calendar_date_time_format(StringView locale, StringView calendar)
|
||||||
{
|
{
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& formats = s_calendar_formats.at(data->date_time_formats);
|
auto const& formats = s_calendar_formats.at(data->date_time_formats);
|
||||||
return TRY(formats.to_unicode_calendar_format());
|
return TRY(formats.to_unicode_calendar_format());
|
||||||
}
|
}
|
||||||
|
@ -2156,7 +2156,7 @@ ErrorOr<Vector<CalendarPattern>> get_calendar_available_formats(StringView local
|
||||||
{
|
{
|
||||||
Vector<CalendarPattern> result {};
|
Vector<CalendarPattern> result {};
|
||||||
|
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& available_formats = s_calendar_pattern_lists.at(data->available_formats);
|
auto const& available_formats = s_calendar_pattern_lists.at(data->available_formats);
|
||||||
TRY(result.try_ensure_capacity(available_formats.size()));
|
TRY(result.try_ensure_capacity(available_formats.size()));
|
||||||
|
|
||||||
|
@ -2169,7 +2169,7 @@ ErrorOr<Vector<CalendarPattern>> get_calendar_available_formats(StringView local
|
||||||
|
|
||||||
ErrorOr<Optional<CalendarRangePattern>> get_calendar_default_range_format(StringView locale, StringView calendar)
|
ErrorOr<Optional<CalendarRangePattern>> get_calendar_default_range_format(StringView locale, StringView calendar)
|
||||||
{
|
{
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& pattern = s_calendar_range_patterns[data->default_range_format];
|
auto const& pattern = s_calendar_range_patterns[data->default_range_format];
|
||||||
return TRY(pattern.to_unicode_calendar_range_pattern());
|
return TRY(pattern.to_unicode_calendar_range_pattern());
|
||||||
}
|
}
|
||||||
|
@ -2181,7 +2181,7 @@ ErrorOr<Vector<CalendarRangePattern>> get_calendar_range_formats(StringView loca
|
||||||
{
|
{
|
||||||
Vector<CalendarRangePattern> result {};
|
Vector<CalendarRangePattern> result {};
|
||||||
|
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& range_formats = s_calendar_range_pattern_lists.at(data->range_formats);
|
auto const& range_formats = s_calendar_range_pattern_lists.at(data->range_formats);
|
||||||
|
|
||||||
for (auto format : range_formats) {
|
for (auto format : range_formats) {
|
||||||
|
@ -2199,7 +2199,7 @@ ErrorOr<Vector<CalendarRangePattern>> get_calendar_range12_formats(StringView lo
|
||||||
{
|
{
|
||||||
Vector<CalendarRangePattern> result {};
|
Vector<CalendarRangePattern> result {};
|
||||||
|
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& range12_formats = s_calendar_range_pattern_lists.at(data->range12_formats);
|
auto const& range12_formats = s_calendar_range_pattern_lists.at(data->range12_formats);
|
||||||
|
|
||||||
for (auto format : range12_formats) {
|
for (auto format : range12_formats) {
|
||||||
|
@ -2215,7 +2215,7 @@ ErrorOr<Vector<CalendarRangePattern>> get_calendar_range12_formats(StringView lo
|
||||||
|
|
||||||
static ErrorOr<ReadonlySpan<@string_index_type@>> find_calendar_symbols(StringView locale, StringView calendar, CalendarSymbol symbol, CalendarPatternStyle style)
|
static ErrorOr<ReadonlySpan<@string_index_type@>> find_calendar_symbols(StringView locale, StringView calendar, CalendarSymbol symbol, CalendarPatternStyle style)
|
||||||
{
|
{
|
||||||
if (auto const* data = TRY(find_calendar_data(locale, calendar)); data != nullptr) {
|
if (auto const* data = find_calendar_data(locale, calendar); data != nullptr) {
|
||||||
auto const& symbols_list = s_calendar_symbol_lists[data->symbols];
|
auto const& symbols_list = s_calendar_symbol_lists[data->symbols];
|
||||||
auto symbol_index = to_underlying(symbol);
|
auto symbol_index = to_underlying(symbol);
|
||||||
|
|
||||||
|
|
|
@ -1351,18 +1351,18 @@ static constexpr Array<@type@, @size@> @name@ { {)~~~");
|
||||||
|
|
||||||
struct CanonicalLanguageID
|
struct CanonicalLanguageID
|
||||||
{
|
{
|
||||||
ErrorOr<LanguageID> to_unicode_language_id() const
|
LanguageID to_unicode_language_id() const
|
||||||
{
|
{
|
||||||
LanguageID language_id {};
|
LanguageID language_id {};
|
||||||
TRY(language_id.variants.try_ensure_capacity(variants_size));
|
language_id.variants.ensure_capacity(variants_size);
|
||||||
|
|
||||||
language_id.language = TRY(String::from_utf8(decode_string(language)));
|
language_id.language = MUST(String::from_utf8(decode_string(language)));
|
||||||
if (script != 0)
|
if (script != 0)
|
||||||
language_id.script = TRY(String::from_utf8(decode_string(script)));
|
language_id.script = MUST(String::from_utf8(decode_string(script)));
|
||||||
if (region != 0)
|
if (region != 0)
|
||||||
language_id.region = TRY(String::from_utf8(decode_string(region)));
|
language_id.region = MUST(String::from_utf8(decode_string(region)));
|
||||||
for (size_t i = 0; i < variants_size; ++i)
|
for (size_t i = 0; i < variants_size; ++i)
|
||||||
language_id.variants.append(TRY(String::from_utf8(decode_string(variants[i]))));
|
language_id.variants.append(MUST(String::from_utf8(decode_string(variants[i]))));
|
||||||
|
|
||||||
return language_id;
|
return language_id;
|
||||||
}
|
}
|
||||||
|
@ -1674,13 +1674,13 @@ static ReadonlySpan<@string_index_type@> find_keyword_indices(StringView locale,
|
||||||
return s_keyword_lists.at(keywords_index);
|
return s_keyword_lists.at(keywords_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<StringView>> get_preferred_keyword_value_for_locale(StringView locale, StringView key)
|
Optional<StringView> get_preferred_keyword_value_for_locale(StringView locale, StringView key)
|
||||||
{
|
{
|
||||||
// Hour cycle keywords are region-based rather than locale-based, so they need to be handled specially.
|
// Hour cycle keywords are region-based rather than locale-based, so they need to be handled specially.
|
||||||
// FIXME: Calendar keywords are also region-based, and will need to be handled here when we support non-Gregorian calendars:
|
// FIXME: Calendar keywords are also region-based, and will need to be handled here when we support non-Gregorian calendars:
|
||||||
// https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/supplemental/calendarPreferenceData.json
|
// https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/supplemental/calendarPreferenceData.json
|
||||||
if (key == "hc"sv) {
|
if (key == "hc"sv) {
|
||||||
auto hour_cycles = TRY(get_locale_hour_cycles(locale));
|
auto hour_cycles = MUST(get_locale_hour_cycles(locale));
|
||||||
if (hour_cycles.is_empty())
|
if (hour_cycles.is_empty())
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
|
@ -1703,16 +1703,16 @@ ErrorOr<Optional<StringView>> get_preferred_keyword_value_for_locale(StringView
|
||||||
return Optional<StringView> { decode_string(keyword_indices[0]) };
|
return Optional<StringView> { decode_string(keyword_indices[0]) };
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Vector<StringView>> get_keywords_for_locale(StringView locale, StringView key)
|
Vector<StringView> get_keywords_for_locale(StringView locale, StringView key)
|
||||||
{
|
{
|
||||||
// Hour cycle keywords are region-based rather than locale-based, so they need to be handled specially.
|
// Hour cycle keywords are region-based rather than locale-based, so they need to be handled specially.
|
||||||
// FIXME: Calendar keywords are also region-based, and will need to be handled here when we support non-Gregorian calendars:
|
// FIXME: Calendar keywords are also region-based, and will need to be handled here when we support non-Gregorian calendars:
|
||||||
// https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/supplemental/calendarPreferenceData.json
|
// https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/supplemental/calendarPreferenceData.json
|
||||||
if (key == "hc"sv) {
|
if (key == "hc"sv) {
|
||||||
auto hour_cycles = TRY(get_locale_hour_cycles(locale));
|
auto hour_cycles = MUST(get_locale_hour_cycles(locale));
|
||||||
|
|
||||||
Vector<StringView> values;
|
Vector<StringView> values;
|
||||||
TRY(values.try_ensure_capacity(hour_cycles.size()));
|
values.ensure_capacity(hour_cycles.size());
|
||||||
|
|
||||||
for (auto hour_cycle : hour_cycles)
|
for (auto hour_cycle : hour_cycles)
|
||||||
values.unchecked_append(hour_cycle_to_string(hour_cycle));
|
values.unchecked_append(hour_cycle_to_string(hour_cycle));
|
||||||
|
@ -1727,7 +1727,7 @@ ErrorOr<Vector<StringView>> get_keywords_for_locale(StringView locale, StringVie
|
||||||
auto keyword_indices = find_keyword_indices(locale, key);
|
auto keyword_indices = find_keyword_indices(locale, key);
|
||||||
|
|
||||||
Vector<StringView> keywords;
|
Vector<StringView> keywords;
|
||||||
TRY(keywords.try_ensure_capacity(keyword_indices.size()));
|
keywords.ensure_capacity(keyword_indices.size());
|
||||||
|
|
||||||
for (auto keyword : keyword_indices)
|
for (auto keyword : keyword_indices)
|
||||||
keywords.unchecked_append(decode_string(keyword));
|
keywords.unchecked_append(decode_string(keyword));
|
||||||
|
@ -1798,7 +1798,7 @@ Optional<CharacterOrder> character_order_for_locale(StringView locale)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> resolve_complex_language_aliases(LanguageID& language_id)
|
void resolve_complex_language_aliases(LanguageID& language_id)
|
||||||
{
|
{
|
||||||
for (auto const& map : s_complex_alias) {
|
for (auto const& map : s_complex_alias) {
|
||||||
auto key_language = decode_string(map.key.language);
|
auto key_language = decode_string(map.key.language);
|
||||||
|
@ -1814,7 +1814,7 @@ ErrorOr<void> resolve_complex_language_aliases(LanguageID& language_id)
|
||||||
if (!map.key.matches_variants(language_id.variants))
|
if (!map.key.matches_variants(language_id.variants))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto alias = TRY(map.alias.to_unicode_language_id());
|
auto alias = map.alias.to_unicode_language_id();
|
||||||
|
|
||||||
if (alias.language == "und"sv)
|
if (alias.language == "und"sv)
|
||||||
alias.language = move(language_id.language);
|
alias.language = move(language_id.language);
|
||||||
|
@ -1828,11 +1828,9 @@ ErrorOr<void> resolve_complex_language_aliases(LanguageID& language_id)
|
||||||
language_id = move(alias);
|
language_id = move(alias);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<LanguageID>> add_likely_subtags(LanguageID const& language_id)
|
Optional<LanguageID> add_likely_subtags(LanguageID const& language_id)
|
||||||
{
|
{
|
||||||
// https://www.unicode.org/reports/tr35/#Likely_Subtags
|
// https://www.unicode.org/reports/tr35/#Likely_Subtags
|
||||||
auto const* likely_subtag = resolve_likely_subtag(language_id);
|
auto const* likely_subtag = resolve_likely_subtag(language_id);
|
||||||
|
@ -1849,19 +1847,19 @@ ErrorOr<Optional<LanguageID>> add_likely_subtags(LanguageID const& language_id)
|
||||||
auto alias_region = decode_string(likely_subtag->alias.region);
|
auto alias_region = decode_string(likely_subtag->alias.region);
|
||||||
|
|
||||||
if (maximized.language == "und"sv)
|
if (maximized.language == "und"sv)
|
||||||
maximized.language = TRY(String::from_utf8(alias_language));
|
maximized.language = MUST(String::from_utf8(alias_language));
|
||||||
if (!maximized.script.has_value() || (!key_script.is_empty() && !alias_script.is_empty()))
|
if (!maximized.script.has_value() || (!key_script.is_empty() && !alias_script.is_empty()))
|
||||||
maximized.script = TRY(String::from_utf8(alias_script));
|
maximized.script = MUST(String::from_utf8(alias_script));
|
||||||
if (!maximized.region.has_value() || (!key_region.is_empty() && !alias_region.is_empty()))
|
if (!maximized.region.has_value() || (!key_region.is_empty() && !alias_region.is_empty()))
|
||||||
maximized.region = TRY(String::from_utf8(alias_region));
|
maximized.region = MUST(String::from_utf8(alias_region));
|
||||||
|
|
||||||
return maximized;
|
return maximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<String>> resolve_most_likely_territory(LanguageID const& language_id)
|
Optional<String> resolve_most_likely_territory(LanguageID const& language_id)
|
||||||
{
|
{
|
||||||
if (auto const* likely_subtag = resolve_likely_subtag(language_id); likely_subtag != nullptr)
|
if (auto const* likely_subtag = resolve_likely_subtag(language_id); likely_subtag != nullptr)
|
||||||
return String::from_utf8(decode_string(likely_subtag->alias.region));
|
return MUST(String::from_utf8(decode_string(likely_subtag->alias.region)));
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -927,7 +927,7 @@ Optional<ReadonlySpan<u32>> get_digits_for_number_system(StringView system)
|
||||||
return s_number_systems_digits[number_system_index];
|
return s_number_systems_digits[number_system_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<NumberSystemData const*> find_number_system(StringView locale, StringView system)
|
static NumberSystemData const* find_number_system(StringView locale, StringView system)
|
||||||
{
|
{
|
||||||
auto locale_value = locale_from_string(locale);
|
auto locale_value = locale_from_string(locale);
|
||||||
if (!locale_value.has_value())
|
if (!locale_value.has_value())
|
||||||
|
@ -957,44 +957,44 @@ static ErrorOr<NumberSystemData const*> find_number_system(StringView locale, St
|
||||||
if (auto const* number_system = lookup_number_system(system))
|
if (auto const* number_system = lookup_number_system(system))
|
||||||
return number_system;
|
return number_system;
|
||||||
|
|
||||||
auto default_number_system = TRY(get_preferred_keyword_value_for_locale(locale, "nu"sv));
|
auto default_number_system = get_preferred_keyword_value_for_locale(locale, "nu"sv);
|
||||||
if (!default_number_system.has_value())
|
if (!default_number_system.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return lookup_number_system(*default_number_system);
|
return lookup_number_system(*default_number_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<StringView>> get_number_system_symbol(StringView locale, StringView system, NumericSymbol symbol)
|
Optional<StringView> get_number_system_symbol(StringView locale, StringView system, NumericSymbol symbol)
|
||||||
{
|
{
|
||||||
if (auto const* number_system = TRY(find_number_system(locale, system)); number_system != nullptr) {
|
if (auto const* number_system = find_number_system(locale, system); number_system != nullptr) {
|
||||||
auto symbols = s_numeric_symbol_lists.at(number_system->symbols);
|
auto symbols = s_numeric_symbol_lists.at(number_system->symbols);
|
||||||
|
|
||||||
auto symbol_index = to_underlying(symbol);
|
auto symbol_index = to_underlying(symbol);
|
||||||
if (symbol_index >= symbols.size())
|
if (symbol_index >= symbols.size())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
return Optional<StringView> { decode_string(symbols[symbol_index]) };
|
return decode_string(symbols[symbol_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OptionalNone {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<NumberGroupings>> get_number_system_groupings(StringView locale, StringView system)
|
Optional<NumberGroupings> get_number_system_groupings(StringView locale, StringView system)
|
||||||
{
|
{
|
||||||
auto locale_value = locale_from_string(locale);
|
auto locale_value = locale_from_string(locale);
|
||||||
if (!locale_value.has_value())
|
if (!locale_value.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
u8 minimum_grouping_digits = s_minimum_grouping_digits[to_underlying(*locale_value) - 1];
|
u8 minimum_grouping_digits = s_minimum_grouping_digits[to_underlying(*locale_value) - 1];
|
||||||
|
|
||||||
if (auto const* number_system = TRY(find_number_system(locale, system)); number_system != nullptr)
|
if (auto const* number_system = find_number_system(locale, system); number_system != nullptr)
|
||||||
return NumberGroupings { minimum_grouping_digits, number_system->primary_grouping_size, number_system->secondary_grouping_size };
|
return NumberGroupings { minimum_grouping_digits, number_system->primary_grouping_size, number_system->secondary_grouping_size };
|
||||||
return OptionalNone {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<NumberFormat>> get_standard_number_system_format(StringView locale, StringView system, StandardNumberFormatType type)
|
ErrorOr<Optional<NumberFormat>> get_standard_number_system_format(StringView locale, StringView system, StandardNumberFormatType type)
|
||||||
{
|
{
|
||||||
if (auto const* number_system = TRY(find_number_system(locale, system)); number_system != nullptr) {
|
if (auto const* number_system = find_number_system(locale, system); number_system != nullptr) {
|
||||||
@number_format_index_type@ format_index = 0;
|
@number_format_index_type@ format_index = 0;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -1025,7 +1025,7 @@ ErrorOr<Vector<NumberFormat>> get_compact_number_system_formats(StringView local
|
||||||
{
|
{
|
||||||
Vector<NumberFormat> formats;
|
Vector<NumberFormat> formats;
|
||||||
|
|
||||||
if (auto const* number_system = TRY(find_number_system(locale, system)); number_system != nullptr) {
|
if (auto const* number_system = find_number_system(locale, system); number_system != nullptr) {
|
||||||
@number_format_list_index_type@ number_format_list_index { 0 };
|
@number_format_list_index_type@ number_format_list_index { 0 };
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
|
@ -104,11 +104,11 @@ template<typename LHS, typename RHS>
|
||||||
TEST_CASE(parse_unicode_locale_id)
|
TEST_CASE(parse_unicode_locale_id)
|
||||||
{
|
{
|
||||||
auto fail = [](StringView locale) {
|
auto fail = [](StringView locale) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
EXPECT(!locale_id.has_value());
|
EXPECT(!locale_id.has_value());
|
||||||
};
|
};
|
||||||
auto pass = [](StringView locale, Optional<StringView> expected_language, Optional<StringView> expected_script, Optional<StringView> expected_region, Vector<StringView> expected_variants) {
|
auto pass = [](StringView locale, Optional<StringView> expected_language, Optional<StringView> expected_script, Optional<StringView> expected_region, Vector<StringView> expected_variants) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
EXPECT_EQ(locale_id->language_id.language, expected_language);
|
EXPECT_EQ(locale_id->language_id.language, expected_language);
|
||||||
|
@ -145,11 +145,11 @@ TEST_CASE(parse_unicode_locale_id_with_unicode_locale_extension)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fail = [](StringView locale) {
|
auto fail = [](StringView locale) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
EXPECT(!locale_id.has_value());
|
EXPECT(!locale_id.has_value());
|
||||||
};
|
};
|
||||||
auto pass = [](StringView locale, LocaleExtension const& expected_extension) {
|
auto pass = [](StringView locale, LocaleExtension const& expected_extension) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
EXPECT_EQ(locale_id->extensions.size(), 1u);
|
EXPECT_EQ(locale_id->extensions.size(), 1u);
|
||||||
|
|
||||||
|
@ -209,11 +209,11 @@ TEST_CASE(parse_unicode_locale_id_with_transformed_extension)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fail = [](StringView locale) {
|
auto fail = [](StringView locale) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
EXPECT(!locale_id.has_value());
|
EXPECT(!locale_id.has_value());
|
||||||
};
|
};
|
||||||
auto pass = [](StringView locale, TransformedExtension const& expected_extension) {
|
auto pass = [](StringView locale, TransformedExtension const& expected_extension) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
EXPECT_EQ(locale_id->extensions.size(), 1u);
|
EXPECT_EQ(locale_id->extensions.size(), 1u);
|
||||||
|
|
||||||
|
@ -280,11 +280,11 @@ TEST_CASE(parse_unicode_locale_id_with_other_extension)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fail = [](StringView locale) {
|
auto fail = [](StringView locale) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
EXPECT(!locale_id.has_value());
|
EXPECT(!locale_id.has_value());
|
||||||
};
|
};
|
||||||
auto pass = [](StringView locale, OtherExtension const& expected_extension) {
|
auto pass = [](StringView locale, OtherExtension const& expected_extension) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
EXPECT_EQ(locale_id->extensions.size(), 1u);
|
EXPECT_EQ(locale_id->extensions.size(), 1u);
|
||||||
|
|
||||||
|
@ -314,11 +314,11 @@ TEST_CASE(parse_unicode_locale_id_with_other_extension)
|
||||||
TEST_CASE(parse_unicode_locale_id_with_private_use_extension)
|
TEST_CASE(parse_unicode_locale_id_with_private_use_extension)
|
||||||
{
|
{
|
||||||
auto fail = [](StringView locale) {
|
auto fail = [](StringView locale) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
EXPECT(!locale_id.has_value());
|
EXPECT(!locale_id.has_value());
|
||||||
};
|
};
|
||||||
auto pass = [](StringView locale, Vector<StringView> const& expected_extension) {
|
auto pass = [](StringView locale, Vector<StringView> const& expected_extension) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
EXPECT(compare_vectors(locale_id->private_use_extensions, expected_extension));
|
EXPECT(compare_vectors(locale_id->private_use_extensions, expected_extension));
|
||||||
};
|
};
|
||||||
|
@ -338,10 +338,10 @@ TEST_CASE(parse_unicode_locale_id_with_private_use_extension)
|
||||||
TEST_CASE(canonicalize_unicode_locale_id)
|
TEST_CASE(canonicalize_unicode_locale_id)
|
||||||
{
|
{
|
||||||
auto test = [](StringView locale, StringView expected_canonical_locale) {
|
auto test = [](StringView locale, StringView expected_canonical_locale) {
|
||||||
auto locale_id = MUST(Locale::parse_unicode_locale_id(locale));
|
auto locale_id = Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
auto canonical_locale = MUST(Locale::canonicalize_unicode_locale_id(*locale_id));
|
auto canonical_locale = Locale::canonicalize_unicode_locale_id(*locale_id);
|
||||||
EXPECT_EQ(*canonical_locale, expected_canonical_locale);
|
EXPECT_EQ(*canonical_locale, expected_canonical_locale);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace JS::Intl {
|
||||||
// 6.2.2 IsStructurallyValidLanguageTag ( locale ), https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag
|
// 6.2.2 IsStructurallyValidLanguageTag ( locale ), https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag
|
||||||
ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_tag(VM& vm, StringView locale)
|
ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_tag(VM& vm, StringView locale)
|
||||||
{
|
{
|
||||||
auto contains_duplicate_variant = [&](auto& variants) -> ThrowCompletionOr<bool> {
|
auto contains_duplicate_variant = [&](auto& variants) {
|
||||||
if (variants.is_empty())
|
if (variants.is_empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_t
|
||||||
// IsStructurallyValidLanguageTag returns true if all of the following conditions hold, false otherwise:
|
// IsStructurallyValidLanguageTag returns true if all of the following conditions hold, false otherwise:
|
||||||
|
|
||||||
// locale can be generated from the EBNF grammar for unicode_locale_id in Unicode Technical Standard #35 LDML § 3.2 Unicode Locale Identifier;
|
// locale can be generated from the EBNF grammar for unicode_locale_id in Unicode Technical Standard #35 LDML § 3.2 Unicode Locale Identifier;
|
||||||
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale));
|
auto locale_id = ::Locale::parse_unicode_locale_id(locale);
|
||||||
if (!locale_id.has_value())
|
if (!locale_id.has_value())
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_t
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
// the unicode_language_id within locale contains no duplicate unicode_variant_subtag subtags; and
|
// the unicode_language_id within locale contains no duplicate unicode_variant_subtag subtags; and
|
||||||
if (TRY(contains_duplicate_variant(locale_id->language_id.variants)))
|
if (contains_duplicate_variant(locale_id->language_id.variants))
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
// if locale contains an extensions* component, that component
|
// if locale contains an extensions* component, that component
|
||||||
|
@ -72,7 +72,7 @@ ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_t
|
||||||
// the tlang component contains no duplicate unicode_variant_subtag subtags.
|
// the tlang component contains no duplicate unicode_variant_subtag subtags.
|
||||||
if (auto* transformed = extension.get_pointer<::Locale::TransformedExtension>()) {
|
if (auto* transformed = extension.get_pointer<::Locale::TransformedExtension>()) {
|
||||||
auto& language = transformed->language;
|
auto& language = transformed->language;
|
||||||
if (language.has_value() && TRY(contains_duplicate_variant(language->variants)))
|
if (language.has_value() && contains_duplicate_variant(language->variants))
|
||||||
return Optional<::Locale::LocaleID> {};
|
return Optional<::Locale::LocaleID> {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ ThrowCompletionOr<String> canonicalize_unicode_locale_id(VM& vm, ::Locale::Local
|
||||||
|
|
||||||
// 1. Let localeId be the string locale after performing the algorithm to transform it to canonical syntax per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers.
|
// 1. Let localeId be the string locale after performing the algorithm to transform it to canonical syntax per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers.
|
||||||
// 2. Let localeId be the string localeId after performing the algorithm to transform it to canonical form.
|
// 2. Let localeId be the string localeId after performing the algorithm to transform it to canonical form.
|
||||||
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::canonicalize_unicode_locale_id(locale));
|
auto locale_id = ::Locale::canonicalize_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
// 4. Return localeId.
|
// 4. Return localeId.
|
||||||
|
@ -302,12 +302,12 @@ static ThrowCompletionOr<MatcherResult> lookup_matcher(VM& vm, Vector<String> co
|
||||||
|
|
||||||
// 2. For each element locale of requestedLocales, do
|
// 2. For each element locale of requestedLocales, do
|
||||||
for (auto const& locale : requested_locales) {
|
for (auto const& locale : requested_locales) {
|
||||||
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale));
|
auto locale_id = ::Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
// a. Let noExtensionsLocale be the String value that is locale with any Unicode locale extension sequences removed.
|
// a. Let noExtensionsLocale be the String value that is locale with any Unicode locale extension sequences removed.
|
||||||
auto extensions = locale_id->remove_extension_type<::Locale::LocaleExtension>();
|
auto extensions = locale_id->remove_extension_type<::Locale::LocaleExtension>();
|
||||||
auto no_extensions_locale = TRY_OR_THROW_OOM(vm, locale_id->to_string());
|
auto no_extensions_locale = locale_id->to_string();
|
||||||
|
|
||||||
// b. Let availableLocale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
|
// b. Let availableLocale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
|
||||||
auto available_locale = best_available_locale(no_extensions_locale);
|
auto available_locale = best_available_locale(no_extensions_locale);
|
||||||
|
@ -433,7 +433,7 @@ ThrowCompletionOr<LocaleResult> resolve_locale(VM& vm, Vector<String> const& req
|
||||||
// NOTE: ECMA-402 assumes keyLocaleData is sorted by locale preference. Our list is sorted
|
// NOTE: ECMA-402 assumes keyLocaleData is sorted by locale preference. Our list is sorted
|
||||||
// alphabetically, so we get the locale's preferred value from LibUnicode.
|
// alphabetically, so we get the locale's preferred value from LibUnicode.
|
||||||
Optional<String> value;
|
Optional<String> value;
|
||||||
if (auto preference = TRY_OR_THROW_OOM(vm, ::Locale::get_preferred_keyword_value_for_locale(found_locale, key)); preference.has_value())
|
if (auto preference = ::Locale::get_preferred_keyword_value_for_locale(found_locale, key); preference.has_value())
|
||||||
value = TRY_OR_THROW_OOM(vm, String::from_utf8(*preference));
|
value = TRY_OR_THROW_OOM(vm, String::from_utf8(*preference));
|
||||||
|
|
||||||
// g. Let supportedExtensionAddition be "".
|
// g. Let supportedExtensionAddition be "".
|
||||||
|
@ -481,7 +481,7 @@ ThrowCompletionOr<LocaleResult> resolve_locale(VM& vm, Vector<String> const& req
|
||||||
if (options_value.has_value()) {
|
if (options_value.has_value()) {
|
||||||
// 1. Let optionsValue be the string optionsValue after performing the algorithm steps to transform Unicode extension values to canonical syntax per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers, treating key as ukey and optionsValue as uvalue productions.
|
// 1. Let optionsValue be the string optionsValue after performing the algorithm steps to transform Unicode extension values to canonical syntax per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers, treating key as ukey and optionsValue as uvalue productions.
|
||||||
// 2. Let optionsValue be the string optionsValue after performing the algorithm steps to replace Unicode extension values with their canonical form per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers, treating key as ukey and optionsValue as uvalue productions.
|
// 2. Let optionsValue be the string optionsValue after performing the algorithm steps to replace Unicode extension values with their canonical form per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers, treating key as ukey and optionsValue as uvalue productions.
|
||||||
TRY_OR_THROW_OOM(vm, ::Locale::canonicalize_unicode_extension_values(key, *options_value, true));
|
::Locale::canonicalize_unicode_extension_values(key, *options_value, true);
|
||||||
|
|
||||||
// 3. If optionsValue is the empty String, then
|
// 3. If optionsValue is the empty String, then
|
||||||
if (options_value->is_empty()) {
|
if (options_value->is_empty()) {
|
||||||
|
@ -509,7 +509,7 @@ ThrowCompletionOr<LocaleResult> resolve_locale(VM& vm, Vector<String> const& req
|
||||||
|
|
||||||
// 10. If supportedExtension is not "-u", then
|
// 10. If supportedExtension is not "-u", then
|
||||||
if (!supported_extension.keywords.is_empty()) {
|
if (!supported_extension.keywords.is_empty()) {
|
||||||
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(found_locale));
|
auto locale_id = ::Locale::parse_unicode_locale_id(found_locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
// a. Set foundLocale to InsertUnicodeExtensionAndCanonicalize(foundLocale, supportedExtension).
|
// a. Set foundLocale to InsertUnicodeExtensionAndCanonicalize(foundLocale, supportedExtension).
|
||||||
|
@ -531,12 +531,12 @@ static ThrowCompletionOr<Vector<String>> lookup_supported_locales(VM& vm, Vector
|
||||||
|
|
||||||
// 2. For each element locale of requestedLocales, do
|
// 2. For each element locale of requestedLocales, do
|
||||||
for (auto const& locale : requested_locales) {
|
for (auto const& locale : requested_locales) {
|
||||||
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale));
|
auto locale_id = ::Locale::parse_unicode_locale_id(locale);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
// a. Let noExtensionsLocale be the String value that is locale with any Unicode locale extension sequences removed.
|
// a. Let noExtensionsLocale be the String value that is locale with any Unicode locale extension sequences removed.
|
||||||
locale_id->remove_extension_type<::Locale::LocaleExtension>();
|
locale_id->remove_extension_type<::Locale::LocaleExtension>();
|
||||||
auto no_extensions_locale = TRY_OR_THROW_OOM(vm, locale_id->to_string());
|
auto no_extensions_locale = locale_id->to_string();
|
||||||
|
|
||||||
// b. Let availableLocale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
|
// b. Let availableLocale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
|
||||||
auto available_locale = best_available_locale(no_extensions_locale);
|
auto available_locale = best_available_locale(no_extensions_locale);
|
||||||
|
|
|
@ -719,7 +719,7 @@ ThrowCompletionOr<Vector<PatternPartition>> format_date_time_pattern(VM& vm, Dat
|
||||||
// Non-standard, TR-35 requires the decimal separator before injected {fractionalSecondDigits} partitions
|
// Non-standard, TR-35 requires the decimal separator before injected {fractionalSecondDigits} partitions
|
||||||
// to adhere to the selected locale. This depends on other generated data, so it is deferred to here.
|
// to adhere to the selected locale. This depends on other generated data, so it is deferred to here.
|
||||||
else if (part == "decimal"sv) {
|
else if (part == "decimal"sv) {
|
||||||
auto decimal_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(data_locale, date_time_format.numbering_system(), ::Locale::NumericSymbol::Decimal)).value_or("."sv);
|
auto decimal_symbol = ::Locale::get_number_system_symbol(data_locale, date_time_format.numbering_system(), ::Locale::NumericSymbol::Decimal).value_or("."sv);
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "literal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(decimal_symbol)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "literal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(decimal_symbol)) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ ThrowCompletionOr<Value> canonical_code_for_display_names(VM& vm, DisplayNames::
|
||||||
// 1. If type is "language", then
|
// 1. If type is "language", then
|
||||||
if (type == DisplayNames::Type::Language) {
|
if (type == DisplayNames::Type::Language) {
|
||||||
// a. If code does not match the unicode_language_id production, throw a RangeError exception.
|
// a. If code does not match the unicode_language_id production, throw a RangeError exception.
|
||||||
if (!TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_language_id(code)).has_value())
|
if (!::Locale::parse_unicode_language_id(code).has_value())
|
||||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, code, "language"sv);
|
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, code, "language"sv);
|
||||||
|
|
||||||
// b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception.
|
// b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception.
|
||||||
|
|
|
@ -63,7 +63,7 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto locale = MUST_OR_THROW_OOM(is_structurally_valid_language_tag(vm, code_string)); locale.has_value())
|
if (auto locale = MUST_OR_THROW_OOM(is_structurally_valid_language_tag(vm, code_string)); locale.has_value())
|
||||||
formatted_result = TRY_OR_THROW_OOM(vm, ::Locale::format_locale_for_display(display_names->locale(), locale.release_value()));
|
formatted_result = ::Locale::format_locale_for_display(display_names->locale(), locale.release_value());
|
||||||
break;
|
break;
|
||||||
case DisplayNames::Type::Region:
|
case DisplayNames::Type::Region:
|
||||||
result = ::Locale::get_locale_territory_mapping(display_names->locale(), code_string);
|
result = ::Locale::get_locale_territory_mapping(display_names->locale(), code_string);
|
||||||
|
|
|
@ -482,7 +482,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_duration_format_pattern(VM
|
||||||
// c. If nextValue is not 0 or nextDisplay is not "auto", then
|
// c. If nextValue is not 0 or nextDisplay is not "auto", then
|
||||||
if (next_value != 0.0 || next_display != DurationFormat::Display::Auto) {
|
if (next_value != 0.0 || next_display != DurationFormat::Display::Auto) {
|
||||||
// i. Let separator be dataLocaleData.[[formats]].[[digital]].[[separator]].
|
// i. Let separator be dataLocaleData.[[formats]].[[digital]].[[separator]].
|
||||||
auto separator = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(data_locale, duration_format.numbering_system(), ::Locale::NumericSymbol::TimeSeparator)).value_or(":"sv);
|
auto separator = ::Locale::get_number_system_symbol(data_locale, duration_format.numbering_system(), ::Locale::NumericSymbol::TimeSeparator).value_or(":"sv);
|
||||||
|
|
||||||
// ii. Append the new Record { [[Type]]: "literal", [[Value]]: separator} to the end of result.
|
// ii. Append the new Record { [[Type]]: "literal", [[Value]]: separator} to the end of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "literal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(separator)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "literal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(separator)) }));
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
|
|
||||||
namespace JS::Intl {
|
namespace JS::Intl {
|
||||||
|
|
||||||
ThrowCompletionOr<NonnullGCPtr<Locale>> Locale::create(Realm& realm, ::Locale::LocaleID locale_id)
|
NonnullGCPtr<Locale> Locale::create(Realm& realm, ::Locale::LocaleID locale_id)
|
||||||
{
|
{
|
||||||
auto locale = realm.heap().allocate<Locale>(realm, realm.intrinsics().intl_locale_prototype());
|
auto locale = realm.heap().allocate<Locale>(realm, realm.intrinsics().intl_locale_prototype());
|
||||||
locale->set_locale(TRY_OR_THROW_OOM(realm.vm(), locale_id.to_string()));
|
locale->set_locale(locale_id.to_string());
|
||||||
|
|
||||||
for (auto& extension : locale_id.extensions) {
|
for (auto& extension : locale_id.extensions) {
|
||||||
if (!extension.has<::Locale::LocaleExtension>())
|
if (!extension.has<::Locale::LocaleExtension>())
|
||||||
|
@ -51,7 +51,7 @@ Locale::Locale(Object& prototype)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1.1 CreateArrayFromListOrRestricted ( list , restricted )
|
// 1.1.1 CreateArrayFromListOrRestricted ( list , restricted )
|
||||||
static ThrowCompletionOr<NonnullGCPtr<Array>> create_array_from_list_or_restricted(VM& vm, Vector<StringView> list, Optional<String> restricted)
|
static NonnullGCPtr<Array> create_array_from_list_or_restricted(VM& vm, Vector<StringView> list, Optional<String> restricted)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
|
@ -63,12 +63,12 @@ static ThrowCompletionOr<NonnullGCPtr<Array>> create_array_from_list_or_restrict
|
||||||
|
|
||||||
// 2. Return ! CreateArrayFromList( list ).
|
// 2. Return ! CreateArrayFromList( list ).
|
||||||
return Array::create_from<StringView>(realm, list, [&vm](auto value) {
|
return Array::create_from<StringView>(realm, list, [&vm](auto value) {
|
||||||
return PrimitiveString::create(vm, String::from_utf8(value).release_value());
|
return PrimitiveString::create(vm, MUST(String::from_utf8(value)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1.2 CalendarsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-calendars-of-locale
|
// 1.1.2 CalendarsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-calendars-of-locale
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> calendars_of_locale(VM& vm, Locale const& locale_object)
|
NonnullGCPtr<Array> calendars_of_locale(VM& vm, Locale const& locale_object)
|
||||||
{
|
{
|
||||||
// 1. Let restricted be loc.[[Calendar]].
|
// 1. Let restricted be loc.[[Calendar]].
|
||||||
Optional<String> restricted = locale_object.has_calendar() ? locale_object.calendar() : Optional<String> {};
|
Optional<String> restricted = locale_object.has_calendar() ? locale_object.calendar() : Optional<String> {};
|
||||||
|
@ -77,17 +77,17 @@ ThrowCompletionOr<NonnullGCPtr<Array>> calendars_of_locale(VM& vm, Locale const&
|
||||||
auto const& locale = locale_object.locale();
|
auto const& locale = locale_object.locale();
|
||||||
|
|
||||||
// 3. Assert: locale matches the unicode_locale_id production.
|
// 3. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
|
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
|
||||||
|
|
||||||
// 4. Let list be a List of 1 or more unique canonical calendar 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 date and time formatting in locale.
|
// 4. Let list be a List of 1 or more unique canonical calendar 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 date and time formatting in locale.
|
||||||
auto list = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "ca"sv));
|
auto list = ::Locale::get_keywords_for_locale(locale, "ca"sv);
|
||||||
|
|
||||||
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
||||||
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1.3 CollationsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-collations-of-locale
|
// 1.1.3 CollationsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-collations-of-locale
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> collations_of_locale(VM& vm, Locale const& locale_object)
|
NonnullGCPtr<Array> collations_of_locale(VM& vm, Locale const& locale_object)
|
||||||
{
|
{
|
||||||
// 1. Let restricted be loc.[[Collation]].
|
// 1. Let restricted be loc.[[Collation]].
|
||||||
Optional<String> restricted = locale_object.has_collation() ? locale_object.collation() : Optional<String> {};
|
Optional<String> restricted = locale_object.has_collation() ? locale_object.collation() : Optional<String> {};
|
||||||
|
@ -96,17 +96,17 @@ ThrowCompletionOr<NonnullGCPtr<Array>> collations_of_locale(VM& vm, Locale const
|
||||||
auto const& locale = locale_object.locale();
|
auto const& locale = locale_object.locale();
|
||||||
|
|
||||||
// 3. Assert: locale matches the unicode_locale_id production.
|
// 3. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
|
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
|
||||||
|
|
||||||
// 4. Let list be a List of 1 or more unique canonical collation identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, ordered as if an Array of the same values had been sorted, using %Array.prototype.sort% using undefined as comparefn, of those in common use for string comparison in locale. The values "standard" and "search" must be excluded from list.
|
// 4. Let list be a List of 1 or more unique canonical collation identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, ordered as if an Array of the same values had been sorted, using %Array.prototype.sort% using undefined as comparefn, of those in common use for string comparison in locale. The values "standard" and "search" must be excluded from list.
|
||||||
auto list = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "co"sv));
|
auto list = ::Locale::get_keywords_for_locale(locale, "co"sv);
|
||||||
|
|
||||||
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
||||||
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1.4 HourCyclesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-hour-cycles-of-locale
|
// 1.1.4 HourCyclesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-hour-cycles-of-locale
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> hour_cycles_of_locale(VM& vm, Locale const& locale_object)
|
NonnullGCPtr<Array> hour_cycles_of_locale(VM& vm, Locale const& locale_object)
|
||||||
{
|
{
|
||||||
// 1. Let restricted be loc.[[HourCycle]].
|
// 1. Let restricted be loc.[[HourCycle]].
|
||||||
Optional<String> restricted = locale_object.has_hour_cycle() ? locale_object.hour_cycle() : Optional<String> {};
|
Optional<String> restricted = locale_object.has_hour_cycle() ? locale_object.hour_cycle() : Optional<String> {};
|
||||||
|
@ -115,17 +115,17 @@ ThrowCompletionOr<NonnullGCPtr<Array>> hour_cycles_of_locale(VM& vm, Locale cons
|
||||||
auto const& locale = locale_object.locale();
|
auto const& locale = locale_object.locale();
|
||||||
|
|
||||||
// 3. Assert: locale matches the unicode_locale_id production.
|
// 3. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
|
VERIFY(::Locale::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.
|
// 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 = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "hc"sv));
|
auto list = ::Locale::get_keywords_for_locale(locale, "hc"sv);
|
||||||
|
|
||||||
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
||||||
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1.5 NumberingSystemsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-numbering-systems-of-locale
|
// 1.1.5 NumberingSystemsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-numbering-systems-of-locale
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM& vm, Locale const& locale_object)
|
NonnullGCPtr<Array> numbering_systems_of_locale(VM& vm, Locale const& locale_object)
|
||||||
{
|
{
|
||||||
// 1. Let restricted be loc.[[NumberingSystem]].
|
// 1. Let restricted be loc.[[NumberingSystem]].
|
||||||
Optional<String> restricted = locale_object.has_numbering_system() ? locale_object.numbering_system() : Optional<String> {};
|
Optional<String> restricted = locale_object.has_numbering_system() ? locale_object.numbering_system() : Optional<String> {};
|
||||||
|
@ -134,10 +134,10 @@ ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM& vm, Local
|
||||||
auto const& locale = locale_object.locale();
|
auto const& locale = locale_object.locale();
|
||||||
|
|
||||||
// 3. Assert: locale matches the unicode_locale_id production.
|
// 3. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
|
VERIFY(::Locale::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.
|
// 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 = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "nu"sv));
|
auto list = ::Locale::get_keywords_for_locale(locale, "nu"sv);
|
||||||
|
|
||||||
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
|
||||||
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
|
||||||
|
@ -145,7 +145,7 @@ ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM& vm, Local
|
||||||
|
|
||||||
// 1.1.6 TimeZonesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-time-zones-of-locale
|
// 1.1.6 TimeZonesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-time-zones-of-locale
|
||||||
// NOTE: Our implementation takes a region rather than a Locale object to avoid needlessly parsing the locale twice.
|
// NOTE: Our implementation takes a region rather than a Locale object to avoid needlessly parsing the locale twice.
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> time_zones_of_locale(VM& vm, StringView region)
|
NonnullGCPtr<Array> time_zones_of_locale(VM& vm, StringView region)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
|
@ -164,13 +164,13 @@ ThrowCompletionOr<NonnullGCPtr<Array>> time_zones_of_locale(VM& vm, StringView r
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1.7 CharacterDirectionOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-character-direction-of-locale
|
// 1.1.7 CharacterDirectionOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-character-direction-of-locale
|
||||||
ThrowCompletionOr<StringView> character_direction_of_locale(VM& vm, Locale const& locale_object)
|
StringView character_direction_of_locale(Locale const& locale_object)
|
||||||
{
|
{
|
||||||
// 1. Let locale be loc.[[Locale]].
|
// 1. Let locale be loc.[[Locale]].
|
||||||
auto const& locale = locale_object.locale();
|
auto const& locale = locale_object.locale();
|
||||||
|
|
||||||
// 2. Assert: locale matches the unicode_locale_id production.
|
// 2. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
|
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
|
||||||
|
|
||||||
// 3. If the default general ordering of characters (characterOrder) within a line in locale is right-to-left, return "rtl".
|
// 3. If the default general ordering of characters (characterOrder) within a line in locale is right-to-left, return "rtl".
|
||||||
// NOTE: LibUnicode handles both LTR and RTL character orders in this call, not just RTL. We then fallback to LTR
|
// NOTE: LibUnicode handles both LTR and RTL character orders in this call, not just RTL. We then fallback to LTR
|
||||||
|
@ -231,7 +231,7 @@ ThrowCompletionOr<WeekInfo> week_info_of_locale(VM& vm, Locale const& locale_obj
|
||||||
auto const& locale = locale_object.locale();
|
auto const& locale = locale_object.locale();
|
||||||
|
|
||||||
// 2. Assert: locale matches the unicode_locale_id production.
|
// 2. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
|
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
|
||||||
|
|
||||||
// 3. Return a record whose fields are defined by Table 1, with values based on locale.
|
// 3. Return a record whose fields are defined by Table 1, with values based on locale.
|
||||||
WeekInfo week_info {};
|
WeekInfo week_info {};
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Locale final : public Object {
|
||||||
JS_OBJECT(Locale, Object);
|
JS_OBJECT(Locale, Object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ThrowCompletionOr<NonnullGCPtr<Locale>> create(Realm&, ::Locale::LocaleID);
|
static NonnullGCPtr<Locale> create(Realm&, ::Locale::LocaleID);
|
||||||
|
|
||||||
static constexpr auto relevant_extension_keys()
|
static constexpr auto relevant_extension_keys()
|
||||||
{
|
{
|
||||||
|
@ -82,12 +82,12 @@ struct WeekInfo {
|
||||||
Vector<u8> weekend; // [[Weekend]]
|
Vector<u8> weekend; // [[Weekend]]
|
||||||
};
|
};
|
||||||
|
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> calendars_of_locale(VM&, Locale const&);
|
NonnullGCPtr<Array> calendars_of_locale(VM&, Locale const&);
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> collations_of_locale(VM&, Locale const& locale);
|
NonnullGCPtr<Array> collations_of_locale(VM&, Locale const& locale);
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> hour_cycles_of_locale(VM&, Locale const& locale);
|
NonnullGCPtr<Array> hour_cycles_of_locale(VM&, Locale const& locale);
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM&, Locale const&);
|
NonnullGCPtr<Array> numbering_systems_of_locale(VM&, Locale const&);
|
||||||
ThrowCompletionOr<NonnullGCPtr<Array>> time_zones_of_locale(VM&, StringView region);
|
NonnullGCPtr<Array> time_zones_of_locale(VM&, StringView region);
|
||||||
ThrowCompletionOr<StringView> character_direction_of_locale(VM&, Locale const&);
|
StringView character_direction_of_locale(Locale const&);
|
||||||
ThrowCompletionOr<WeekInfo> week_info_of_locale(VM&, Locale const&);
|
ThrowCompletionOr<WeekInfo> week_info_of_locale(VM&, Locale const&);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ static ThrowCompletionOr<String> apply_options_to_tag(VM& vm, StringView tag, Ob
|
||||||
auto canonicalized_tag = MUST_OR_THROW_OOM(canonicalize_unicode_locale_id(vm, *locale_id));
|
auto canonicalized_tag = MUST_OR_THROW_OOM(canonicalize_unicode_locale_id(vm, *locale_id));
|
||||||
|
|
||||||
// 11. Assert: tag matches the unicode_locale_id production.
|
// 11. Assert: tag matches the unicode_locale_id production.
|
||||||
locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(canonicalized_tag));
|
locale_id = ::Locale::parse_unicode_locale_id(canonicalized_tag);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
// 12. Let languageId be the substring of tag corresponding to the unicode_language_id production.
|
// 12. Let languageId be the substring of tag corresponding to the unicode_language_id production.
|
||||||
|
@ -109,7 +109,7 @@ static ThrowCompletionOr<LocaleAndKeys> apply_unicode_extension_to_tag(VM& vm, S
|
||||||
{
|
{
|
||||||
// 1. Assert: Type(tag) is String.
|
// 1. Assert: Type(tag) is String.
|
||||||
// 2. Assert: tag matches the unicode_locale_id production.
|
// 2. Assert: tag matches the unicode_locale_id production.
|
||||||
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(tag));
|
auto locale_id = ::Locale::parse_unicode_locale_id(tag);
|
||||||
VERIFY(locale_id.has_value());
|
VERIFY(locale_id.has_value());
|
||||||
|
|
||||||
Vector<String> attributes;
|
Vector<String> attributes;
|
||||||
|
@ -198,7 +198,7 @@ static ThrowCompletionOr<LocaleAndKeys> apply_unicode_extension_to_tag(VM& vm, S
|
||||||
|
|
||||||
// 7. Let locale be the String value that is tag with any Unicode locale extension sequences removed.
|
// 7. Let locale be the String value that is tag with any Unicode locale extension sequences removed.
|
||||||
locale_id->remove_extension_type<::Locale::LocaleExtension>();
|
locale_id->remove_extension_type<::Locale::LocaleExtension>();
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, locale_id->to_string());
|
auto locale = locale_id->to_string();
|
||||||
|
|
||||||
// 8. Let newExtension be a Unicode BCP 47 U Extension based on attributes and keywords.
|
// 8. Let newExtension be a Unicode BCP 47 U Extension based on attributes and keywords.
|
||||||
::Locale::LocaleExtension new_extension { move(attributes), move(keywords) };
|
::Locale::LocaleExtension new_extension { move(attributes), move(keywords) };
|
||||||
|
|
|
@ -61,15 +61,15 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::maximize)
|
||||||
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
|
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
VERIFY(locale.has_value());
|
VERIFY(locale.has_value());
|
||||||
|
|
||||||
// 3. Let maximal be the result of the Add Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set maximal to loc.[[Locale]].
|
// 3. Let maximal be the result of the Add Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set maximal to loc.[[Locale]].
|
||||||
if (auto maximal = TRY_OR_THROW_OOM(vm, ::Locale::add_likely_subtags(locale->language_id)); maximal.has_value())
|
if (auto maximal = ::Locale::add_likely_subtags(locale->language_id); maximal.has_value())
|
||||||
locale->language_id = maximal.release_value();
|
locale->language_id = maximal.release_value();
|
||||||
|
|
||||||
// 4. Return ! Construct(%Locale%, maximal).
|
// 4. Return ! Construct(%Locale%, maximal).
|
||||||
return MUST_OR_THROW_OOM(Locale::create(realm, locale.release_value()));
|
return Locale::create(realm, locale.release_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 14.3.4 Intl.Locale.prototype.minimize ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
|
// 14.3.4 Intl.Locale.prototype.minimize ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
|
||||||
|
@ -81,15 +81,15 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::minimize)
|
||||||
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
|
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
VERIFY(locale.has_value());
|
VERIFY(locale.has_value());
|
||||||
|
|
||||||
// 3. Let minimal be the result of the Remove Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set minimal to loc.[[Locale]].
|
// 3. Let minimal be the result of the Remove Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set minimal to loc.[[Locale]].
|
||||||
if (auto minimal = TRY_OR_THROW_OOM(vm, ::Locale::remove_likely_subtags(locale->language_id)); minimal.has_value())
|
if (auto minimal = ::Locale::remove_likely_subtags(locale->language_id); minimal.has_value())
|
||||||
locale->language_id = minimal.release_value();
|
locale->language_id = minimal.release_value();
|
||||||
|
|
||||||
// 4. Return ! Construct(%Locale%, minimal).
|
// 4. Return ! Construct(%Locale%, minimal).
|
||||||
return MUST_OR_THROW_OOM(Locale::create(realm, locale.release_value()));
|
return Locale::create(realm, locale.release_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 14.3.5 Intl.Locale.prototype.toString ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
|
// 14.3.5 Intl.Locale.prototype.toString ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
|
||||||
|
@ -111,11 +111,11 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::base_name)
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
// 3. Let locale be loc.[[Locale]].
|
// 3. Let locale be loc.[[Locale]].
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
VERIFY(locale.has_value());
|
VERIFY(locale.has_value());
|
||||||
|
|
||||||
// 4. Return the substring of locale corresponding to the unicode_language_id production.
|
// 4. Return the substring of locale corresponding to the unicode_language_id production.
|
||||||
return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, locale->language_id.to_string()));
|
return PrimitiveString::create(vm, locale->language_id.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#define JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES \
|
#define JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES \
|
||||||
|
@ -160,7 +160,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::language)
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
// 3. Let locale be loc.[[Locale]].
|
// 3. Let locale be loc.[[Locale]].
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
|
|
||||||
// 4. Assert: locale matches the unicode_locale_id production.
|
// 4. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(locale.has_value());
|
VERIFY(locale.has_value());
|
||||||
|
@ -177,7 +177,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::script)
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
// 3. Let locale be loc.[[Locale]].
|
// 3. Let locale be loc.[[Locale]].
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
|
|
||||||
// 4. Assert: locale matches the unicode_locale_id production.
|
// 4. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(locale.has_value());
|
VERIFY(locale.has_value());
|
||||||
|
@ -198,7 +198,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
// 3. Let locale be loc.[[Locale]].
|
// 3. Let locale be loc.[[Locale]].
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
|
|
||||||
// 4. Assert: locale matches the unicode_locale_id production.
|
// 4. Assert: locale matches the unicode_locale_id production.
|
||||||
VERIFY(locale.has_value());
|
VERIFY(locale.has_value());
|
||||||
|
@ -221,11 +221,11 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
|
||||||
// 1.4.17 get Intl.Locale.prototype.collations, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.collations
|
// 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.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
|
// 1.4.19 get Intl.Locale.prototype.numberingSystems, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.numberingSystems
|
||||||
#define __JS_ENUMERATE(keyword) \
|
#define __JS_ENUMERATE(keyword) \
|
||||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \
|
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \
|
||||||
{ \
|
{ \
|
||||||
auto locale_object = TRY(typed_this_object(vm)); \
|
auto locale_object = TRY(typed_this_object(vm)); \
|
||||||
return MUST_OR_THROW_OOM(keyword##_of_locale(vm, locale_object)); \
|
return keyword##_of_locale(vm, locale_object); \
|
||||||
}
|
}
|
||||||
JS_ENUMERATE_LOCALE_INFO_PROPERTIES
|
JS_ENUMERATE_LOCALE_INFO_PROPERTIES
|
||||||
#undef __JS_ENUMERATE
|
#undef __JS_ENUMERATE
|
||||||
|
@ -238,14 +238,14 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::time_zones)
|
||||||
auto locale_object = TRY(typed_this_object(vm));
|
auto locale_object = TRY(typed_this_object(vm));
|
||||||
|
|
||||||
// 3. Let locale be loc.[[Locale]].
|
// 3. Let locale be loc.[[Locale]].
|
||||||
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
|
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
|
||||||
|
|
||||||
// 4. If the unicode_language_id production of locale does not contain the ["-" unicode_region_subtag] sequence, return undefined.
|
// 4. If the unicode_language_id production of locale does not contain the ["-" unicode_region_subtag] sequence, return undefined.
|
||||||
if (!locale.has_value() || !locale->language_id.region.has_value())
|
if (!locale.has_value() || !locale->language_id.region.has_value())
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
|
||||||
// 5. Return ! TimeZonesOfLocale(loc).
|
// 5. Return ! TimeZonesOfLocale(loc).
|
||||||
return MUST_OR_THROW_OOM(time_zones_of_locale(vm, locale->language_id.region.value()));
|
return time_zones_of_locale(vm, locale->language_id.region.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.4.21 get Intl.Locale.prototype.textInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.textInfo
|
// 1.4.21 get Intl.Locale.prototype.textInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.textInfo
|
||||||
|
@ -261,7 +261,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::text_info)
|
||||||
auto info = Object::create(realm, realm.intrinsics().object_prototype());
|
auto info = Object::create(realm, realm.intrinsics().object_prototype());
|
||||||
|
|
||||||
// 4. Let dir be ! CharacterDirectionOfLocale(loc).
|
// 4. Let dir be ! CharacterDirectionOfLocale(loc).
|
||||||
auto direction = MUST_OR_THROW_OOM(character_direction_of_locale(vm, locale_object));
|
auto direction = character_direction_of_locale(locale_object);
|
||||||
|
|
||||||
// 5. Perform ! CreateDataPropertyOrThrow(info, "direction", dir).
|
// 5. Perform ! CreateDataPropertyOrThrow(info, "direction", dir).
|
||||||
MUST(info->create_data_property_or_throw(vm.names.direction, PrimitiveString::create(vm, direction)));
|
MUST(info->create_data_property_or_throw(vm.names.direction, PrimitiveString::create(vm, direction)));
|
||||||
|
|
|
@ -537,13 +537,13 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
|
||||||
// 2. If x is not-a-number, then
|
// 2. If x is not-a-number, then
|
||||||
if (number.is_nan()) {
|
if (number.is_nan()) {
|
||||||
// a. Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value.
|
// a. Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value.
|
||||||
auto symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::NaN)).value_or("NaN"sv);
|
auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::NaN).value_or("NaN"sv);
|
||||||
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
|
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
|
||||||
}
|
}
|
||||||
// 3. Else if x is positive-infinity, then
|
// 3. Else if x is positive-infinity, then
|
||||||
else if (number.is_positive_infinity()) {
|
else if (number.is_positive_infinity()) {
|
||||||
// a. Let n be an ILD String value indicating positive infinity.
|
// a. Let n be an ILD String value indicating positive infinity.
|
||||||
auto symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity)).value_or("infinity"sv);
|
auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv);
|
||||||
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
|
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
|
||||||
}
|
}
|
||||||
// 4. Else if x is negative-infinity, then
|
// 4. Else if x is negative-infinity, then
|
||||||
|
@ -551,7 +551,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
|
||||||
// a. Let n be an ILD String value indicating negative infinity.
|
// a. Let n be an ILD String value indicating negative infinity.
|
||||||
// NOTE: The CLDR does not contain unique strings for negative infinity. The negative sign will
|
// NOTE: The CLDR does not contain unique strings for negative infinity. The negative sign will
|
||||||
// be inserted by the pattern returned from GetNumberFormatPattern.
|
// be inserted by the pattern returned from GetNumberFormatPattern.
|
||||||
auto symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity)).value_or("infinity"sv);
|
auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv);
|
||||||
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
|
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
|
||||||
}
|
}
|
||||||
// 5. Else,
|
// 5. Else,
|
||||||
|
@ -617,7 +617,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
|
||||||
// d. Else if p is equal to "plusSign", then
|
// d. Else if p is equal to "plusSign", then
|
||||||
else if (part == "plusSign"sv) {
|
else if (part == "plusSign"sv) {
|
||||||
// i. Let plusSignSymbol be the ILND String representing the plus sign.
|
// i. Let plusSignSymbol be the ILND String representing the plus sign.
|
||||||
auto plus_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PlusSign)).value_or("+"sv);
|
auto plus_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PlusSign).value_or("+"sv);
|
||||||
// ii. Append a new Record { [[Type]]: "plusSign", [[Value]]: plusSignSymbol } as the last element of result.
|
// ii. Append a new Record { [[Type]]: "plusSign", [[Value]]: plusSignSymbol } as the last element of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "plusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(plus_sign_symbol)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "plusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(plus_sign_symbol)) }));
|
||||||
}
|
}
|
||||||
|
@ -625,7 +625,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
|
||||||
// e. Else if p is equal to "minusSign", then
|
// e. Else if p is equal to "minusSign", then
|
||||||
else if (part == "minusSign"sv) {
|
else if (part == "minusSign"sv) {
|
||||||
// i. Let minusSignSymbol be the ILND String representing the minus sign.
|
// i. Let minusSignSymbol be the ILND String representing the minus sign.
|
||||||
auto minus_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign)).value_or("-"sv);
|
auto minus_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign).value_or("-"sv);
|
||||||
// ii. Append a new Record { [[Type]]: "minusSign", [[Value]]: minusSignSymbol } as the last element of result.
|
// ii. Append a new Record { [[Type]]: "minusSign", [[Value]]: minusSignSymbol } as the last element of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "minusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(minus_sign_symbol)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "minusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(minus_sign_symbol)) }));
|
||||||
}
|
}
|
||||||
|
@ -633,7 +633,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
|
||||||
// f. Else if p is equal to "percentSign" and numberFormat.[[Style]] is "percent", then
|
// f. Else if p is equal to "percentSign" and numberFormat.[[Style]] is "percent", then
|
||||||
else if ((part == "percentSign"sv) && (number_format.style() == NumberFormat::Style::Percent)) {
|
else if ((part == "percentSign"sv) && (number_format.style() == NumberFormat::Style::Percent)) {
|
||||||
// i. Let percentSignSymbol be the ILND String representing the percent sign.
|
// i. Let percentSignSymbol be the ILND String representing the percent sign.
|
||||||
auto percent_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PercentSign)).value_or("%"sv);
|
auto percent_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PercentSign).value_or("%"sv);
|
||||||
// ii. Append a new Record { [[Type]]: "percentSign", [[Value]]: percentSignSymbol } as the last element of result.
|
// ii. Append a new Record { [[Type]]: "percentSign", [[Value]]: percentSignSymbol } as the last element of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "percentSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(percent_sign_symbol)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "percentSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(percent_sign_symbol)) }));
|
||||||
}
|
}
|
||||||
|
@ -744,7 +744,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
|
||||||
// 1. Let result be a new empty List.
|
// 1. Let result be a new empty List.
|
||||||
Vector<PatternPartition> result;
|
Vector<PatternPartition> result;
|
||||||
|
|
||||||
auto grouping_sizes = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_groupings(number_format.data_locale(), number_format.numbering_system()));
|
auto grouping_sizes = ::Locale::get_number_system_groupings(number_format.data_locale(), number_format.numbering_system());
|
||||||
if (!grouping_sizes.has_value())
|
if (!grouping_sizes.has_value())
|
||||||
return Vector<PatternPartition> {};
|
return Vector<PatternPartition> {};
|
||||||
|
|
||||||
|
@ -827,7 +827,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
|
||||||
// 7. Else,
|
// 7. Else,
|
||||||
else {
|
else {
|
||||||
// a. Let groupSepSymbol be the implementation-, locale-, and numbering system-dependent (ILND) String representing the grouping separator.
|
// a. Let groupSepSymbol be the implementation-, locale-, and numbering system-dependent (ILND) String representing the grouping separator.
|
||||||
auto group_sep_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Group)).value_or(","sv);
|
auto group_sep_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Group).value_or(","sv);
|
||||||
|
|
||||||
// b. Let groups be a List whose elements are, in left to right order, the substrings defined by ILND set of locations within the integer, which may depend on the value of numberFormat.[[UseGrouping]].
|
// b. Let groups be a List whose elements are, in left to right order, the substrings defined by ILND set of locations within the integer, which may depend on the value of numberFormat.[[UseGrouping]].
|
||||||
auto groups = MUST_OR_THROW_OOM(separate_integer_into_groups(vm, *grouping_sizes, move(integer), number_format.use_grouping()));
|
auto groups = MUST_OR_THROW_OOM(separate_integer_into_groups(vm, *grouping_sizes, move(integer), number_format.use_grouping()));
|
||||||
|
@ -854,7 +854,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
|
||||||
// 8. If fraction is not undefined, then
|
// 8. If fraction is not undefined, then
|
||||||
if (fraction.has_value()) {
|
if (fraction.has_value()) {
|
||||||
// a. Let decimalSepSymbol be the ILND String representing the decimal separator.
|
// a. Let decimalSepSymbol be the ILND String representing the decimal separator.
|
||||||
auto decimal_sep_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Decimal)).value_or("."sv);
|
auto decimal_sep_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Decimal).value_or("."sv);
|
||||||
// b. Append a new Record { [[Type]]: "decimal", [[Value]]: decimalSepSymbol } as the last element of result.
|
// b. Append a new Record { [[Type]]: "decimal", [[Value]]: decimalSepSymbol } as the last element of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "decimal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(decimal_sep_symbol)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "decimal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(decimal_sep_symbol)) }));
|
||||||
// c. Append a new Record { [[Type]]: "fraction", [[Value]]: fraction } as the last element of result.
|
// c. Append a new Record { [[Type]]: "fraction", [[Value]]: fraction } as the last element of result.
|
||||||
|
@ -878,7 +878,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
|
||||||
// vi. Else if p is equal to "scientificSeparator", then
|
// vi. Else if p is equal to "scientificSeparator", then
|
||||||
else if (part == "scientificSeparator"sv) {
|
else if (part == "scientificSeparator"sv) {
|
||||||
// 1. Let scientificSeparator be the ILND String representing the exponent separator.
|
// 1. Let scientificSeparator be the ILND String representing the exponent separator.
|
||||||
auto scientific_separator = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Exponential)).value_or("E"sv);
|
auto scientific_separator = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Exponential).value_or("E"sv);
|
||||||
// 2. Append a new Record { [[Type]]: "exponentSeparator", [[Value]]: scientificSeparator } as the last element of result.
|
// 2. Append a new Record { [[Type]]: "exponentSeparator", [[Value]]: scientificSeparator } as the last element of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "exponentSeparator"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(scientific_separator)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "exponentSeparator"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(scientific_separator)) }));
|
||||||
}
|
}
|
||||||
|
@ -887,7 +887,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
|
||||||
// 1. If exponent < 0, then
|
// 1. If exponent < 0, then
|
||||||
if (exponent < 0) {
|
if (exponent < 0) {
|
||||||
// a. Let minusSignSymbol be the ILND String representing the minus sign.
|
// a. Let minusSignSymbol be the ILND String representing the minus sign.
|
||||||
auto minus_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign)).value_or("-"sv);
|
auto minus_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign).value_or("-"sv);
|
||||||
|
|
||||||
// b. Append a new Record { [[Type]]: "exponentMinusSign", [[Value]]: minusSignSymbol } as the last element of result.
|
// b. Append a new Record { [[Type]]: "exponentMinusSign", [[Value]]: minusSignSymbol } as the last element of result.
|
||||||
TRY_OR_THROW_OOM(vm, result.try_append({ "exponentMinusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(minus_sign_symbol)) }));
|
TRY_OR_THROW_OOM(vm, result.try_append({ "exponentMinusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(minus_sign_symbol)) }));
|
||||||
|
@ -1854,7 +1854,7 @@ ThrowCompletionOr<Vector<PatternPartitionWithSource>> partition_number_range_pat
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Let rangeSeparator be an ILND String value used to separate two numbers.
|
// 7. Let rangeSeparator be an ILND String value used to separate two numbers.
|
||||||
auto range_separator_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::RangeSeparator)).value_or("-"sv);
|
auto range_separator_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::RangeSeparator).value_or("-"sv);
|
||||||
auto range_separator = TRY_OR_THROW_OOM(vm, ::Locale::augment_range_pattern(range_separator_symbol, result.last().value, end_result[0].value));
|
auto range_separator = TRY_OR_THROW_OOM(vm, ::Locale::augment_range_pattern(range_separator_symbol, result.last().value, end_result[0].value));
|
||||||
|
|
||||||
// 8. Append a new Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } element to result.
|
// 8. Append a new Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } element to result.
|
||||||
|
@ -1887,7 +1887,7 @@ ThrowCompletionOr<Vector<PatternPartitionWithSource>> partition_number_range_pat
|
||||||
ThrowCompletionOr<Vector<PatternPartitionWithSource>> format_approximately(VM& vm, NumberFormat& number_format, Vector<PatternPartitionWithSource> result)
|
ThrowCompletionOr<Vector<PatternPartitionWithSource>> format_approximately(VM& vm, NumberFormat& number_format, Vector<PatternPartitionWithSource> result)
|
||||||
{
|
{
|
||||||
// 1. Let approximatelySign be an ILND String value used to signify that a number is approximate.
|
// 1. Let approximatelySign be an ILND String value used to signify that a number is approximate.
|
||||||
auto approximately_sign = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::ApproximatelySign));
|
auto approximately_sign = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::ApproximatelySign);
|
||||||
|
|
||||||
// 2. If approximatelySign is not empty, insert a new Record { [[Type]]: "approximatelySign", [[Value]]: approximatelySign } at an ILND index in result. For example, if numberFormat has [[Locale]] "en-US" and [[NumberingSystem]] "latn" and [[Style]] "decimal", the new Record might be inserted before the first element of result.
|
// 2. If approximatelySign is not empty, insert a new Record { [[Type]]: "approximatelySign", [[Value]]: approximatelySign } at an ILND index in result. For example, if numberFormat has [[Locale]] "en-US" and [[NumberingSystem]] "latn" and [[Style]] "decimal", the new Record might be inserted before the first element of result.
|
||||||
if (approximately_sign.has_value() && !approximately_sign->is_empty()) {
|
if (approximately_sign.has_value() && !approximately_sign->is_empty()) {
|
||||||
|
|
|
@ -1262,18 +1262,18 @@ static ThrowCompletionOr<String> transform_case(VM& vm, String const& string, Va
|
||||||
// 2. If requestedLocales is not an empty List, then
|
// 2. If requestedLocales is not an empty List, then
|
||||||
if (!requested_locales.is_empty()) {
|
if (!requested_locales.is_empty()) {
|
||||||
// a. Let requestedLocale be requestedLocales[0].
|
// a. Let requestedLocale be requestedLocales[0].
|
||||||
requested_locale = TRY_OR_THROW_OOM(vm, Locale::parse_unicode_locale_id(requested_locales[0]));
|
requested_locale = Locale::parse_unicode_locale_id(requested_locales[0]);
|
||||||
}
|
}
|
||||||
// 3. Else,
|
// 3. Else,
|
||||||
else {
|
else {
|
||||||
// a. Let requestedLocale be ! DefaultLocale().
|
// a. Let requestedLocale be ! DefaultLocale().
|
||||||
requested_locale = TRY_OR_THROW_OOM(vm, Locale::parse_unicode_locale_id(Locale::default_locale()));
|
requested_locale = Locale::parse_unicode_locale_id(Locale::default_locale());
|
||||||
}
|
}
|
||||||
VERIFY(requested_locale.has_value());
|
VERIFY(requested_locale.has_value());
|
||||||
|
|
||||||
// 4. Let noExtensionsLocale be the String value that is requestedLocale with any Unicode locale extension sequences (6.2.1) removed.
|
// 4. Let noExtensionsLocale be the String value that is requestedLocale with any Unicode locale extension sequences (6.2.1) removed.
|
||||||
requested_locale->remove_extension_type<Locale::LocaleExtension>();
|
requested_locale->remove_extension_type<Locale::LocaleExtension>();
|
||||||
auto no_extensions_locale = TRY_OR_THROW_OOM(vm, requested_locale->to_string());
|
auto no_extensions_locale = requested_locale->to_string();
|
||||||
|
|
||||||
// 5. Let availableLocales be a List with language tags that includes the languages for which the Unicode Character Database contains language sensitive case mappings. Implementations may add additional language tags if they support case mapping for additional locales.
|
// 5. Let availableLocales be a List with language tags that includes the languages for which the Unicode Character Database contains language sensitive case mappings. Implementations may add additional language tags if they support case mapping for additional locales.
|
||||||
// 6. Let locale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
|
// 6. Let locale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
|
||||||
|
|
|
@ -109,12 +109,12 @@ static ErrorOr<T> find_regional_values_for_locale(StringView locale, GetRegional
|
||||||
|
|
||||||
auto return_default_values = [&]() { return get_regional_values("001"sv); };
|
auto return_default_values = [&]() { return get_regional_values("001"sv); };
|
||||||
|
|
||||||
auto language = TRY(parse_unicode_language_id(locale));
|
auto language = parse_unicode_language_id(locale);
|
||||||
if (!language.has_value())
|
if (!language.has_value())
|
||||||
return return_default_values();
|
return return_default_values();
|
||||||
|
|
||||||
if (!language->region.has_value())
|
if (!language->region.has_value())
|
||||||
language = TRY(add_likely_subtags(*language));
|
language = add_likely_subtags(*language);
|
||||||
if (!language.has_value() || !language->region.has_value())
|
if (!language.has_value() || !language->region.has_value())
|
||||||
return return_default_values();
|
return return_default_values();
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ static ErrorOr<Optional<String>> format_time_zone_offset(StringView locale, Cale
|
||||||
if (!formats.has_value())
|
if (!formats.has_value())
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
auto number_system = TRY(get_preferred_keyword_value_for_locale(locale, "nu"sv));
|
auto number_system = get_preferred_keyword_value_for_locale(locale, "nu"sv);
|
||||||
if (!number_system.has_value())
|
if (!number_system.has_value())
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ bool is_type_identifier(StringView identifier)
|
||||||
return lexer.is_eof() && (lexer.tell() > 0);
|
return lexer.is_eof() && (lexer.tell() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Optional<LanguageID>> parse_unicode_language_id(GenericLexer& lexer)
|
static Optional<LanguageID> parse_unicode_language_id(GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#Unicode_language_identifier
|
// https://unicode.org/reports/tr35/#Unicode_language_identifier
|
||||||
//
|
//
|
||||||
|
@ -120,25 +120,25 @@ static ErrorOr<Optional<LanguageID>> parse_unicode_language_id(GenericLexer& lex
|
||||||
while (!lexer.is_eof() && (state != ParseState::Done)) {
|
while (!lexer.is_eof() && (state != ParseState::Done)) {
|
||||||
auto segment = consume_next_segment(lexer, state != ParseState::ParsingLanguageOrScript);
|
auto segment = consume_next_segment(lexer, state != ParseState::ParsingLanguageOrScript);
|
||||||
if (!segment.has_value())
|
if (!segment.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ParseState::ParsingLanguageOrScript:
|
case ParseState::ParsingLanguageOrScript:
|
||||||
if (is_unicode_language_subtag(*segment)) {
|
if (is_unicode_language_subtag(*segment)) {
|
||||||
state = ParseState::ParsingScript;
|
state = ParseState::ParsingScript;
|
||||||
language_id.language = TRY(String::from_utf8(*segment));
|
language_id.language = MUST(String::from_utf8(*segment));
|
||||||
} else if (is_unicode_script_subtag(*segment)) {
|
} else if (is_unicode_script_subtag(*segment)) {
|
||||||
state = ParseState::ParsingRegion;
|
state = ParseState::ParsingRegion;
|
||||||
language_id.script = TRY(String::from_utf8(*segment));
|
language_id.script = MUST(String::from_utf8(*segment));
|
||||||
} else {
|
} else {
|
||||||
return OptionalNone {};
|
return {};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ParseState::ParsingScript:
|
case ParseState::ParsingScript:
|
||||||
if (is_unicode_script_subtag(*segment)) {
|
if (is_unicode_script_subtag(*segment)) {
|
||||||
state = ParseState::ParsingRegion;
|
state = ParseState::ParsingRegion;
|
||||||
language_id.script = TRY(String::from_utf8(*segment));
|
language_id.script = MUST(String::from_utf8(*segment));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ static ErrorOr<Optional<LanguageID>> parse_unicode_language_id(GenericLexer& lex
|
||||||
case ParseState::ParsingRegion:
|
case ParseState::ParsingRegion:
|
||||||
if (is_unicode_region_subtag(*segment)) {
|
if (is_unicode_region_subtag(*segment)) {
|
||||||
state = ParseState::ParsingVariant;
|
state = ParseState::ParsingVariant;
|
||||||
language_id.region = TRY(String::from_utf8(*segment));
|
language_id.region = MUST(String::from_utf8(*segment));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ static ErrorOr<Optional<LanguageID>> parse_unicode_language_id(GenericLexer& lex
|
||||||
|
|
||||||
case ParseState::ParsingVariant:
|
case ParseState::ParsingVariant:
|
||||||
if (is_unicode_variant_subtag(*segment)) {
|
if (is_unicode_variant_subtag(*segment)) {
|
||||||
TRY(language_id.variants.try_append(TRY(String::from_utf8(*segment))));
|
language_id.variants.append(MUST(String::from_utf8(*segment)));
|
||||||
} else {
|
} else {
|
||||||
lexer.retreat(segment->length() + 1);
|
lexer.retreat(segment->length() + 1);
|
||||||
state = ParseState::Done;
|
state = ParseState::Done;
|
||||||
|
@ -172,7 +172,7 @@ static ErrorOr<Optional<LanguageID>> parse_unicode_language_id(GenericLexer& lex
|
||||||
return language_id;
|
return language_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Optional<LocaleExtension>> parse_unicode_locale_extension(GenericLexer& lexer)
|
static Optional<LocaleExtension> parse_unicode_locale_extension(GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#unicode_locale_extensions
|
// https://unicode.org/reports/tr35/#unicode_locale_extensions
|
||||||
//
|
//
|
||||||
|
@ -191,7 +191,7 @@ static ErrorOr<Optional<LocaleExtension>> parse_unicode_locale_extension(Generic
|
||||||
while (!lexer.is_eof() && (state != ParseState::Done)) {
|
while (!lexer.is_eof() && (state != ParseState::Done)) {
|
||||||
auto segment = consume_next_segment(lexer);
|
auto segment = consume_next_segment(lexer);
|
||||||
if (!segment.has_value())
|
if (!segment.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
if (state == ParseState::ParsingAttributeOrKeyword)
|
if (state == ParseState::ParsingAttributeOrKeyword)
|
||||||
state = is_key(*segment) ? ParseState::ParsingKeyword : ParseState::ParsingAttribute;
|
state = is_key(*segment) ? ParseState::ParsingKeyword : ParseState::ParsingAttribute;
|
||||||
|
@ -199,7 +199,7 @@ static ErrorOr<Optional<LocaleExtension>> parse_unicode_locale_extension(Generic
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ParseState::ParsingAttribute:
|
case ParseState::ParsingAttribute:
|
||||||
if (is_attribute(*segment)) {
|
if (is_attribute(*segment)) {
|
||||||
TRY(locale_extension.attributes.try_append(TRY(String::from_utf8(*segment))));
|
locale_extension.attributes.append(MUST(String::from_utf8(*segment)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ static ErrorOr<Optional<LocaleExtension>> parse_unicode_locale_extension(Generic
|
||||||
|
|
||||||
case ParseState::ParsingKeyword: {
|
case ParseState::ParsingKeyword: {
|
||||||
// keyword = key (sep type)?
|
// keyword = key (sep type)?
|
||||||
Keyword keyword { .key = TRY(String::from_utf8(*segment)) };
|
Keyword keyword { .key = MUST(String::from_utf8(*segment)) };
|
||||||
Vector<StringView> keyword_values;
|
Vector<StringView> keyword_values;
|
||||||
|
|
||||||
if (!is_key(*segment)) {
|
if (!is_key(*segment)) {
|
||||||
|
@ -226,14 +226,14 @@ static ErrorOr<Optional<LocaleExtension>> parse_unicode_locale_extension(Generic
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(keyword_values.try_append(*type));
|
keyword_values.append(*type);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
TRY(builder.try_join('-', keyword_values));
|
builder.join('-', keyword_values);
|
||||||
keyword.value = TRY(builder.to_string());
|
keyword.value = MUST(builder.to_string());
|
||||||
|
|
||||||
TRY(locale_extension.keywords.try_append(move(keyword)));
|
locale_extension.keywords.append(move(keyword));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,11 +243,11 @@ static ErrorOr<Optional<LocaleExtension>> parse_unicode_locale_extension(Generic
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locale_extension.attributes.is_empty() && locale_extension.keywords.is_empty())
|
if (locale_extension.attributes.is_empty() && locale_extension.keywords.is_empty())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
return locale_extension;
|
return locale_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Optional<TransformedExtension>> parse_transformed_extension(GenericLexer& lexer)
|
static Optional<TransformedExtension> parse_transformed_extension(GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#transformed_extensions
|
// https://unicode.org/reports/tr35/#transformed_extensions
|
||||||
//
|
//
|
||||||
|
@ -266,7 +266,7 @@ static ErrorOr<Optional<TransformedExtension>> parse_transformed_extension(Gener
|
||||||
while (!lexer.is_eof() && (state != ParseState::Done)) {
|
while (!lexer.is_eof() && (state != ParseState::Done)) {
|
||||||
auto segment = consume_next_segment(lexer);
|
auto segment = consume_next_segment(lexer);
|
||||||
if (!segment.has_value())
|
if (!segment.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
if (state == ParseState::ParsingLanguageOrField)
|
if (state == ParseState::ParsingLanguageOrField)
|
||||||
state = is_unicode_language_subtag(*segment) ? ParseState::ParsingLanguage : ParseState::ParsingField;
|
state = is_unicode_language_subtag(*segment) ? ParseState::ParsingLanguage : ParseState::ParsingField;
|
||||||
|
@ -275,17 +275,17 @@ static ErrorOr<Optional<TransformedExtension>> parse_transformed_extension(Gener
|
||||||
case ParseState::ParsingLanguage:
|
case ParseState::ParsingLanguage:
|
||||||
lexer.retreat(segment->length());
|
lexer.retreat(segment->length());
|
||||||
|
|
||||||
if (auto language_id = TRY(parse_unicode_language_id(lexer)); language_id.has_value()) {
|
if (auto language_id = parse_unicode_language_id(lexer); language_id.has_value()) {
|
||||||
transformed_extension.language = language_id.release_value();
|
transformed_extension.language = language_id.release_value();
|
||||||
state = ParseState::ParsingField;
|
state = ParseState::ParsingField;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
case ParseState::ParsingField: {
|
case ParseState::ParsingField: {
|
||||||
// tfield = tkey tvalue;
|
// tfield = tkey tvalue;
|
||||||
TransformedField field { .key = TRY(String::from_utf8(*segment)) };
|
TransformedField field { .key = MUST(String::from_utf8(*segment)) };
|
||||||
Vector<StringView> field_values;
|
Vector<StringView> field_values;
|
||||||
|
|
||||||
if (!is_transformed_key(*segment)) {
|
if (!is_transformed_key(*segment)) {
|
||||||
|
@ -303,17 +303,17 @@ static ErrorOr<Optional<TransformedExtension>> parse_transformed_extension(Gener
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(field_values.try_append(*value));
|
field_values.append(*value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_values.is_empty())
|
if (field_values.is_empty())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
TRY(builder.try_join('-', field_values));
|
builder.join('-', field_values);
|
||||||
field.value = TRY(builder.to_string());
|
field.value = MUST(builder.to_string());
|
||||||
|
|
||||||
TRY(transformed_extension.fields.try_append(move(field)));
|
transformed_extension.fields.append(move(field));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,11 +323,11 @@ static ErrorOr<Optional<TransformedExtension>> parse_transformed_extension(Gener
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!transformed_extension.language.has_value() && transformed_extension.fields.is_empty())
|
if (!transformed_extension.language.has_value() && transformed_extension.fields.is_empty())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
return transformed_extension;
|
return transformed_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Optional<OtherExtension>> parse_other_extension(char key, GenericLexer& lexer)
|
static Optional<OtherExtension> parse_other_extension(char key, GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#other_extensions
|
// https://unicode.org/reports/tr35/#other_extensions
|
||||||
//
|
//
|
||||||
|
@ -336,7 +336,7 @@ static ErrorOr<Optional<OtherExtension>> parse_other_extension(char key, Generic
|
||||||
Vector<StringView> other_values;
|
Vector<StringView> other_values;
|
||||||
|
|
||||||
if (!is_ascii_alphanumeric(key) || (key == 'x') || (key == 'X'))
|
if (!is_ascii_alphanumeric(key) || (key == 'x') || (key == 'X'))
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto segment = consume_next_segment(lexer);
|
auto segment = consume_next_segment(lexer);
|
||||||
|
@ -348,20 +348,20 @@ static ErrorOr<Optional<OtherExtension>> parse_other_extension(char key, Generic
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(other_values.try_append(*segment));
|
other_values.append(*segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other_values.is_empty())
|
if (other_values.is_empty())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
TRY(builder.try_join('-', other_values));
|
builder.join('-', other_values);
|
||||||
other_extension.value = TRY(builder.to_string());
|
other_extension.value = MUST(builder.to_string());
|
||||||
|
|
||||||
return other_extension;
|
return other_extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Optional<Extension>> parse_extension(GenericLexer& lexer)
|
static Optional<Extension> parse_extension(GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#extensions
|
// https://unicode.org/reports/tr35/#extensions
|
||||||
//
|
//
|
||||||
|
@ -372,28 +372,28 @@ static ErrorOr<Optional<Extension>> parse_extension(GenericLexer& lexer)
|
||||||
switch (char key = (*header)[0]) {
|
switch (char key = (*header)[0]) {
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'U':
|
case 'U':
|
||||||
if (auto extension = TRY(parse_unicode_locale_extension(lexer)); extension.has_value())
|
if (auto extension = parse_unicode_locale_extension(lexer); extension.has_value())
|
||||||
return Extension { extension.release_value() };
|
return Extension { extension.release_value() };
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
case 'T':
|
case 'T':
|
||||||
if (auto extension = TRY(parse_transformed_extension(lexer)); extension.has_value())
|
if (auto extension = parse_transformed_extension(lexer); extension.has_value())
|
||||||
return Extension { extension.release_value() };
|
return Extension { extension.release_value() };
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (auto extension = TRY(parse_other_extension(key, lexer)); extension.has_value())
|
if (auto extension = parse_other_extension(key, lexer); extension.has_value())
|
||||||
return Extension { extension.release_value() };
|
return Extension { extension.release_value() };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lexer.retreat(lexer.tell() - starting_position);
|
lexer.retreat(lexer.tell() - starting_position);
|
||||||
return OptionalNone {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Vector<String>> parse_private_use_extensions(GenericLexer& lexer)
|
static Vector<String> parse_private_use_extensions(GenericLexer& lexer)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#pu_extensions
|
// https://unicode.org/reports/tr35/#pu_extensions
|
||||||
//
|
//
|
||||||
|
@ -402,9 +402,9 @@ static ErrorOr<Vector<String>> parse_private_use_extensions(GenericLexer& lexer)
|
||||||
|
|
||||||
auto header = consume_next_segment(lexer);
|
auto header = consume_next_segment(lexer);
|
||||||
if (!header.has_value())
|
if (!header.has_value())
|
||||||
return Vector<String> {};
|
return {};
|
||||||
|
|
||||||
auto parse_values = [&]() -> ErrorOr<Vector<String>> {
|
auto parse_values = [&]() {
|
||||||
Vector<String> extensions;
|
Vector<String> extensions;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -417,33 +417,33 @@ static ErrorOr<Vector<String>> parse_private_use_extensions(GenericLexer& lexer)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(extensions.try_append(TRY(String::from_utf8(*segment))));
|
extensions.append(MUST(String::from_utf8(*segment)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return extensions;
|
return extensions;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((header->length() == 1) && (((*header)[0] == 'x') || ((*header)[0] == 'X'))) {
|
if ((header->length() == 1) && (((*header)[0] == 'x') || ((*header)[0] == 'X'))) {
|
||||||
if (auto extensions = TRY(parse_values()); !extensions.is_empty())
|
if (auto extensions = parse_values(); !extensions.is_empty())
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
lexer.retreat(lexer.tell() - starting_position);
|
lexer.retreat(lexer.tell() - starting_position);
|
||||||
return Vector<String> {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<LanguageID>> parse_unicode_language_id(StringView language)
|
Optional<LanguageID> parse_unicode_language_id(StringView language)
|
||||||
{
|
{
|
||||||
GenericLexer lexer { language };
|
GenericLexer lexer { language };
|
||||||
|
|
||||||
auto language_id = TRY(parse_unicode_language_id(lexer));
|
auto language_id = parse_unicode_language_id(lexer);
|
||||||
if (!lexer.is_eof())
|
if (!lexer.is_eof())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
return language_id;
|
return language_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<LocaleID>> parse_unicode_locale_id(StringView locale)
|
Optional<LocaleID> parse_unicode_locale_id(StringView locale)
|
||||||
{
|
{
|
||||||
GenericLexer lexer { locale };
|
GenericLexer lexer { locale };
|
||||||
|
|
||||||
|
@ -452,28 +452,28 @@ ErrorOr<Optional<LocaleID>> parse_unicode_locale_id(StringView locale)
|
||||||
// unicode_locale_id = unicode_language_id
|
// unicode_locale_id = unicode_language_id
|
||||||
// extensions*
|
// extensions*
|
||||||
// pu_extensions?
|
// pu_extensions?
|
||||||
auto language_id = TRY(parse_unicode_language_id(lexer));
|
auto language_id = parse_unicode_language_id(lexer);
|
||||||
if (!language_id.has_value())
|
if (!language_id.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
LocaleID locale_id { language_id.release_value() };
|
LocaleID locale_id { language_id.release_value() };
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto extension = TRY(parse_extension(lexer));
|
auto extension = parse_extension(lexer);
|
||||||
if (!extension.has_value())
|
if (!extension.has_value())
|
||||||
break;
|
break;
|
||||||
TRY(locale_id.extensions.try_append(extension.release_value()));
|
locale_id.extensions.append(extension.release_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
locale_id.private_use_extensions = TRY(parse_private_use_extensions(lexer));
|
locale_id.private_use_extensions = parse_private_use_extensions(lexer);
|
||||||
|
|
||||||
if (!lexer.is_eof())
|
if (!lexer.is_eof())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
return locale_id;
|
return locale_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<void> perform_hard_coded_key_value_substitutions(StringView key, String& value)
|
static void perform_hard_coded_key_value_substitutions(StringView key, String& value)
|
||||||
{
|
{
|
||||||
// FIXME: In the XML export of CLDR, there are some aliases defined in the following files:
|
// FIXME: In the XML export of CLDR, there are some aliases defined in the following files:
|
||||||
// https://github.com/unicode-org/cldr-staging/blob/master/production/common/bcp47/calendar.xml
|
// https://github.com/unicode-org/cldr-staging/blob/master/production/common/bcp47/calendar.xml
|
||||||
|
@ -540,14 +540,13 @@ static ErrorOr<void> perform_hard_coded_key_value_substitutions(StringView key,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.has_value())
|
if (result.has_value())
|
||||||
value = TRY(String::from_utf8(*result));
|
value = MUST(String::from_utf8(*result));
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> canonicalize_unicode_extension_values(StringView key, String& value, bool remove_true)
|
void canonicalize_unicode_extension_values(StringView key, String& value, bool remove_true)
|
||||||
{
|
{
|
||||||
value = TRY(value.to_lowercase());
|
value = MUST(value.to_lowercase());
|
||||||
TRY(perform_hard_coded_key_value_substitutions(key, value));
|
perform_hard_coded_key_value_substitutions(key, value);
|
||||||
|
|
||||||
// Note: The spec says to remove "true" type and tfield values but that is believed to be a bug in the spec
|
// Note: The spec says to remove "true" type and tfield values but that is believed to be a bug in the spec
|
||||||
// because, for tvalues, that would result in invalid syntax:
|
// because, for tvalues, that would result in invalid syntax:
|
||||||
|
@ -556,7 +555,7 @@ ErrorOr<void> canonicalize_unicode_extension_values(StringView key, String& valu
|
||||||
// https://github.com/tc39/test262/blob/18bb955771669541c56c28748603f6afdb2e25ff/test/intl402/Intl/getCanonicalLocales/transformed-ext-canonical.js
|
// https://github.com/tc39/test262/blob/18bb955771669541c56c28748603f6afdb2e25ff/test/intl402/Intl/getCanonicalLocales/transformed-ext-canonical.js
|
||||||
if (remove_true && (value == "true"sv)) {
|
if (remove_true && (value == "true"sv)) {
|
||||||
value = {};
|
value = {};
|
||||||
return {};
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.is_one_of("sd"sv, "rg"sv)) {
|
if (key.is_one_of("sd"sv, "rg"sv)) {
|
||||||
|
@ -566,28 +565,26 @@ ErrorOr<void> canonicalize_unicode_extension_values(StringView key, String& valu
|
||||||
// FIXME: Subdivision subtags do not appear in the CLDR likelySubtags.json file.
|
// FIXME: Subdivision subtags do not appear in the CLDR likelySubtags.json file.
|
||||||
// Implement the spec's recommendation of using just the first alias for now,
|
// Implement the spec's recommendation of using just the first alias for now,
|
||||||
// but we should determine if there's anything else needed here.
|
// but we should determine if there's anything else needed here.
|
||||||
value = TRY(String::from_utf8(aliases[0]));
|
value = MUST(String::from_utf8(aliases[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<void> transform_unicode_locale_id_to_canonical_syntax(LocaleID& locale_id)
|
static void transform_unicode_locale_id_to_canonical_syntax(LocaleID& locale_id)
|
||||||
{
|
{
|
||||||
auto canonicalize_language = [&](LanguageID& language_id, bool force_lowercase) -> ErrorOr<void> {
|
auto canonicalize_language = [&](LanguageID& language_id, bool force_lowercase) {
|
||||||
language_id.language = TRY(language_id.language->to_lowercase());
|
language_id.language = MUST(language_id.language->to_lowercase());
|
||||||
if (language_id.script.has_value())
|
if (language_id.script.has_value())
|
||||||
language_id.script = TRY(language_id.script->to_titlecase());
|
language_id.script = MUST(language_id.script->to_titlecase());
|
||||||
if (language_id.region.has_value())
|
if (language_id.region.has_value())
|
||||||
language_id.region = TRY(language_id.region->to_uppercase());
|
language_id.region = MUST(language_id.region->to_uppercase());
|
||||||
for (auto& variant : language_id.variants)
|
for (auto& variant : language_id.variants)
|
||||||
variant = TRY(variant.to_lowercase());
|
variant = MUST(variant.to_lowercase());
|
||||||
|
|
||||||
TRY(resolve_complex_language_aliases(language_id));
|
resolve_complex_language_aliases(language_id);
|
||||||
|
|
||||||
if (auto alias = resolve_language_alias(*language_id.language); alias.has_value()) {
|
if (auto alias = resolve_language_alias(*language_id.language); alias.has_value()) {
|
||||||
auto language_alias = TRY(parse_unicode_language_id(*alias));
|
auto language_alias = parse_unicode_language_id(*alias);
|
||||||
VERIFY(language_alias.has_value());
|
VERIFY(language_alias.has_value());
|
||||||
|
|
||||||
language_id.language = move(language_alias->language);
|
language_id.language = move(language_alias->language);
|
||||||
|
@ -601,33 +598,31 @@ static ErrorOr<void> transform_unicode_locale_id_to_canonical_syntax(LocaleID& l
|
||||||
|
|
||||||
if (language_id.script.has_value()) {
|
if (language_id.script.has_value()) {
|
||||||
if (auto alias = resolve_script_tag_alias(*language_id.script); alias.has_value())
|
if (auto alias = resolve_script_tag_alias(*language_id.script); alias.has_value())
|
||||||
language_id.script = TRY(String::from_utf8(*alias));
|
language_id.script = MUST(String::from_utf8(*alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (language_id.region.has_value()) {
|
if (language_id.region.has_value()) {
|
||||||
if (auto alias = resolve_territory_alias(*language_id.region); alias.has_value())
|
if (auto alias = resolve_territory_alias(*language_id.region); alias.has_value())
|
||||||
language_id.region = TRY(resolve_most_likely_territory_alias(language_id, *alias));
|
language_id.region = resolve_most_likely_territory_alias(language_id, *alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
quick_sort(language_id.variants);
|
quick_sort(language_id.variants);
|
||||||
|
|
||||||
for (auto& variant : language_id.variants) {
|
for (auto& variant : language_id.variants) {
|
||||||
variant = TRY(variant.to_lowercase());
|
variant = MUST(variant.to_lowercase());
|
||||||
if (auto alias = resolve_variant_alias(variant); alias.has_value())
|
if (auto alias = resolve_variant_alias(variant); alias.has_value())
|
||||||
variant = TRY(String::from_utf8(*alias));
|
variant = MUST(String::from_utf8(*alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force_lowercase) {
|
if (force_lowercase) {
|
||||||
if (language_id.script.has_value())
|
if (language_id.script.has_value())
|
||||||
language_id.script = TRY(language_id.script->to_lowercase());
|
language_id.script = MUST(language_id.script->to_lowercase());
|
||||||
if (language_id.region.has_value())
|
if (language_id.region.has_value())
|
||||||
language_id.region = TRY(language_id.region->to_lowercase());
|
language_id.region = MUST(language_id.region->to_lowercase());
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TRY(canonicalize_language(locale_id.language_id, false));
|
canonicalize_language(locale_id.language_id, false);
|
||||||
|
|
||||||
quick_sort(locale_id.extensions, [](auto const& left, auto const& right) {
|
quick_sort(locale_id.extensions, [](auto const& left, auto const& right) {
|
||||||
auto key = [](auto const& extension) {
|
auto key = [](auto const& extension) {
|
||||||
|
@ -641,114 +636,103 @@ static ErrorOr<void> transform_unicode_locale_id_to_canonical_syntax(LocaleID& l
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto& extension : locale_id.extensions) {
|
for (auto& extension : locale_id.extensions) {
|
||||||
TRY(extension.visit(
|
extension.visit(
|
||||||
[&](LocaleExtension& ext) -> ErrorOr<void> {
|
[&](LocaleExtension& ext) {
|
||||||
for (auto& attribute : ext.attributes)
|
for (auto& attribute : ext.attributes)
|
||||||
attribute = TRY(attribute.to_lowercase());
|
attribute = MUST(attribute.to_lowercase());
|
||||||
|
|
||||||
for (auto& keyword : ext.keywords) {
|
for (auto& keyword : ext.keywords) {
|
||||||
keyword.key = TRY(keyword.key.to_lowercase());
|
keyword.key = MUST(keyword.key.to_lowercase());
|
||||||
TRY(canonicalize_unicode_extension_values(keyword.key, keyword.value, true));
|
canonicalize_unicode_extension_values(keyword.key, keyword.value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
quick_sort(ext.attributes);
|
quick_sort(ext.attributes);
|
||||||
quick_sort(ext.keywords, [](auto const& a, auto const& b) { return a.key < b.key; });
|
quick_sort(ext.keywords, [](auto const& a, auto const& b) { return a.key < b.key; });
|
||||||
return {};
|
|
||||||
},
|
},
|
||||||
[&](TransformedExtension& ext) -> ErrorOr<void> {
|
[&](TransformedExtension& ext) {
|
||||||
if (ext.language.has_value())
|
if (ext.language.has_value())
|
||||||
TRY(canonicalize_language(*ext.language, true));
|
canonicalize_language(*ext.language, true);
|
||||||
|
|
||||||
for (auto& field : ext.fields) {
|
for (auto& field : ext.fields) {
|
||||||
field.key = TRY(field.key.to_lowercase());
|
field.key = MUST(field.key.to_lowercase());
|
||||||
TRY(canonicalize_unicode_extension_values(field.key, field.value, false));
|
canonicalize_unicode_extension_values(field.key, field.value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
quick_sort(ext.fields, [](auto const& a, auto const& b) { return a.key < b.key; });
|
quick_sort(ext.fields, [](auto const& a, auto const& b) { return a.key < b.key; });
|
||||||
return {};
|
|
||||||
},
|
},
|
||||||
[&](OtherExtension& ext) -> ErrorOr<void> {
|
[&](OtherExtension& ext) {
|
||||||
ext.key = static_cast<char>(to_ascii_lowercase(ext.key));
|
ext.key = static_cast<char>(to_ascii_lowercase(ext.key));
|
||||||
ext.value = TRY(ext.value.to_lowercase());
|
ext.value = MUST(ext.value.to_lowercase());
|
||||||
return {};
|
});
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& extension : locale_id.private_use_extensions)
|
for (auto& extension : locale_id.private_use_extensions)
|
||||||
extension = TRY(extension.to_lowercase());
|
extension = MUST(extension.to_lowercase());
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<String>> canonicalize_unicode_locale_id(LocaleID& locale_id)
|
Optional<String> canonicalize_unicode_locale_id(LocaleID& locale_id)
|
||||||
{
|
{
|
||||||
// https://unicode.org/reports/tr35/#Canonical_Unicode_Locale_Identifiers
|
// https://unicode.org/reports/tr35/#Canonical_Unicode_Locale_Identifiers
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
||||||
auto append_sep_and_string = [&](Optional<String> const& string) -> ErrorOr<void> {
|
auto append_sep_and_string = [&](Optional<String> const& string) {
|
||||||
if (!string.has_value() || string->is_empty())
|
if (!string.has_value() || string->is_empty())
|
||||||
return {};
|
return;
|
||||||
TRY(builder.try_appendff("-{}", *string));
|
builder.appendff("-{}", *string);
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!locale_id.language_id.language.has_value())
|
if (!locale_id.language_id.language.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
TRY(transform_unicode_locale_id_to_canonical_syntax(locale_id));
|
transform_unicode_locale_id_to_canonical_syntax(locale_id);
|
||||||
|
|
||||||
TRY(builder.try_append(TRY(locale_id.language_id.language->to_lowercase())));
|
builder.append(MUST(locale_id.language_id.language->to_lowercase()));
|
||||||
TRY(append_sep_and_string(locale_id.language_id.script));
|
append_sep_and_string(locale_id.language_id.script);
|
||||||
TRY(append_sep_and_string(locale_id.language_id.region));
|
append_sep_and_string(locale_id.language_id.region);
|
||||||
for (auto const& variant : locale_id.language_id.variants)
|
for (auto const& variant : locale_id.language_id.variants)
|
||||||
TRY(append_sep_and_string(variant));
|
append_sep_and_string(variant);
|
||||||
|
|
||||||
for (auto const& extension : locale_id.extensions) {
|
for (auto const& extension : locale_id.extensions) {
|
||||||
TRY(extension.visit(
|
extension.visit(
|
||||||
[&](LocaleExtension const& ext) -> ErrorOr<void> {
|
[&](LocaleExtension const& ext) {
|
||||||
TRY(builder.try_append("-u"sv));
|
builder.append("-u"sv);
|
||||||
|
|
||||||
for (auto const& attribute : ext.attributes)
|
for (auto const& attribute : ext.attributes)
|
||||||
TRY(append_sep_and_string(attribute));
|
append_sep_and_string(attribute);
|
||||||
for (auto const& keyword : ext.keywords) {
|
for (auto const& keyword : ext.keywords) {
|
||||||
TRY(append_sep_and_string(keyword.key));
|
append_sep_and_string(keyword.key);
|
||||||
TRY(append_sep_and_string(keyword.value));
|
append_sep_and_string(keyword.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
|
||||||
},
|
},
|
||||||
[&](TransformedExtension const& ext) -> ErrorOr<void> {
|
[&](TransformedExtension const& ext) {
|
||||||
TRY(builder.try_append("-t"sv));
|
builder.append("-t"sv);
|
||||||
|
|
||||||
if (ext.language.has_value()) {
|
if (ext.language.has_value()) {
|
||||||
TRY(append_sep_and_string(ext.language->language));
|
append_sep_and_string(ext.language->language);
|
||||||
TRY(append_sep_and_string(ext.language->script));
|
append_sep_and_string(ext.language->script);
|
||||||
TRY(append_sep_and_string(ext.language->region));
|
append_sep_and_string(ext.language->region);
|
||||||
for (auto const& variant : ext.language->variants)
|
for (auto const& variant : ext.language->variants)
|
||||||
TRY(append_sep_and_string(variant));
|
append_sep_and_string(variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& field : ext.fields) {
|
for (auto const& field : ext.fields) {
|
||||||
TRY(append_sep_and_string(field.key));
|
append_sep_and_string(field.key);
|
||||||
TRY(append_sep_and_string(field.value));
|
append_sep_and_string(field.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
|
||||||
},
|
},
|
||||||
[&](OtherExtension const& ext) -> ErrorOr<void> {
|
[&](OtherExtension const& ext) {
|
||||||
TRY(builder.try_appendff("-{:c}", to_ascii_lowercase(ext.key)));
|
builder.appendff("-{:c}", to_ascii_lowercase(ext.key));
|
||||||
TRY(append_sep_and_string(ext.value));
|
append_sep_and_string(ext.value);
|
||||||
return {};
|
});
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!locale_id.private_use_extensions.is_empty()) {
|
if (!locale_id.private_use_extensions.is_empty()) {
|
||||||
TRY(builder.try_append("-x"sv));
|
builder.append("-x"sv);
|
||||||
for (auto const& extension : locale_id.private_use_extensions)
|
for (auto const& extension : locale_id.private_use_extensions)
|
||||||
TRY(append_sep_and_string(extension));
|
append_sep_and_string(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.to_string();
|
return MUST(builder.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView default_locale()
|
StringView default_locale()
|
||||||
|
@ -808,8 +792,8 @@ Optional<KeywordHours> __attribute__((weak)) keyword_hc_from_string(StringView)
|
||||||
Optional<KeywordColCaseFirst> __attribute__((weak)) keyword_kf_from_string(StringView) { return {}; }
|
Optional<KeywordColCaseFirst> __attribute__((weak)) keyword_kf_from_string(StringView) { return {}; }
|
||||||
Optional<KeywordColNumeric> __attribute__((weak)) keyword_kn_from_string(StringView) { return {}; }
|
Optional<KeywordColNumeric> __attribute__((weak)) keyword_kn_from_string(StringView) { return {}; }
|
||||||
Optional<KeywordNumbers> __attribute__((weak)) keyword_nu_from_string(StringView) { return {}; }
|
Optional<KeywordNumbers> __attribute__((weak)) keyword_nu_from_string(StringView) { return {}; }
|
||||||
ErrorOr<Vector<StringView>> __attribute__((weak)) get_keywords_for_locale(StringView, StringView) { return Vector<StringView> {}; }
|
Vector<StringView> __attribute__((weak)) get_keywords_for_locale(StringView, StringView) { return {}; }
|
||||||
ErrorOr<Optional<StringView>> __attribute__((weak)) get_preferred_keyword_value_for_locale(StringView, StringView) { return OptionalNone {}; }
|
Optional<StringView> __attribute__((weak)) get_preferred_keyword_value_for_locale(StringView, StringView) { return {}; }
|
||||||
Optional<DisplayPattern> __attribute__((weak)) get_locale_display_patterns(StringView) { return {}; }
|
Optional<DisplayPattern> __attribute__((weak)) get_locale_display_patterns(StringView) { return {}; }
|
||||||
Optional<StringView> __attribute__((weak)) get_locale_language_mapping(StringView, StringView) { return {}; }
|
Optional<StringView> __attribute__((weak)) get_locale_language_mapping(StringView, StringView) { return {}; }
|
||||||
Optional<StringView> __attribute__((weak)) get_locale_territory_mapping(StringView, StringView) { return {}; }
|
Optional<StringView> __attribute__((weak)) get_locale_territory_mapping(StringView, StringView) { return {}; }
|
||||||
|
@ -824,14 +808,14 @@ Optional<StringView> __attribute__((weak)) get_locale_short_date_field_mapping(S
|
||||||
Optional<StringView> __attribute__((weak)) get_locale_narrow_date_field_mapping(StringView, StringView) { return {}; }
|
Optional<StringView> __attribute__((weak)) get_locale_narrow_date_field_mapping(StringView, StringView) { return {}; }
|
||||||
|
|
||||||
// https://www.unicode.org/reports/tr35/tr35-39/tr35-general.html#Display_Name_Elements
|
// https://www.unicode.org/reports/tr35/tr35-39/tr35-general.html#Display_Name_Elements
|
||||||
ErrorOr<Optional<String>> format_locale_for_display(StringView locale, LocaleID locale_id)
|
Optional<String> format_locale_for_display(StringView locale, LocaleID locale_id)
|
||||||
{
|
{
|
||||||
auto language_id = move(locale_id.language_id);
|
auto language_id = move(locale_id.language_id);
|
||||||
VERIFY(language_id.language.has_value());
|
VERIFY(language_id.language.has_value());
|
||||||
|
|
||||||
auto patterns = get_locale_display_patterns(locale);
|
auto patterns = get_locale_display_patterns(locale);
|
||||||
if (!patterns.has_value())
|
if (!patterns.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
auto primary_tag = get_locale_language_mapping(locale, *language_id.language).value_or(*language_id.language);
|
auto primary_tag = get_locale_language_mapping(locale, *language_id.language).value_or(*language_id.language);
|
||||||
Optional<StringView> script;
|
Optional<StringView> script;
|
||||||
|
@ -845,21 +829,21 @@ ErrorOr<Optional<String>> format_locale_for_display(StringView locale, LocaleID
|
||||||
Optional<String> secondary_tag;
|
Optional<String> secondary_tag;
|
||||||
|
|
||||||
if (script.has_value() && region.has_value()) {
|
if (script.has_value() && region.has_value()) {
|
||||||
secondary_tag = TRY(String::from_utf8(patterns->locale_separator));
|
secondary_tag = MUST(String::from_utf8(patterns->locale_separator));
|
||||||
secondary_tag = TRY(secondary_tag->replace("{0}"sv, *script, ReplaceMode::FirstOnly));
|
secondary_tag = MUST(secondary_tag->replace("{0}"sv, *script, ReplaceMode::FirstOnly));
|
||||||
secondary_tag = TRY(secondary_tag->replace("{1}"sv, *region, ReplaceMode::FirstOnly));
|
secondary_tag = MUST(secondary_tag->replace("{1}"sv, *region, ReplaceMode::FirstOnly));
|
||||||
} else if (script.has_value()) {
|
} else if (script.has_value()) {
|
||||||
secondary_tag = TRY(String::from_utf8(*script));
|
secondary_tag = MUST(String::from_utf8(*script));
|
||||||
} else if (region.has_value()) {
|
} else if (region.has_value()) {
|
||||||
secondary_tag = TRY(String::from_utf8(*region));
|
secondary_tag = MUST(String::from_utf8(*region));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!secondary_tag.has_value())
|
if (!secondary_tag.has_value())
|
||||||
return String::from_utf8(primary_tag);
|
return MUST(String::from_utf8(primary_tag));
|
||||||
|
|
||||||
auto result = TRY(String::from_utf8(patterns->locale_pattern));
|
auto result = MUST(String::from_utf8(patterns->locale_pattern));
|
||||||
result = TRY(result.replace("{0}"sv, primary_tag, ReplaceMode::FirstOnly));
|
result = MUST(result.replace("{0}"sv, primary_tag, ReplaceMode::FirstOnly));
|
||||||
result = TRY(result.replace("{1}"sv, *secondary_tag, ReplaceMode::FirstOnly));
|
result = MUST(result.replace("{1}"sv, *secondary_tag, ReplaceMode::FirstOnly));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -873,10 +857,10 @@ Optional<StringView> __attribute__((weak)) resolve_territory_alias(StringView) {
|
||||||
Optional<StringView> __attribute__((weak)) resolve_script_tag_alias(StringView) { return {}; }
|
Optional<StringView> __attribute__((weak)) resolve_script_tag_alias(StringView) { return {}; }
|
||||||
Optional<StringView> __attribute__((weak)) resolve_variant_alias(StringView) { return {}; }
|
Optional<StringView> __attribute__((weak)) resolve_variant_alias(StringView) { return {}; }
|
||||||
Optional<StringView> __attribute__((weak)) resolve_subdivision_alias(StringView) { return {}; }
|
Optional<StringView> __attribute__((weak)) resolve_subdivision_alias(StringView) { return {}; }
|
||||||
ErrorOr<void> __attribute__((weak)) resolve_complex_language_aliases(LanguageID&) { return {}; }
|
void __attribute__((weak)) resolve_complex_language_aliases(LanguageID&) { }
|
||||||
ErrorOr<Optional<LanguageID>> __attribute__((weak)) add_likely_subtags(LanguageID const&) { return OptionalNone {}; }
|
Optional<LanguageID> __attribute__((weak)) add_likely_subtags(LanguageID const&) { return {}; }
|
||||||
|
|
||||||
ErrorOr<Optional<LanguageID>> remove_likely_subtags(LanguageID const& language_id)
|
Optional<LanguageID> remove_likely_subtags(LanguageID const& language_id)
|
||||||
{
|
{
|
||||||
// https://www.unicode.org/reports/tr35/#Likely_Subtags
|
// https://www.unicode.org/reports/tr35/#Likely_Subtags
|
||||||
auto return_language_and_variants = [](auto language, auto variants) {
|
auto return_language_and_variants = [](auto language, auto variants) {
|
||||||
|
@ -885,9 +869,9 @@ ErrorOr<Optional<LanguageID>> remove_likely_subtags(LanguageID const& language_i
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1. First get max = AddLikelySubtags(inputLocale). If an error is signaled, return it.
|
// 1. First get max = AddLikelySubtags(inputLocale). If an error is signaled, return it.
|
||||||
auto maximized = TRY(add_likely_subtags(language_id));
|
auto maximized = add_likely_subtags(language_id);
|
||||||
if (!maximized.has_value())
|
if (!maximized.has_value())
|
||||||
return OptionalNone {};
|
return {};
|
||||||
|
|
||||||
// 2. Remove the variants from max.
|
// 2. Remove the variants from max.
|
||||||
auto variants = move(maximized->variants);
|
auto variants = move(maximized->variants);
|
||||||
|
@ -899,113 +883,108 @@ ErrorOr<Optional<LanguageID>> remove_likely_subtags(LanguageID const& language_i
|
||||||
|
|
||||||
// 4. Then for trial in {languagemax, languagemax_regionmax, languagemax_scriptmax}:
|
// 4. Then for trial in {languagemax, languagemax_regionmax, languagemax_scriptmax}:
|
||||||
// If AddLikelySubtags(trial) = max, then return trial + variants.
|
// If AddLikelySubtags(trial) = max, then return trial + variants.
|
||||||
auto run_trial = [&](Optional<String> language, Optional<String> script, Optional<String> region) -> ErrorOr<Optional<LanguageID>> {
|
auto run_trial = [&](Optional<String> language, Optional<String> script, Optional<String> region) -> Optional<LanguageID> {
|
||||||
LanguageID trial { .language = move(language), .script = move(script), .region = move(region) };
|
LanguageID trial { .language = move(language), .script = move(script), .region = move(region) };
|
||||||
|
|
||||||
if (TRY(add_likely_subtags(trial)) == maximized)
|
if (add_likely_subtags(trial) == maximized)
|
||||||
return return_language_and_variants(move(trial), move(variants));
|
return return_language_and_variants(move(trial), move(variants));
|
||||||
return OptionalNone {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto trial = TRY(run_trial(language_max, {}, {})); trial.has_value())
|
if (auto trial = run_trial(language_max, {}, {}); trial.has_value())
|
||||||
return trial;
|
return trial;
|
||||||
if (auto trial = TRY(run_trial(language_max, {}, region_max)); trial.has_value())
|
if (auto trial = run_trial(language_max, {}, region_max); trial.has_value())
|
||||||
return trial;
|
return trial;
|
||||||
if (auto trial = TRY(run_trial(language_max, script_max, {})); trial.has_value())
|
if (auto trial = run_trial(language_max, script_max, {}); trial.has_value())
|
||||||
return trial;
|
return trial;
|
||||||
|
|
||||||
// 5. If you do not get a match, return max + variants.
|
// 5. If you do not get a match, return max + variants.
|
||||||
return return_language_and_variants(maximized.release_value(), move(variants));
|
return return_language_and_variants(maximized.release_value(), move(variants));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<Optional<String>> __attribute__((weak)) resolve_most_likely_territory(LanguageID const&) { return OptionalNone {}; }
|
Optional<String> __attribute__((weak)) resolve_most_likely_territory(LanguageID const&) { return {}; }
|
||||||
|
|
||||||
ErrorOr<String> resolve_most_likely_territory_alias(LanguageID const& language_id, StringView territory_alias)
|
String resolve_most_likely_territory_alias(LanguageID const& language_id, StringView territory_alias)
|
||||||
{
|
{
|
||||||
auto aliases = territory_alias.split_view(' ');
|
auto aliases = territory_alias.split_view(' ');
|
||||||
|
|
||||||
if (aliases.size() > 1) {
|
if (aliases.size() > 1) {
|
||||||
auto territory = TRY(resolve_most_likely_territory(language_id));
|
auto territory = resolve_most_likely_territory(language_id);
|
||||||
if (territory.has_value() && aliases.contains_slow(*territory))
|
if (territory.has_value() && aliases.contains_slow(*territory))
|
||||||
return territory.release_value();
|
return territory.release_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
return String::from_utf8(aliases[0]);
|
return MUST(String::from_utf8(aliases[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<String> LanguageID::to_string() const
|
String LanguageID::to_string() const
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
||||||
auto append_segment = [&](Optional<String> const& segment) -> ErrorOr<void> {
|
auto append_segment = [&](Optional<String> const& segment) {
|
||||||
if (!segment.has_value())
|
if (!segment.has_value())
|
||||||
return {};
|
return;
|
||||||
if (!builder.is_empty())
|
if (!builder.is_empty())
|
||||||
TRY(builder.try_append('-'));
|
builder.append('-');
|
||||||
TRY(builder.try_append(*segment));
|
builder.append(*segment);
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TRY(append_segment(language));
|
append_segment(language);
|
||||||
TRY(append_segment(script));
|
append_segment(script);
|
||||||
TRY(append_segment(region));
|
append_segment(region);
|
||||||
for (auto const& variant : variants)
|
for (auto const& variant : variants)
|
||||||
TRY(append_segment(variant));
|
append_segment(variant);
|
||||||
|
|
||||||
return builder.to_string();
|
return MUST(builder.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<String> LocaleID::to_string() const
|
String LocaleID::to_string() const
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
||||||
auto append_segment = [&](auto const& segment) -> ErrorOr<void> {
|
auto append_segment = [&](auto const& segment) {
|
||||||
if (segment.is_empty())
|
if (segment.is_empty())
|
||||||
return {};
|
return;
|
||||||
if (!builder.is_empty())
|
if (!builder.is_empty())
|
||||||
TRY(builder.try_append('-'));
|
builder.append('-');
|
||||||
TRY(builder.try_append(segment));
|
builder.append(segment);
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TRY(append_segment(TRY(language_id.to_string())));
|
append_segment(language_id.to_string());
|
||||||
|
|
||||||
for (auto const& extension : extensions) {
|
for (auto const& extension : extensions) {
|
||||||
TRY(extension.visit(
|
extension.visit(
|
||||||
[&](LocaleExtension const& ext) -> ErrorOr<void> {
|
[&](LocaleExtension const& ext) {
|
||||||
TRY(builder.try_append("-u"sv));
|
builder.append("-u"sv);
|
||||||
for (auto const& attribute : ext.attributes)
|
for (auto const& attribute : ext.attributes)
|
||||||
TRY(append_segment(attribute));
|
append_segment(attribute);
|
||||||
for (auto const& keyword : ext.keywords) {
|
for (auto const& keyword : ext.keywords) {
|
||||||
TRY(append_segment(keyword.key));
|
append_segment(keyword.key);
|
||||||
TRY(append_segment(keyword.value));
|
append_segment(keyword.value);
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
},
|
},
|
||||||
[&](TransformedExtension const& ext) -> ErrorOr<void> {
|
[&](TransformedExtension const& ext) {
|
||||||
TRY(builder.try_append("-t"sv));
|
builder.append("-t"sv);
|
||||||
if (ext.language.has_value())
|
if (ext.language.has_value())
|
||||||
TRY(append_segment(TRY(ext.language->to_string())));
|
append_segment(ext.language->to_string());
|
||||||
for (auto const& field : ext.fields) {
|
for (auto const& field : ext.fields) {
|
||||||
TRY(append_segment(field.key));
|
append_segment(field.key);
|
||||||
TRY(append_segment(field.value));
|
append_segment(field.value);
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
},
|
},
|
||||||
[&](OtherExtension const& ext) -> ErrorOr<void> {
|
[&](OtherExtension const& ext) {
|
||||||
TRY(builder.try_appendff("-{}", ext.key));
|
builder.appendff("-{}", ext.key);
|
||||||
TRY(append_segment(ext.value));
|
append_segment(ext.value);
|
||||||
return {};
|
});
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!private_use_extensions.is_empty()) {
|
if (!private_use_extensions.is_empty()) {
|
||||||
TRY(builder.try_append("-x"sv));
|
builder.append("-x"sv);
|
||||||
for (auto const& extension : private_use_extensions)
|
for (auto const& extension : private_use_extensions)
|
||||||
TRY(append_segment(extension));
|
append_segment(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.to_string();
|
return MUST(builder.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/CharacterTypes.h>
|
#include <AK/CharacterTypes.h>
|
||||||
#include <AK/Error.h>
|
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
|
@ -18,7 +17,7 @@
|
||||||
namespace Locale {
|
namespace Locale {
|
||||||
|
|
||||||
struct LanguageID {
|
struct LanguageID {
|
||||||
ErrorOr<String> to_string() const;
|
String to_string() const;
|
||||||
bool operator==(LanguageID const&) const = default;
|
bool operator==(LanguageID const&) const = default;
|
||||||
|
|
||||||
bool is_root { false };
|
bool is_root { false };
|
||||||
|
@ -56,7 +55,7 @@ struct OtherExtension {
|
||||||
using Extension = AK::Variant<LocaleExtension, TransformedExtension, OtherExtension>;
|
using Extension = AK::Variant<LocaleExtension, TransformedExtension, OtherExtension>;
|
||||||
|
|
||||||
struct LocaleID {
|
struct LocaleID {
|
||||||
ErrorOr<String> to_string() const;
|
String to_string() const;
|
||||||
|
|
||||||
template<typename ExtensionType>
|
template<typename ExtensionType>
|
||||||
Vector<Extension> remove_extension_type()
|
Vector<Extension> remove_extension_type()
|
||||||
|
@ -137,11 +136,11 @@ constexpr bool is_unicode_variant_subtag(StringView subtag)
|
||||||
|
|
||||||
bool is_type_identifier(StringView);
|
bool is_type_identifier(StringView);
|
||||||
|
|
||||||
ErrorOr<Optional<LanguageID>> parse_unicode_language_id(StringView);
|
Optional<LanguageID> parse_unicode_language_id(StringView);
|
||||||
ErrorOr<Optional<LocaleID>> parse_unicode_locale_id(StringView);
|
Optional<LocaleID> parse_unicode_locale_id(StringView);
|
||||||
|
|
||||||
ErrorOr<void> canonicalize_unicode_extension_values(StringView key, String& value, bool remove_true);
|
void canonicalize_unicode_extension_values(StringView key, String& value, bool remove_true);
|
||||||
ErrorOr<Optional<String>> canonicalize_unicode_locale_id(LocaleID&);
|
Optional<String> canonicalize_unicode_locale_id(LocaleID&);
|
||||||
|
|
||||||
StringView default_locale();
|
StringView default_locale();
|
||||||
bool is_locale_available(StringView locale);
|
bool is_locale_available(StringView locale);
|
||||||
|
@ -173,11 +172,11 @@ Optional<KeywordHours> keyword_hc_from_string(StringView hc);
|
||||||
Optional<KeywordColCaseFirst> keyword_kf_from_string(StringView kf);
|
Optional<KeywordColCaseFirst> keyword_kf_from_string(StringView kf);
|
||||||
Optional<KeywordColNumeric> keyword_kn_from_string(StringView kn);
|
Optional<KeywordColNumeric> keyword_kn_from_string(StringView kn);
|
||||||
Optional<KeywordNumbers> keyword_nu_from_string(StringView nu);
|
Optional<KeywordNumbers> keyword_nu_from_string(StringView nu);
|
||||||
ErrorOr<Vector<StringView>> get_keywords_for_locale(StringView locale, StringView key);
|
Vector<StringView> get_keywords_for_locale(StringView locale, StringView key);
|
||||||
ErrorOr<Optional<StringView>> get_preferred_keyword_value_for_locale(StringView locale, StringView key);
|
Optional<StringView> get_preferred_keyword_value_for_locale(StringView locale, StringView key);
|
||||||
|
|
||||||
Optional<DisplayPattern> get_locale_display_patterns(StringView locale);
|
Optional<DisplayPattern> get_locale_display_patterns(StringView locale);
|
||||||
ErrorOr<Optional<String>> format_locale_for_display(StringView locale, LocaleID locale_id);
|
Optional<String> format_locale_for_display(StringView locale, LocaleID locale_id);
|
||||||
|
|
||||||
Optional<StringView> get_locale_language_mapping(StringView locale, StringView language);
|
Optional<StringView> get_locale_language_mapping(StringView locale, StringView language);
|
||||||
Optional<StringView> get_locale_territory_mapping(StringView locale, StringView territory);
|
Optional<StringView> get_locale_territory_mapping(StringView locale, StringView territory);
|
||||||
|
@ -202,12 +201,12 @@ Optional<StringView> resolve_territory_alias(StringView territory);
|
||||||
Optional<StringView> resolve_script_tag_alias(StringView script_tag);
|
Optional<StringView> resolve_script_tag_alias(StringView script_tag);
|
||||||
Optional<StringView> resolve_variant_alias(StringView variant);
|
Optional<StringView> resolve_variant_alias(StringView variant);
|
||||||
Optional<StringView> resolve_subdivision_alias(StringView subdivision);
|
Optional<StringView> resolve_subdivision_alias(StringView subdivision);
|
||||||
ErrorOr<void> resolve_complex_language_aliases(LanguageID& language_id);
|
void resolve_complex_language_aliases(LanguageID& language_id);
|
||||||
|
|
||||||
ErrorOr<Optional<LanguageID>> add_likely_subtags(LanguageID const& language_id);
|
Optional<LanguageID> add_likely_subtags(LanguageID const& language_id);
|
||||||
ErrorOr<Optional<LanguageID>> remove_likely_subtags(LanguageID const& language_id);
|
Optional<LanguageID> remove_likely_subtags(LanguageID const& language_id);
|
||||||
|
|
||||||
ErrorOr<Optional<String>> resolve_most_likely_territory(LanguageID const& language_id);
|
Optional<String> resolve_most_likely_territory(LanguageID const& language_id);
|
||||||
ErrorOr<String> resolve_most_likely_territory_alias(LanguageID const& language_id, StringView territory_alias);
|
String resolve_most_likely_territory_alias(LanguageID const& language_id, StringView territory_alias);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
namespace Locale {
|
namespace Locale {
|
||||||
|
|
||||||
ErrorOr<Optional<StringView>> __attribute__((weak)) get_number_system_symbol(StringView, StringView, NumericSymbol) { return OptionalNone {}; }
|
Optional<StringView> __attribute__((weak)) get_number_system_symbol(StringView, StringView, NumericSymbol) { return {}; }
|
||||||
ErrorOr<Optional<NumberGroupings>> __attribute__((weak)) get_number_system_groupings(StringView, StringView) { return OptionalNone {}; }
|
Optional<NumberGroupings> __attribute__((weak)) get_number_system_groupings(StringView, StringView) { return {}; }
|
||||||
ErrorOr<Optional<NumberFormat>> __attribute__((weak)) get_standard_number_system_format(StringView, StringView, StandardNumberFormatType) { return OptionalNone {}; }
|
ErrorOr<Optional<NumberFormat>> __attribute__((weak)) get_standard_number_system_format(StringView, StringView, StandardNumberFormatType) { return OptionalNone {}; }
|
||||||
ErrorOr<Vector<NumberFormat>> __attribute__((weak)) get_compact_number_system_formats(StringView, StringView, CompactNumberFormatType) { return Vector<NumberFormat> {}; }
|
ErrorOr<Vector<NumberFormat>> __attribute__((weak)) get_compact_number_system_formats(StringView, StringView, CompactNumberFormatType) { return Vector<NumberFormat> {}; }
|
||||||
ErrorOr<Vector<NumberFormat>> __attribute__((weak)) get_unit_formats(StringView, StringView, Style) { return Vector<NumberFormat> {}; }
|
ErrorOr<Vector<NumberFormat>> __attribute__((weak)) get_unit_formats(StringView, StringView, Style) { return Vector<NumberFormat> {}; }
|
||||||
|
|
|
@ -61,8 +61,8 @@ enum class NumericSymbol : u8 {
|
||||||
TimeSeparator,
|
TimeSeparator,
|
||||||
};
|
};
|
||||||
|
|
||||||
ErrorOr<Optional<StringView>> get_number_system_symbol(StringView locale, StringView system, NumericSymbol symbol);
|
Optional<StringView> get_number_system_symbol(StringView locale, StringView system, NumericSymbol symbol);
|
||||||
ErrorOr<Optional<NumberGroupings>> get_number_system_groupings(StringView locale, StringView system);
|
Optional<NumberGroupings> get_number_system_groupings(StringView locale, StringView system);
|
||||||
|
|
||||||
Optional<ReadonlySpan<u32>> get_digits_for_number_system(StringView system);
|
Optional<ReadonlySpan<u32>> get_digits_for_number_system(StringView system);
|
||||||
ErrorOr<String> replace_digits_for_number_system(StringView system, StringView number);
|
ErrorOr<String> replace_digits_for_number_system(StringView system, StringView number);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue