mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 05:25:32 +03:00
LibUnicode: Parse and generate long and short generic time zone names
This implements the CalendarPatternStyle::{Long,Short}Generic styles of time zone name formatting.
This commit is contained in:
parent
d50f5e14f8
commit
e2dfbe8f67
Notes:
sideshowbarker
2024-07-17 21:09:27 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/e2dfbe8f674 Pull-request: https://github.com/SerenityOS/serenity/pull/11813 Reviewed-by: https://github.com/linusg ✅
@ -383,16 +383,26 @@ struct AK::Traits<Calendar> : public GenericTraits<Calendar> {
|
|||||||
struct TimeZoneNames {
|
struct TimeZoneNames {
|
||||||
unsigned hash() const
|
unsigned hash() const
|
||||||
{
|
{
|
||||||
return pair_int_hash(long_name, short_name);
|
auto hash = pair_int_hash(short_standard_name, long_standard_name);
|
||||||
|
hash = pair_int_hash(hash, short_generic_name);
|
||||||
|
hash = pair_int_hash(hash, long_generic_name);
|
||||||
|
|
||||||
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(TimeZoneNames const& other) const
|
bool operator==(TimeZoneNames const& other) const
|
||||||
{
|
{
|
||||||
return (long_name == other.long_name) && (short_name == other.short_name);
|
return (short_standard_name == other.short_standard_name)
|
||||||
|
&& (long_standard_name == other.long_standard_name)
|
||||||
|
&& (short_generic_name == other.short_generic_name)
|
||||||
|
&& (long_generic_name == other.long_generic_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringIndexType long_name { 0 };
|
StringIndexType short_standard_name { 0 };
|
||||||
StringIndexType short_name { 0 };
|
StringIndexType long_standard_name { 0 };
|
||||||
|
|
||||||
|
StringIndexType short_generic_name { 0 };
|
||||||
|
StringIndexType long_generic_name { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -400,9 +410,11 @@ struct AK::Formatter<TimeZoneNames> : Formatter<FormatString> {
|
|||||||
ErrorOr<void> format(FormatBuilder& builder, TimeZoneNames const& time_zone)
|
ErrorOr<void> format(FormatBuilder& builder, TimeZoneNames const& time_zone)
|
||||||
{
|
{
|
||||||
return Formatter<FormatString>::format(builder,
|
return Formatter<FormatString>::format(builder,
|
||||||
"{{ {}, {} }}",
|
"{{ {}, {}, {}, {} }}",
|
||||||
time_zone.long_name,
|
time_zone.short_standard_name,
|
||||||
time_zone.short_name);
|
time_zone.long_standard_name,
|
||||||
|
time_zone.short_generic_name,
|
||||||
|
time_zone.long_generic_name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1411,18 +1423,16 @@ static ErrorOr<void> parse_time_zone_names(String locale_time_zone_names_path, U
|
|||||||
if (meta_zone_object.is_null())
|
if (meta_zone_object.is_null())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto parse_name = [&](StringView type, JsonObject const& meta_zone_object) -> Optional<StringIndexType> {
|
auto parse_name = [&](StringView type, JsonObject const& meta_zone_object, Span<StringView const> keys) -> Optional<StringIndexType> {
|
||||||
auto const& names = meta_zone_object.get(type);
|
auto const& names = meta_zone_object.get(type);
|
||||||
if (!names.is_object())
|
if (!names.is_object())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto const& daylight = names.as_object().get("daylight"sv);
|
for (auto key : keys) {
|
||||||
if (daylight.is_string())
|
auto const& name = names.as_object().get(key);
|
||||||
return locale_data.unique_strings.ensure(daylight.as_string());
|
if (name.is_string())
|
||||||
|
return locale_data.unique_strings.ensure(name.as_string());
|
||||||
auto const& standard = names.as_object().get("standard"sv);
|
}
|
||||||
if (standard.is_string())
|
|
||||||
return locale_data.unique_strings.ensure(standard.as_string());
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
@ -1458,16 +1468,23 @@ static ErrorOr<void> parse_time_zone_names(String locale_time_zone_names_path, U
|
|||||||
time_zone_formats.gmt_zero_format = locale_data.unique_strings.ensure(gmt_zero_format_string.as_string());
|
time_zone_formats.gmt_zero_format = locale_data.unique_strings.ensure(gmt_zero_format_string.as_string());
|
||||||
|
|
||||||
auto parse_time_zone = [&](StringView meta_zone, JsonObject const& meta_zone_object) {
|
auto parse_time_zone = [&](StringView meta_zone, JsonObject const& meta_zone_object) {
|
||||||
|
constexpr auto standard_keys = Array { "daylight"sv, "standard"sv };
|
||||||
|
constexpr auto generic_keys = Array { "generic"sv };
|
||||||
|
|
||||||
auto golden_zones = locale_data.meta_zones.find(meta_zone);
|
auto golden_zones = locale_data.meta_zones.find(meta_zone);
|
||||||
if (golden_zones == locale_data.meta_zones.end())
|
if (golden_zones == locale_data.meta_zones.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TimeZoneNames time_zone_names {};
|
TimeZoneNames time_zone_names {};
|
||||||
|
|
||||||
if (auto long_name = parse_name("long"sv, meta_zone_object); long_name.has_value())
|
if (auto name = parse_name("long"sv, meta_zone_object, standard_keys); name.has_value())
|
||||||
time_zone_names.long_name = long_name.value();
|
time_zone_names.long_standard_name = name.value();
|
||||||
if (auto short_name = parse_name("short"sv, meta_zone_object); short_name.has_value())
|
if (auto name = parse_name("short"sv, meta_zone_object, standard_keys); name.has_value())
|
||||||
time_zone_names.short_name = short_name.value();
|
time_zone_names.short_standard_name = name.value();
|
||||||
|
if (auto name = parse_name("long"sv, meta_zone_object, generic_keys); name.has_value())
|
||||||
|
time_zone_names.long_generic_name = name.value();
|
||||||
|
if (auto name = parse_name("short"sv, meta_zone_object, generic_keys); name.has_value())
|
||||||
|
time_zone_names.short_generic_name = name.value();
|
||||||
|
|
||||||
auto time_zone_index = locale_data.unique_time_zones.ensure(move(time_zone_names));
|
auto time_zone_index = locale_data.unique_time_zones.ensure(move(time_zone_names));
|
||||||
|
|
||||||
@ -1795,8 +1812,11 @@ struct CalendarData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TimeZoneNames {
|
struct TimeZoneNames {
|
||||||
@string_index_type@ long_name { 0 };
|
@string_index_type@ short_standard_name { 0 };
|
||||||
@string_index_type@ short_name { 0 };
|
@string_index_type@ long_standard_name { 0 };
|
||||||
|
|
||||||
|
@string_index_type@ short_generic_name { 0 };
|
||||||
|
@string_index_type@ long_generic_name { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimeZoneFormatImpl {
|
struct TimeZoneFormatImpl {
|
||||||
@ -2176,19 +2196,28 @@ static TimeZoneNames const* find_time_zone_names(StringView locale, StringView t
|
|||||||
|
|
||||||
Optional<StringView> get_time_zone_name(StringView locale, StringView time_zone, CalendarPatternStyle style)
|
Optional<StringView> get_time_zone_name(StringView locale, StringView time_zone, CalendarPatternStyle style)
|
||||||
{
|
{
|
||||||
if ((style == CalendarPatternStyle::Long) || (style == CalendarPatternStyle::Short)) {
|
if (auto const* data = find_time_zone_names(locale, time_zone); data != nullptr) {
|
||||||
if (auto const* data = find_time_zone_names(locale, time_zone); data != nullptr) {
|
size_t name_index = 0;
|
||||||
auto time_zone_index = style == CalendarPatternStyle::Long ? data->long_name : data->short_name;
|
|
||||||
if (time_zone_index != 0)
|
|
||||||
return s_string_list[time_zone_index];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// FIXME: We will need to parse the "generic" time zone names from timeZoneNames.json
|
|
||||||
// to support time zones other than UTC.
|
|
||||||
VERIFY(time_zone == "UTC"sv);
|
|
||||||
|
|
||||||
if (auto formats = get_time_zone_format(locale); formats.has_value())
|
switch (style) {
|
||||||
return formats->gmt_zero_format;
|
case CalendarPatternStyle::Short:
|
||||||
|
name_index = data->short_standard_name;
|
||||||
|
break;
|
||||||
|
case CalendarPatternStyle::Long:
|
||||||
|
name_index = data->long_standard_name;
|
||||||
|
break;
|
||||||
|
case CalendarPatternStyle::ShortGeneric:
|
||||||
|
name_index = data->short_generic_name;
|
||||||
|
break;
|
||||||
|
case CalendarPatternStyle::LongGeneric:
|
||||||
|
name_index = data->long_generic_name;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name_index != 0)
|
||||||
|
return s_string_list[name_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -23,37 +23,53 @@ TEST_CASE(time_zone_name)
|
|||||||
constexpr auto test_data = Array {
|
constexpr auto test_data = Array {
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "UTC"sv, "Coordinated Universal Time"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "UTC"sv, "Coordinated Universal Time"sv },
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "UTC"sv, "UTC"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "UTC"sv, "UTC"sv },
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::ShortGeneric, "UTC"sv, "GMT"sv },
|
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::LongGeneric, "UTC"sv, "GMT"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::LongGeneric, "UTC"sv, "GMT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::ShortGeneric, "UTC"sv, "GMT"sv },
|
||||||
|
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "UTC"sv, "التوقيت العالمي المنسق"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "UTC"sv, "التوقيت العالمي المنسق"sv },
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "UTC"sv, "UTC"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "UTC"sv, "UTC"sv },
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::ShortGeneric, "UTC"sv, "غرينتش"sv },
|
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::LongGeneric, "UTC"sv, "غرينتش"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::LongGeneric, "UTC"sv, "غرينتش"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::ShortGeneric, "UTC"sv, "غرينتش"sv },
|
||||||
|
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "America/Los_Angeles"sv, "Pacific Daylight Time"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "America/Los_Angeles"sv, "Pacific Daylight Time"sv },
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "America/Los_Angeles"sv, "PDT"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "America/Los_Angeles"sv, "PDT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::LongGeneric, "America/Los_Angeles"sv, "Pacific Time"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::ShortGeneric, "America/Los_Angeles"sv, "PT"sv },
|
||||||
|
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "America/Los_Angeles"sv, "توقيت المحيط الهادي الصيفي"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "America/Los_Angeles"sv, "توقيت المحيط الهادي الصيفي"sv },
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "America/Los_Angeles"sv, "غرينتش-٨"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "America/Los_Angeles"sv, "غرينتش-٨"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::LongGeneric, "America/Los_Angeles"sv, "توقيت المحيط الهادي"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::ShortGeneric, "America/Los_Angeles"sv, "غرينتش-٨"sv },
|
||||||
|
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "America/Vancouver"sv, "Pacific Daylight Time"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "America/Vancouver"sv, "Pacific Daylight Time"sv },
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "America/Vancouver"sv, "PDT"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "America/Vancouver"sv, "PDT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::LongGeneric, "America/Vancouver"sv, "Pacific Time"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::ShortGeneric, "America/Vancouver"sv, "PT"sv },
|
||||||
|
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "America/Vancouver"sv, "توقيت المحيط الهادي الصيفي"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "America/Vancouver"sv, "توقيت المحيط الهادي الصيفي"sv },
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "America/Vancouver"sv, "غرينتش-٨"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "America/Vancouver"sv, "غرينتش-٨"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::LongGeneric, "America/Vancouver"sv, "توقيت المحيط الهادي"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::ShortGeneric, "America/Vancouver"sv, "غرينتش-٨"sv },
|
||||||
|
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "Europe/London"sv, "Greenwich Mean Time"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "Europe/London"sv, "Greenwich Mean Time"sv },
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "Europe/London"sv, "GMT"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "Europe/London"sv, "GMT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::LongGeneric, "Europe/London"sv, "GMT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::ShortGeneric, "Europe/London"sv, "GMT"sv },
|
||||||
|
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "Europe/London"sv, "توقيت غرينتش"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "Europe/London"sv, "توقيت غرينتش"sv },
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "Europe/London"sv, "غرينتش"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "Europe/London"sv, "غرينتش"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::LongGeneric, "Europe/London"sv, "غرينتش"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::ShortGeneric, "Europe/London"sv, "غرينتش"sv },
|
||||||
|
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "Africa/Accra"sv, "Greenwich Mean Time"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Long, "Africa/Accra"sv, "Greenwich Mean Time"sv },
|
||||||
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "Africa/Accra"sv, "GMT"sv },
|
TestData { "en"sv, Unicode::CalendarPatternStyle::Short, "Africa/Accra"sv, "GMT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::LongGeneric, "Africa/Accra"sv, "GMT"sv },
|
||||||
|
TestData { "en"sv, Unicode::CalendarPatternStyle::ShortGeneric, "Africa/Accra"sv, "GMT"sv },
|
||||||
|
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "Africa/Accra"sv, "توقيت غرينتش"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Long, "Africa/Accra"sv, "توقيت غرينتش"sv },
|
||||||
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "Africa/Accra"sv, "غرينتش"sv },
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::Short, "Africa/Accra"sv, "غرينتش"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::LongGeneric, "Africa/Accra"sv, "غرينتش"sv },
|
||||||
|
TestData { "ar"sv, Unicode::CalendarPatternStyle::ShortGeneric, "Africa/Accra"sv, "غرينتش"sv },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr auto jan_1_2022 = AK::Time::from_seconds(1640995200); // Saturday, January 1, 2022 12:00:00 AM
|
constexpr auto jan_1_2022 = AK::Time::from_seconds(1640995200); // Saturday, January 1, 2022 12:00:00 AM
|
||||||
|
Loading…
Reference in New Issue
Block a user