diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp index 82e05bf6a7..0304eb9890 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp @@ -39,6 +39,9 @@ constexpr auto s_currency_list_index_type = "u16"sv; using CalendarListIndexType = u8; constexpr auto s_calendar_list_index_type = "u8"sv; +using DateFieldListIndexType = u8; +constexpr auto s_date_field_list_index_type = "u8"sv; + using KeywordListIndexType = u8; constexpr auto s_keyword_list_index_type = "u8"sv; @@ -113,6 +116,7 @@ using TerritoryList = Vector; using ScriptList = Vector; using CurrencyList = Vector; using CalendarList = Vector; +using DateFieldList = Vector; using KeywordList = Vector; using ListPatternList = Vector; @@ -128,6 +132,9 @@ struct Locale { CurrencyListIndexType narrow_currencies { 0 }; CurrencyListIndexType numeric_currencies { 0 }; CalendarListIndexType calendars { 0 }; + DateFieldListIndexType long_date_fields { 0 }; + DateFieldListIndexType short_date_fields { 0 }; + DateFieldListIndexType narrow_date_fields { 0 }; KeywordListIndexType keywords { 0 }; ListPatternListIndexType list_patterns { 0 }; }; @@ -144,6 +151,7 @@ struct UnicodeLocaleData { UniqueStorage unique_script_lists; UniqueStorage unique_currency_lists; UniqueStorage unique_calendar_lists; + UniqueStorage unique_date_field_lists; UniqueStorage unique_keyword_lists; UniqueStorage unique_list_patterns; UniqueStorage unique_list_pattern_lists; @@ -162,6 +170,14 @@ struct UnicodeLocaleData { { "ethiopic-amete-alem"sv, "ethioaa"sv }, { "gregorian"sv, "gregory"sv }, }; + Vector date_fields; + Vector date_field_aliases { + // ECMA-402 and the CLDR refer to some date fields with different names. Defining these aliases + // means we can remain agnostic about the naming differences elsewhere. + { "dayperiod"sv, "dayPeriod"sv }, + { "week"sv, "weekOfYear"sv }, + { "zone"sv, "timeZoneName"sv }, + }; Vector keywords { "ca"sv, "nu"sv }; // FIXME: These should be parsed from BCP47. https://unicode-org.atlassian.net/browse/CLDR-15158 Vector list_pattern_types; Vector list_pattern_styles; @@ -501,6 +517,64 @@ static ErrorOr parse_locale_calendars(String locale_path, UnicodeLocaleDat return {}; } +static ErrorOr parse_locale_date_fields(String dates_path, UnicodeLocaleData& locale_data, Locale& locale) +{ + LexicalPath date_fields_path(move(dates_path)); + date_fields_path = date_fields_path.append("dateFields.json"sv); + + auto date_fields_file = TRY(Core::File::open(date_fields_path.string(), Core::OpenMode::ReadOnly)); + auto locale_date_fields = TRY(JsonValue::from_string(date_fields_file->read_all())); + + auto const& main_object = locale_date_fields.as_object().get("main"sv); + auto const& locale_object = main_object.as_object().get(date_fields_path.parent().basename()); + auto const& dates_object = locale_object.as_object().get("dates"sv); + auto const& fields_object = dates_object.as_object().get("fields"sv); + + auto is_sanctioned_field = [](StringView field) { + // This is a copy of the units sanctioned for use within ECMA-402, with names adjusted for the names used by the CLDR. + // https://tc39.es/ecma402/#table-validcodeforDateField + return field.is_one_of("era"sv, "year"sv, "quarter"sv, "month"sv, "week"sv, "weekday"sv, "day"sv, "dayperiod"sv, "hour"sv, "minute"sv, "second"sv, "zone"sv); + }; + + fields_object.as_object().for_each_member([&](auto const& key, JsonValue const&) { + if (!is_sanctioned_field(key)) + return; + + if (!locale_data.date_fields.contains_slow(key)) + locale_data.date_fields.append(key); + }); + + quick_sort(locale_data.date_fields); + + DateFieldList long_date_fields {}; + long_date_fields.resize(locale_data.date_fields.size()); + + DateFieldList short_date_fields {}; + short_date_fields.resize(locale_data.date_fields.size()); + + DateFieldList narrow_date_fields {}; + narrow_date_fields.resize(locale_data.date_fields.size()); + + fields_object.as_object().for_each_member([&](auto const& key, JsonValue const& value) { + if (!is_sanctioned_field(key)) + return; + + auto const& long_name = value.as_object().get("displayName"sv); + auto const& short_name = fields_object.as_object().get(String::formatted("{}-short", key)).as_object().get("displayName"sv); + auto const& narrow_name = fields_object.as_object().get(String::formatted("{}-narrow", key)).as_object().get("displayName"sv); + + auto index = locale_data.date_fields.find_first_index(key).value(); + long_date_fields[index] = locale_data.unique_strings.ensure(long_name.as_string()); + short_date_fields[index] = locale_data.unique_strings.ensure(short_name.as_string()); + narrow_date_fields[index] = locale_data.unique_strings.ensure(narrow_name.as_string()); + }); + + locale.long_date_fields = locale_data.unique_date_field_lists.ensure(move(long_date_fields)); + locale.short_date_fields = locale_data.unique_date_field_lists.ensure(move(short_date_fields)); + locale.narrow_date_fields = locale_data.unique_date_field_lists.ensure(move(narrow_date_fields)); + return {}; +} + static ErrorOr parse_numeric_keywords(String locale_numbers_path, UnicodeLocaleData& locale_data, KeywordList& keywords) { static constexpr StringView key = "nu"sv; @@ -748,6 +822,9 @@ static ErrorOr parse_all_locales(String core_path, String locale_names_pat auto dates_path = TRY(next_path_from_dir_iterator(dates_iterator)); auto language = TRY(remove_variants_from_path(dates_path)); + auto& locale = locale_data.locales.ensure(language); + TRY(parse_locale_date_fields(dates_path, locale_data, locale)); + auto& keywords = ensure_keyword_list(language); TRY(parse_calendar_keywords(dates_path, locale_data, keywords)); } @@ -783,6 +860,7 @@ namespace Unicode { generate_enum(generator, format_identifier, "ScriptTag"sv, {}, locale_data.scripts); generate_enum(generator, format_identifier, "Currency"sv, {}, locale_data.currencies); generate_enum(generator, format_identifier, "CalendarName"sv, {}, locale_data.calendars, locale_data.calendar_aliases); + generate_enum(generator, format_identifier, "DateField"sv, {}, locale_data.date_fields, locale_data.date_field_aliases); generate_enum(generator, format_identifier, "Key"sv, {}, locale_data.keywords); generate_enum(generator, format_identifier, "Variant"sv, {}, locale_data.variants); generate_enum(generator, format_identifier, "ListPatternType"sv, {}, locale_data.list_pattern_types); @@ -832,6 +910,7 @@ struct Patterns { locale_data.unique_script_lists.generate(generator, s_string_index_type, "s_script_lists"sv); locale_data.unique_currency_lists.generate(generator, s_string_index_type, "s_currency_lists"sv); locale_data.unique_calendar_lists.generate(generator, s_string_index_type, "s_calendar_lists"sv); + locale_data.unique_date_field_lists.generate(generator, s_string_index_type, "s_date_field_lists"sv); locale_data.unique_keyword_lists.generate(generator, s_string_index_type, "s_keyword_lists"sv); locale_data.unique_list_patterns.generate(generator, "Patterns"sv, "s_list_patterns"sv, 10); locale_data.unique_list_pattern_lists.generate(generator, s_list_pattern_index_type, "s_list_pattern_lists"sv); @@ -888,6 +967,9 @@ static constexpr Array<@type@, @size@> @name@ { {)~~~"); append_mapping(locales, locale_data.locales, s_currency_list_index_type, "s_narrow_currencies"sv, [&](auto const& locale) { return locale.narrow_currencies; }); append_mapping(locales, locale_data.locales, s_currency_list_index_type, "s_numeric_currencies"sv, [&](auto const& locale) { return locale.numeric_currencies; }); append_mapping(locales, locale_data.locales, s_calendar_list_index_type, "s_calendars"sv, [&](auto const& locale) { return locale.calendars; }); + append_mapping(locales, locale_data.locales, s_date_field_list_index_type, "s_long_date_fields"sv, [&](auto const& locale) { return locale.long_date_fields; }); + append_mapping(locales, locale_data.locales, s_date_field_list_index_type, "s_short_date_fields"sv, [&](auto const& locale) { return locale.short_date_fields; }); + append_mapping(locales, locale_data.locales, s_date_field_list_index_type, "s_narrow_date_fields"sv, [&](auto const& locale) { return locale.narrow_date_fields; }); append_mapping(locales, locale_data.locales, s_keyword_list_index_type, "s_keywords"sv, [&](auto const& locale) { return locale.keywords; }); append_mapping(locales, locale_data.locales, s_list_pattern_list_index_type, "s_locale_list_patterns"sv, [&](auto const& locale) { return locale.list_patterns; }); @@ -1154,6 +1236,11 @@ Optional get_locale_@enum_snake@_mapping(StringView locale, StringVi append_from_string("CalendarName"sv, "calendar_name"sv, locale_data.calendars, locale_data.calendar_aliases); append_mapping_search("calendar"sv, "calendar_name"sv, "s_calendars"sv, "s_calendar_lists"sv); + append_from_string("DateField"sv, "date_field"sv, locale_data.date_fields, locale_data.date_field_aliases); + append_mapping_search("long_date_field"sv, "date_field"sv, "s_long_date_fields"sv, "s_date_field_lists"sv); + append_mapping_search("short_date_field"sv, "date_field"sv, "s_short_date_fields"sv, "s_date_field_lists"sv); + append_mapping_search("narrow_date_field"sv, "date_field"sv, "s_narrow_date_fields"sv, "s_date_field_lists"sv); + append_from_string("Key"sv, "key"sv, locale_data.keywords); append_mapping_search("key"sv, "key"sv, "s_keywords"sv, "s_keyword_lists"sv); diff --git a/Userland/Libraries/LibUnicode/Forward.h b/Userland/Libraries/LibUnicode/Forward.h index de9640d741..0c2ea6ee01 100644 --- a/Userland/Libraries/LibUnicode/Forward.h +++ b/Userland/Libraries/LibUnicode/Forward.h @@ -18,6 +18,7 @@ enum class CalendarSymbol : u8; enum class CompactNumberFormatType : u8; enum class Condition : u8; enum class Currency : u16; +enum class DateField : u8; enum class DayPeriod : u8; enum class Era : u8; enum class GeneralCategory : u8; diff --git a/Userland/Libraries/LibUnicode/Locale.cpp b/Userland/Libraries/LibUnicode/Locale.cpp index 9ed9420e2b..e0362979e8 100644 --- a/Userland/Libraries/LibUnicode/Locale.cpp +++ b/Userland/Libraries/LibUnicode/Locale.cpp @@ -747,6 +747,7 @@ Optional __attribute__((weak)) territory_from_string(StringView) { re Optional __attribute__((weak)) script_tag_from_string(StringView) { return {}; } Optional __attribute__((weak)) currency_from_string(StringView) { return {}; } Optional __attribute__((weak)) calendar_name_from_string(StringView) { return {}; } +Optional __attribute__((weak)) date_field_from_string(StringView) { return {}; } Optional __attribute__((weak)) key_from_string(StringView) { return {}; } Optional __attribute__((weak)) list_pattern_type_from_string(StringView) { return {}; } Optional __attribute__((weak)) list_pattern_style_from_string(StringView) { return {}; } @@ -758,6 +759,9 @@ Optional __attribute__((weak)) get_locale_short_currency_mapping(Str Optional __attribute__((weak)) get_locale_narrow_currency_mapping(StringView, StringView) { return {}; } Optional __attribute__((weak)) get_locale_numeric_currency_mapping(StringView, StringView) { return {}; } Optional __attribute__((weak)) get_locale_calendar_mapping(StringView, StringView) { return {}; } +Optional __attribute__((weak)) get_locale_long_date_field_mapping(StringView, StringView) { return {}; } +Optional __attribute__((weak)) get_locale_short_date_field_mapping(StringView, StringView) { return {}; } +Optional __attribute__((weak)) get_locale_narrow_date_field_mapping(StringView, StringView) { return {}; } Optional get_locale_currency_mapping(StringView locale, StringView currency, Style style) { diff --git a/Userland/Libraries/LibUnicode/Locale.h b/Userland/Libraries/LibUnicode/Locale.h index d410cf475e..a26aae8356 100644 --- a/Userland/Libraries/LibUnicode/Locale.h +++ b/Userland/Libraries/LibUnicode/Locale.h @@ -147,6 +147,7 @@ Optional territory_from_string(StringView territory); Optional script_tag_from_string(StringView script_tag); Optional currency_from_string(StringView currency); Optional calendar_name_from_string(StringView calendar); +Optional date_field_from_string(StringView calendar); Optional key_from_string(StringView key); Optional list_pattern_type_from_string(StringView list_pattern_type); Optional list_pattern_style_from_string(StringView list_pattern_style); @@ -160,6 +161,9 @@ Optional get_locale_narrow_currency_mapping(StringView locale, Strin Optional get_locale_numeric_currency_mapping(StringView locale, StringView currency); Optional get_locale_currency_mapping(StringView locale, StringView currency, Style style); Optional get_locale_calendar_mapping(StringView locale, StringView calendar); +Optional get_locale_long_date_field_mapping(StringView locale, StringView date_field); +Optional get_locale_short_date_field_mapping(StringView locale, StringView date_field); +Optional get_locale_narrow_date_field_mapping(StringView locale, StringView date_field); Optional get_locale_key_mapping(StringView locale, StringView keyword); Vector get_locale_key_mapping_list(StringView locale, StringView keyword);