فهرست منبع

LibJS+LibUnicode: Generate missing patterns with fractionalSecondDigits

TR-35's Matching Skeleton algorithm dictates how user requests including
fractional second digits should be handled when the CLDR format pattern
does not include that field. When the format pattern contains {second},
but does not contain {fractionalSecondDigits}, generate a second pattern
which appends "{decimal}{fractionalSecondDigits}" to the {second} field.
Timothy Flynn 3 سال پیش
والد
کامیت
9f7c727720

+ 25 - 1
Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeDateTimeFormat.cpp

@@ -466,6 +466,13 @@ static void generate_missing_patterns(Calendar& calendar, Vector<CalendarPattern
         return locale_data.unique_strings.ensure(move(new_pattern));
     };
 
+    auto inject_fractional_second_digits = [&](auto format) {
+        auto pattern = locale_data.unique_strings.get(format);
+
+        auto new_pattern = pattern.replace("{second}"sv, "{second}{decimal}{fractionalSecondDigits}"sv);
+        return locale_data.unique_strings.ensure(move(new_pattern));
+    };
+
     auto append_if_unique = [&](auto format) {
         auto format_index = locale_data.unique_patterns.ensure(move(format));
 
@@ -473,11 +480,28 @@ static void generate_missing_patterns(Calendar& calendar, Vector<CalendarPattern
             calendar.available_formats.append(format_index);
     };
 
+    Vector<CalendarPattern> time_formats_with_fractional_second_digits;
+
     for (auto const& format : date_formats)
         append_if_unique(format);
-    for (auto const& format : time_formats)
+    for (auto const& format : time_formats) {
         append_if_unique(format);
 
+        if (format.second.has_value() && !format.fractional_second_digits.has_value()) {
+            auto new_format = format;
+            new_format.fractional_second_digits = 2;
+
+            new_format.pattern_index = inject_fractional_second_digits(new_format.pattern_index);
+            if (new_format.pattern12_index != 0)
+                new_format.pattern12_index = inject_fractional_second_digits(new_format.pattern12_index);
+
+            time_formats_with_fractional_second_digits.append(new_format);
+            append_if_unique(move(new_format));
+        }
+    }
+
+    time_formats.extend(move(time_formats_with_fractional_second_digits));
+
     for (auto const& date_format : date_formats) {
         CalendarPatternIndexType date_time_format_index = 0;
 

+ 12 - 3
Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp

@@ -659,9 +659,18 @@ Optional<Unicode::CalendarPattern> basic_format_matcher(Unicode::CalendarPattern
     //
     // Rather than generating an prohibitively large amount of nearly-duplicate patterns, which only
     // differ by field length, we expand the field lengths here.
-    best_format->for_each_calendar_field_zipped_with(options, [](auto& best_format_field, auto const& option_field, auto) {
-        if (best_format_field.has_value() && option_field.has_value())
-            best_format_field = option_field;
+    best_format->for_each_calendar_field_zipped_with(options, [&](auto& best_format_field, auto const& option_field, auto field_type) {
+        switch (field_type) {
+        case Unicode::CalendarPattern::Field::FractionalSecondDigits:
+            if (best_format->second.has_value() && option_field.has_value())
+                best_format_field = option_field;
+            break;
+
+        default:
+            if (best_format_field.has_value() && option_field.has_value())
+                best_format_field = option_field;
+            break;
+        }
     });
 
     // 11. Return bestFormat.

+ 9 - 3
Userland/Libraries/LibJS/Tests/builtins/Intl/DateTimeFormat/DateTimeFormat.prototype.resolvedOptions.js

@@ -1,6 +1,3 @@
-// NOTE: We cannot yet test the fractionalSecondDigits option. There aren't any patterns in the CLDR
-//       with this field ('S' in https://unicode.org/reports/tr35/tr35-dates.html#dfst-second). We
-//       will need to figure out how this field should be generated.
 describe("correct behavior", () => {
     test("length is 0", () => {
         expect(Intl.DateTimeFormat.prototype.resolvedOptions).toHaveLength(0);
@@ -179,6 +176,15 @@ describe("correct behavior", () => {
         });
     });
 
+    test("fractionalSecondDigits", () => {
+        [1, 2, 3].forEach(fractionalSecondDigits => {
+            const en = new Intl.DateTimeFormat("en", {
+                fractionalSecondDigits: fractionalSecondDigits,
+            });
+            expect(en.resolvedOptions().fractionalSecondDigits).toBe(fractionalSecondDigits);
+        });
+    });
+
     test("timeZoneName", () => {
         ["short", "long"].forEach(timeZoneName => {
             const en = new Intl.DateTimeFormat("en", { timeZoneName: timeZoneName });