mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-13 11:42:38 +03:00
LibJS+LibUnicode: Generate all styles of currency localizations
Currently, LibUnicode is only parsing and generating the "long" style of currency display names. However, the CLDR contains "short" and "narrow" forms as well that need to be handled. Parse these, and update LibJS to actually respect the "style" option provided by the user for displaying currencies with Intl.DisplayNames. Note: There are some discrepencies between the engines on how style is handled. In particular, running: new Intl.DisplayNames('en', {type:'currency', style:'narrow'}).of('usd') Gives: SpiderMoney: "USD" V8: "US Dollar" LibJS: "$" And running: new Intl.DisplayNames('en', {type:'currency', style:'short'}).of('usd') Gives: SpiderMonkey: "$" V8: "US Dollar" LibJS: "$" My best guess is V8 isn't handling style, and just returning the long form (which is what LibJS did before this commit). And SpiderMoney can handle some styles, but if they don't have a value for the requested style, they fall back to the canonicalized code passed into of().
This commit is contained in:
parent
6cfd63e5bd
commit
39e031c4dd
Notes:
sideshowbarker
2024-07-18 01:12:08 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/39e031c4ddc Pull-request: https://github.com/SerenityOS/serenity/pull/10894 Reviewed-by: https://github.com/linusg ✅
@ -40,7 +40,10 @@ struct Locale {
|
||||
HashMap<String, StringIndexType> languages;
|
||||
HashMap<String, StringIndexType> territories;
|
||||
HashMap<String, StringIndexType> scripts;
|
||||
HashMap<String, StringIndexType> currencies;
|
||||
HashMap<String, StringIndexType> long_currencies;
|
||||
HashMap<String, StringIndexType> short_currencies;
|
||||
HashMap<String, StringIndexType> narrow_currencies;
|
||||
HashMap<String, StringIndexType> numeric_currencies;
|
||||
HashMap<String, StringIndexType> keywords;
|
||||
Vector<ListPatterns> list_patterns;
|
||||
};
|
||||
@ -335,10 +338,15 @@ static void parse_locale_currencies(String numbers_path, UnicodeLocaleData& loca
|
||||
auto const& currencies_object = locale_numbers_object.as_object().get("currencies"sv);
|
||||
|
||||
currencies_object.as_object().for_each_member([&](auto const& key, JsonValue const& value) {
|
||||
auto const& display_name = value.as_object().get("displayName"sv);
|
||||
auto const& long_name = value.as_object().get("displayName"sv);
|
||||
auto const& short_name = value.as_object().get("symbol"sv);
|
||||
auto const& narrow_name = value.as_object().get("symbol-alt-narrow"sv);
|
||||
auto const& numeric_name = value.as_object().get("displayName-count-other"sv);
|
||||
|
||||
auto index = locale_data.unique_strings.ensure(display_name.as_string());
|
||||
locale.currencies.set(key, index);
|
||||
locale.long_currencies.set(key, locale_data.unique_strings.ensure(long_name.as_string()));
|
||||
locale.short_currencies.set(key, locale_data.unique_strings.ensure(short_name.as_string()));
|
||||
locale.narrow_currencies.set(key, narrow_name.is_null() ? 0 : locale_data.unique_strings.ensure(narrow_name.as_string()));
|
||||
locale.numeric_currencies.set(key, locale_data.unique_strings.ensure(numeric_name.is_null() ? long_name.as_string() : numeric_name.as_string()));
|
||||
|
||||
if (!locale_data.currencies.contains_slow(key))
|
||||
locale_data.currencies.append(key);
|
||||
@ -565,7 +573,10 @@ Optional<StringView> get_locale_script_tag_mapping(StringView locale, StringView
|
||||
Optional<ScriptTag> script_tag_from_string(StringView script_tag);
|
||||
Optional<StringView> resolve_script_tag_alias(StringView script_tag);
|
||||
|
||||
Optional<StringView> get_locale_currency_mapping(StringView locale, StringView currency);
|
||||
Optional<StringView> get_locale_long_currency_mapping(StringView locale, StringView currency);
|
||||
Optional<StringView> get_locale_short_currency_mapping(StringView locale, StringView currency);
|
||||
Optional<StringView> get_locale_narrow_currency_mapping(StringView locale, StringView currency);
|
||||
Optional<StringView> get_locale_numeric_currency_mapping(StringView locale, StringView currency);
|
||||
Optional<Currency> currency_from_string(StringView currency);
|
||||
|
||||
Optional<StringView> get_locale_key_mapping(StringView locale, StringView key);
|
||||
@ -700,7 +711,10 @@ static constexpr Array<Patterns, @size@> @name@ { {)~~~");
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_languages"sv, "s_languages_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.languages, value.languages); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_territories"sv, "s_territories_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.territories, value.territories); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_scripts"sv, "s_scripts_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.scripts, value.scripts); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_currencies"sv, "s_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.currencies); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_long_currencies"sv, "s_long_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.long_currencies); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_short_currencies"sv, "s_short_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.short_currencies); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_narrow_currencies"sv, "s_narrow_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.narrow_currencies); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_numeric_currencies"sv, "s_numeric_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.numeric_currencies); });
|
||||
generate_mapping(generator, locale_data.locales, s_string_index_type, "s_keywords"sv, "s_keywords_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.keywords, value.keywords); });
|
||||
generate_mapping(generator, locale_data.locales, "Patterns"sv, "s_list_patterns"sv, "s_list_patterns_{}", [&](auto const& name, auto const& value) { append_list_patterns(name, value.list_patterns); });
|
||||
|
||||
@ -884,9 +898,9 @@ static LanguageMapping const* resolve_likely_subtag(Unicode::LanguageID const& l
|
||||
|
||||
)~~~");
|
||||
|
||||
auto append_mapping_search = [&](StringView enum_title, StringView enum_snake, StringView collection_name) {
|
||||
generator.set("enum_title", enum_title);
|
||||
auto append_mapping_search = [&](StringView enum_snake, StringView from_string_name, StringView collection_name) {
|
||||
generator.set("enum_snake", enum_snake);
|
||||
generator.set("from_string_name", from_string_name);
|
||||
generator.set("collection_name", collection_name);
|
||||
generator.append(R"~~~(
|
||||
Optional<StringView> get_locale_@enum_snake@_mapping(StringView locale, StringView @enum_snake@)
|
||||
@ -895,7 +909,7 @@ Optional<StringView> get_locale_@enum_snake@_mapping(StringView locale, StringVi
|
||||
if (!locale_value.has_value())
|
||||
return {};
|
||||
|
||||
auto @enum_snake@_value = @enum_snake@_from_string(@enum_snake@);
|
||||
auto @enum_snake@_value = @from_string_name@_from_string(@enum_snake@);
|
||||
if (!@enum_snake@_value.has_value())
|
||||
return {};
|
||||
|
||||
@ -935,22 +949,25 @@ Optional<StringView> get_locale_@enum_snake@_mapping(StringView locale, StringVi
|
||||
|
||||
append_from_string("Locale"sv, "locale"sv, locale_data.locales.keys());
|
||||
|
||||
append_mapping_search("Language"sv, "language"sv, "s_languages"sv);
|
||||
append_mapping_search("language"sv, "language"sv, "s_languages"sv);
|
||||
append_from_string("Language"sv, "language"sv, locale_data.languages);
|
||||
append_alias_search("language"sv, locale_data.language_aliases);
|
||||
|
||||
append_mapping_search("Territory"sv, "territory"sv, "s_territories"sv);
|
||||
append_mapping_search("territory"sv, "territory"sv, "s_territories"sv);
|
||||
append_from_string("Territory"sv, "territory"sv, locale_data.territories);
|
||||
append_alias_search("territory"sv, locale_data.territory_aliases);
|
||||
|
||||
append_mapping_search("ScriptTag"sv, "script_tag"sv, "s_scripts"sv);
|
||||
append_mapping_search("script_tag"sv, "script_tag"sv, "s_scripts"sv);
|
||||
append_from_string("ScriptTag"sv, "script_tag"sv, locale_data.scripts);
|
||||
append_alias_search("script_tag"sv, locale_data.script_aliases);
|
||||
|
||||
append_mapping_search("Currency"sv, "currency"sv, "s_currencies"sv);
|
||||
append_mapping_search("long_currency"sv, "currency"sv, "s_long_currencies"sv);
|
||||
append_mapping_search("short_currency"sv, "currency"sv, "s_short_currencies"sv);
|
||||
append_mapping_search("narrow_currency"sv, "currency"sv, "s_narrow_currencies"sv);
|
||||
append_mapping_search("numeric_currency"sv, "currency"sv, "s_numeric_currencies"sv);
|
||||
append_from_string("Currency"sv, "currency"sv, locale_data.currencies);
|
||||
|
||||
append_mapping_search("Key"sv, "key"sv, "s_keywords"sv);
|
||||
append_mapping_search("key"sv, "key"sv, "s_keywords"sv);
|
||||
append_from_string("Key"sv, "key"sv, locale_data.keywords);
|
||||
|
||||
append_alias_search("variant"sv, locale_data.variant_aliases);
|
||||
|
@ -63,7 +63,19 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of)
|
||||
result = Unicode::get_locale_script_mapping(display_names->locale(), code.as_string().string());
|
||||
break;
|
||||
case DisplayNames::Type::Currency:
|
||||
result = Unicode::get_locale_currency_mapping(display_names->locale(), code.as_string().string());
|
||||
switch (display_names->style()) {
|
||||
case DisplayNames::Style::Long:
|
||||
result = Unicode::get_locale_currency_mapping(display_names->locale(), code.as_string().string(), Unicode::Style::Long);
|
||||
break;
|
||||
case DisplayNames::Style::Short:
|
||||
result = Unicode::get_locale_currency_mapping(display_names->locale(), code.as_string().string(), Unicode::Style::Short);
|
||||
break;
|
||||
case DisplayNames::Style::Narrow:
|
||||
result = Unicode::get_locale_currency_mapping(display_names->locale(), code.as_string().string(), Unicode::Style::Narrow);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -74,18 +74,48 @@ describe("correct behavior", () => {
|
||||
expect(zhHant.of("Aaaa")).toBe("Aaaa");
|
||||
});
|
||||
|
||||
test("option type currency", () => {
|
||||
const en = new Intl.DisplayNames("en", { type: "currency" });
|
||||
test("option type currency, style long", () => {
|
||||
const en = new Intl.DisplayNames("en", { type: "currency", style: "long" });
|
||||
expect(en.of("USD")).toBe("US Dollar");
|
||||
|
||||
const es419 = new Intl.DisplayNames("es-419", { type: "currency" });
|
||||
const es419 = new Intl.DisplayNames("es-419", { type: "currency", style: "long" });
|
||||
expect(es419.of("USD")).toBe("dólar estadounidense");
|
||||
|
||||
const zhHant = new Intl.DisplayNames(["zh-Hant"], { type: "currency" });
|
||||
const zhHant = new Intl.DisplayNames(["zh-Hant"], { type: "currency", style: "long" });
|
||||
expect(zhHant.of("USD")).toBe("美元");
|
||||
|
||||
expect(en.of("AAA")).toBe("AAA");
|
||||
expect(es419.of("AAA")).toBe("AAA");
|
||||
expect(zhHant.of("AAA")).toBe("AAA");
|
||||
});
|
||||
|
||||
test("option type currency, style short", () => {
|
||||
const en = new Intl.DisplayNames("en", { type: "currency", style: "short" });
|
||||
expect(en.of("USD")).toBe("$");
|
||||
|
||||
const es419 = new Intl.DisplayNames("es-419", { type: "currency", style: "short" });
|
||||
expect(es419.of("USD")).toBe("USD");
|
||||
|
||||
const zhHant = new Intl.DisplayNames(["zh-Hant"], { type: "currency", style: "short" });
|
||||
expect(zhHant.of("USD")).toBe("US$");
|
||||
|
||||
expect(en.of("AAA")).toBe("AAA");
|
||||
expect(es419.of("AAA")).toBe("AAA");
|
||||
expect(zhHant.of("AAA")).toBe("AAA");
|
||||
});
|
||||
|
||||
test("option type currency, style narrow", () => {
|
||||
const en = new Intl.DisplayNames("en", { type: "currency", style: "narrow" });
|
||||
expect(en.of("USD")).toBe("$");
|
||||
|
||||
const es419 = new Intl.DisplayNames("es-419", { type: "currency", style: "narrow" });
|
||||
expect(es419.of("USD")).toBe("$");
|
||||
|
||||
const zhHant = new Intl.DisplayNames(["zh-Hant"], { type: "currency", style: "narrow" });
|
||||
expect(zhHant.of("USD")).toBe("$");
|
||||
|
||||
expect(en.of("AAA")).toBe("AAA");
|
||||
expect(es419.of("AAA")).toBe("AAA");
|
||||
expect(zhHant.of("AAA")).toBe("AAA");
|
||||
});
|
||||
});
|
||||
|
@ -786,13 +786,21 @@ Optional<StringView> get_locale_script_mapping([[maybe_unused]] StringView local
|
||||
#endif
|
||||
}
|
||||
|
||||
Optional<StringView> get_locale_currency_mapping([[maybe_unused]] StringView locale, [[maybe_unused]] StringView currency)
|
||||
Optional<StringView> get_locale_currency_mapping([[maybe_unused]] StringView locale, [[maybe_unused]] StringView currency, [[maybe_unused]] Style style)
|
||||
{
|
||||
#if ENABLE_UNICODE_DATA
|
||||
return Detail::get_locale_currency_mapping(locale, currency);
|
||||
#else
|
||||
return {};
|
||||
switch (style) {
|
||||
case Style::Long:
|
||||
return Detail::get_locale_long_currency_mapping(locale, currency);
|
||||
case Style::Short:
|
||||
return Detail::get_locale_short_currency_mapping(locale, currency);
|
||||
case Style::Narrow:
|
||||
return Detail::get_locale_narrow_currency_mapping(locale, currency);
|
||||
case Style::Numeric:
|
||||
return Detail::get_locale_numeric_currency_mapping(locale, currency);
|
||||
}
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
Vector<StringView> get_locale_key_mapping([[maybe_unused]] StringView locale, [[maybe_unused]] StringView keyword)
|
||||
|
@ -78,6 +78,13 @@ struct LocaleID {
|
||||
Vector<String> private_use_extensions {};
|
||||
};
|
||||
|
||||
enum class Style : u8 {
|
||||
Long,
|
||||
Short,
|
||||
Narrow,
|
||||
Numeric,
|
||||
};
|
||||
|
||||
enum class StandardNumberFormatType : u8 {
|
||||
Decimal,
|
||||
Currency,
|
||||
@ -170,7 +177,7 @@ Optional<Locale> locale_from_string(StringView locale);
|
||||
Optional<StringView> get_locale_language_mapping(StringView locale, StringView language);
|
||||
Optional<StringView> get_locale_territory_mapping(StringView locale, StringView territory);
|
||||
Optional<StringView> get_locale_script_mapping(StringView locale, StringView script);
|
||||
Optional<StringView> get_locale_currency_mapping(StringView locale, StringView currency);
|
||||
Optional<StringView> get_locale_currency_mapping(StringView locale, StringView currency, Style style);
|
||||
Vector<StringView> get_locale_key_mapping(StringView locale, StringView keyword);
|
||||
Optional<StringView> get_number_system_symbol(StringView locale, StringView system, StringView symbol);
|
||||
Optional<NumberFormat> get_standard_number_system_format(StringView locale, StringView system, StandardNumberFormatType type);
|
||||
|
Loading…
Reference in New Issue
Block a user