소스 검색

LibJS: Delegate to NumberFormat for DurationFormat unit formatting

This is a normative change in the Intl.DurationFormat proposal. See:
https://github.com/tc39/proposal-intl-duration-format/commit/12ba9df
Timothy Flynn 2 년 전
부모
커밋
99fc94e138
2개의 변경된 파일33개의 추가작업 그리고 47개의 파일을 삭제
  1. 32 46
      Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp
  2. 1 1
      Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.h

+ 32 - 46
Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp

@@ -299,19 +299,6 @@ ThrowCompletionOr<DurationUnitOptions> get_duration_unit_options(VM& vm, String
     return DurationUnitOptions { .style = move(style), .display = display.as_string().string() };
     return DurationUnitOptions { .style = move(style), .display = display.as_string().string() };
 }
 }
 
 
-// FIXME: LibUnicode currently only exposes unit patterns converted to an ECMA402 NumberFormat-specific format,
-//  since DurationFormat only needs a tiny subset of it, it's much easier to just convert it to the expected format
-//  here, but at some point we should split the NumberFormat exporter to export both formats of the data.
-static String convert_number_format_pattern_to_duration_format_template(::Locale::NumberFormat const& number_format)
-{
-    auto result = number_format.zero_format.replace("{number}"sv, "{0}"sv, ReplaceMode::FirstOnly);
-
-    for (size_t i = 0; i < number_format.identifiers.size(); ++i)
-        result = result.replace(String::formatted("{{unitIdentifier:{}}}", i), number_format.identifiers[i], ReplaceMode::FirstOnly);
-
-    return result;
-}
-
 // 1.1.7 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/proposal-intl-duration-format/#sec-partitiondurationformatpattern
 // 1.1.7 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/proposal-intl-duration-format/#sec-partitiondurationformatpattern
 Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationFormat const& duration_format, Temporal::DurationRecord const& duration)
 Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationFormat const& duration_format, Temporal::DurationRecord const& duration)
 {
 {
@@ -339,19 +326,22 @@ Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationForma
         // d. Let unit be the Unit value.
         // d. Let unit be the Unit value.
         auto unit = duration_instances_component.unit;
         auto unit = duration_instances_component.unit;
 
 
-        // e. Let style be durationFormat.[[<styleSlot>]].
+        // e. Let numberFormatUnit be the NumberFormat Unit value.
+        auto number_format_unit = duration_instances_component.number_format_unit;
+
+        // f. Let style be durationFormat.[[<styleSlot>]].
         auto style = (duration_format.*style_slot)();
         auto style = (duration_format.*style_slot)();
 
 
-        // f. Let display be durationFormat.[[<displaySlot>]].
+        // g. Let display be durationFormat.[[<displaySlot>]].
         auto display = (duration_format.*display_slot)();
         auto display = (duration_format.*display_slot)();
 
 
-        // g. Let value be duration.[[<valueSlot>]].
+        // h. Let value be duration.[[<valueSlot>]].
         auto value = duration.*value_slot;
         auto value = duration.*value_slot;
 
 
-        // h. Let nfOpts be ! OrdinaryObjectCreate(null).
+        // i. Let nfOpts be ! OrdinaryObjectCreate(null).
         auto* number_format_options = Object::create(realm, nullptr);
         auto* number_format_options = Object::create(realm, nullptr);
 
 
-        // i. If unit is "seconds", "milliseconds", or "microseconds", then
+        // j. If unit is "seconds", "milliseconds", or "microseconds", then
         if (unit.is_one_of("seconds"sv, "milliseconds"sv, "microseconds"sv)) {
         if (unit.is_one_of("seconds"sv, "milliseconds"sv, "microseconds"sv)) {
             DurationFormat::ValueStyle next_style;
             DurationFormat::ValueStyle next_style;
 
 
@@ -400,31 +390,31 @@ Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationForma
             }
             }
         }
         }
 
 
-        // j. If style is "2-digit", then
+        // k. If style is "2-digit", then
         if (style == DurationFormat::ValueStyle::TwoDigit) {
         if (style == DurationFormat::ValueStyle::TwoDigit) {
             // i. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2𝔽).
             // i. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2𝔽).
             MUST(number_format_options->create_data_property_or_throw(vm.names.minimumIntegerDigits, Value(2)));
             MUST(number_format_options->create_data_property_or_throw(vm.names.minimumIntegerDigits, Value(2)));
         }
         }
 
 
-        // k. If value is not 0 or display is not "auto", then
+        // l. If value is not 0 or display is not "auto", then
         if (value != 0.0 || display != DurationFormat::Display::Auto) {
         if (value != 0.0 || display != DurationFormat::Display::Auto) {
-            // i. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
-            auto* number_format = static_cast<NumberFormat*>(MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), js_string(vm, duration_format.locale()), number_format_options)));
+            // i. If style is "2-digit" or "numeric", then
+            if (style == DurationFormat::ValueStyle::TwoDigit || style == DurationFormat::ValueStyle::Numeric) {
+                // 1. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
+                auto* number_format = static_cast<NumberFormat*>(MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), js_string(vm, duration_format.locale()), number_format_options)));
 
 
-            // ii. Let dataLocale be durationFormat.[[DataLocale]].
-            auto const& data_locale = duration_format.data_locale();
+                // 2. Let dataLocale be durationFormat.[[DataLocale]].
+                auto const& data_locale = duration_format.data_locale();
 
 
-            // iii. Let dataLocaleData be %DurationFormat%.[[LocaleData]].[[<dataLocale>]].
+                // 3. Let dataLocaleData be %DurationFormat%.[[LocaleData]].[[<dataLocale>]].
 
 
-            // iv. If style is "2-digit" or "numeric", then
-            if (style == DurationFormat::ValueStyle::TwoDigit || style == DurationFormat::ValueStyle::Numeric) {
-                // 1. Let num be ! FormatNumeric(nf, 𝔽(value)).
+                // 4. Let num be ! FormatNumeric(nf, 𝔽(value)).
                 auto number = format_numeric(vm, *number_format, MathematicalValue(value));
                 auto number = format_numeric(vm, *number_format, MathematicalValue(value));
 
 
-                // 2. Append the new Record { [[Type]]: unit, [[Value]]: num} to the end of result.
+                // 5. Append the new Record { [[Type]]: unit, [[Value]]: num} to the end of result.
                 result.append({ unit, number });
                 result.append({ unit, number });
 
 
-                // 3. If unit is "hours" or "minutes", then
+                // 6. If unit is "hours" or "minutes", then
                 if (unit.is_one_of("hours"sv, "minutes"sv)) {
                 if (unit.is_one_of("hours"sv, "minutes"sv)) {
                     double next_value = 0.0;
                     double next_value = 0.0;
                     DurationFormat::Display next_display;
                     DurationFormat::Display next_display;
@@ -462,27 +452,23 @@ Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationForma
                     }
                     }
                 }
                 }
             }
             }
-            // v. Else,
+            // ii. Else,
             else {
             else {
-                // 1. Let num be ! PartitionNumberPattern(nf, 𝔽(value)).
-                auto number = partition_number_pattern(vm, *number_format, MathematicalValue(value));
-
-                // 2. Let pr be ! Construct(%PluralRules%, « durationFormat.[[Locale]] »).
-                auto* plural_rules = static_cast<PluralRules*>(MUST(construct(vm, *realm.intrinsics().intl_plural_rules_constructor(), js_string(vm, duration_format.locale()))));
+                // 1. Perform ! CreateDataPropertyOrThrow(nfOpts, "style", "unit").
+                MUST(number_format_options->create_data_property_or_throw(vm.names.style, js_string(vm, "unit"sv)));
 
 
-                // 3. Let prv be ! ResolvePlural(pr, 𝔽(value)).
-                auto plurality = resolve_plural(*plural_rules, Value(value));
+                // 2. Perform ! CreateDataPropertyOrThrow(nfOpts, "unit", numberFormatUnit).
+                MUST(number_format_options->create_data_property_or_throw(vm.names.unit, js_string(vm, number_format_unit)));
 
 
-                auto formats = ::Locale::get_unit_formats(data_locale, duration_instances_component.unit_singular, static_cast<::Locale::Style>(style));
-                auto pattern = formats.find_if([&](auto& p) { return p.plurality == plurality; });
-                if (pattern == formats.end())
-                    continue;
+                // 3. Perform ! CreateDataPropertyOrThrow(nfOpts, "unitDisplay", style).
+                auto unicode_style = ::Locale::style_to_string(static_cast<::Locale::Style>(style));
+                MUST(number_format_options->create_data_property_or_throw(vm.names.unitDisplay, js_string(vm, unicode_style)));
 
 
-                // 4. Let template be dataLocaleData.[[formats]].[[<style>]].[[<unit>]].[[<prv>]].
-                auto template_ = convert_number_format_pattern_to_duration_format_template(*pattern);
+                // 4. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
+                auto* number_format = static_cast<NumberFormat*>(MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), js_string(vm, duration_format.locale()), number_format_options)));
 
 
-                // 5. Let parts be ! MakePartsList(template, unit, num).
-                auto parts = make_parts_list(template_, unit, move(number));
+                // 5. Let parts be ! PartitionNumberPattern(nf, 𝔽(value)).
+                auto parts = partition_number_pattern(vm, *number_format, MathematicalValue(value));
 
 
                 // 6. Let concat be an empty String.
                 // 6. Let concat be an empty String.
                 StringBuilder concat;
                 StringBuilder concat;

+ 1 - 1
Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.h

@@ -194,7 +194,7 @@ struct DurationInstanceComponent {
     DurationFormat::Display (DurationFormat::*get_display_slot)() const;
     DurationFormat::Display (DurationFormat::*get_display_slot)() const;
     void (DurationFormat::*set_display_slot)(StringView);
     void (DurationFormat::*set_display_slot)(StringView);
     StringView unit;
     StringView unit;
-    StringView unit_singular;
+    StringView number_format_unit;
     Span<StringView const> values;
     Span<StringView const> values;
     StringView digital_default;
     StringView digital_default;
 };
 };