Skip to content

Commit 99fc94e

Browse files
trflynn89linusg
authored andcommitted
LibJS: Delegate to NumberFormat for DurationFormat unit formatting
This is a normative change in the Intl.DurationFormat proposal. See: tc39/proposal-intl-duration-format@12ba9df
1 parent a5bf320 commit 99fc94e

File tree

2 files changed

+33
-47
lines changed

2 files changed

+33
-47
lines changed

Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,6 @@ ThrowCompletionOr<DurationUnitOptions> get_duration_unit_options(VM& vm, String
299299
return DurationUnitOptions { .style = move(style), .display = display.as_string().string() };
300300
}
301301

302-
// FIXME: LibUnicode currently only exposes unit patterns converted to an ECMA402 NumberFormat-specific format,
303-
// since DurationFormat only needs a tiny subset of it, it's much easier to just convert it to the expected format
304-
// here, but at some point we should split the NumberFormat exporter to export both formats of the data.
305-
static String convert_number_format_pattern_to_duration_format_template(::Locale::NumberFormat const& number_format)
306-
{
307-
auto result = number_format.zero_format.replace("{number}"sv, "{0}"sv, ReplaceMode::FirstOnly);
308-
309-
for (size_t i = 0; i < number_format.identifiers.size(); ++i)
310-
result = result.replace(String::formatted("{{unitIdentifier:{}}}", i), number_format.identifiers[i], ReplaceMode::FirstOnly);
311-
312-
return result;
313-
}
314-
315302
// 1.1.7 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/proposal-intl-duration-format/#sec-partitiondurationformatpattern
316303
Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationFormat const& duration_format, Temporal::DurationRecord const& duration)
317304
{
@@ -339,19 +326,22 @@ Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationForma
339326
// d. Let unit be the Unit value.
340327
auto unit = duration_instances_component.unit;
341328

342-
// e. Let style be durationFormat.[[<styleSlot>]].
329+
// e. Let numberFormatUnit be the NumberFormat Unit value.
330+
auto number_format_unit = duration_instances_component.number_format_unit;
331+
332+
// f. Let style be durationFormat.[[<styleSlot>]].
343333
auto style = (duration_format.*style_slot)();
344334

345-
// f. Let display be durationFormat.[[<displaySlot>]].
335+
// g. Let display be durationFormat.[[<displaySlot>]].
346336
auto display = (duration_format.*display_slot)();
347337

348-
// g. Let value be duration.[[<valueSlot>]].
338+
// h. Let value be duration.[[<valueSlot>]].
349339
auto value = duration.*value_slot;
350340

351-
// h. Let nfOpts be ! OrdinaryObjectCreate(null).
341+
// i. Let nfOpts be ! OrdinaryObjectCreate(null).
352342
auto* number_format_options = Object::create(realm, nullptr);
353343

354-
// i. If unit is "seconds", "milliseconds", or "microseconds", then
344+
// j. If unit is "seconds", "milliseconds", or "microseconds", then
355345
if (unit.is_one_of("seconds"sv, "milliseconds"sv, "microseconds"sv)) {
356346
DurationFormat::ValueStyle next_style;
357347

@@ -400,31 +390,31 @@ Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationForma
400390
}
401391
}
402392

403-
// j. If style is "2-digit", then
393+
// k. If style is "2-digit", then
404394
if (style == DurationFormat::ValueStyle::TwoDigit) {
405395
// i. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2𝔽).
406396
MUST(number_format_options->create_data_property_or_throw(vm.names.minimumIntegerDigits, Value(2)));
407397
}
408398

409-
// k. If value is not 0 or display is not "auto", then
399+
// l. If value is not 0 or display is not "auto", then
410400
if (value != 0.0 || display != DurationFormat::Display::Auto) {
411-
// i. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
412-
auto* number_format = static_cast<NumberFormat*>(MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), js_string(vm, duration_format.locale()), number_format_options)));
401+
// i. If style is "2-digit" or "numeric", then
402+
if (style == DurationFormat::ValueStyle::TwoDigit || style == DurationFormat::ValueStyle::Numeric) {
403+
// 1. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
404+
auto* number_format = static_cast<NumberFormat*>(MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), js_string(vm, duration_format.locale()), number_format_options)));
413405

414-
// ii. Let dataLocale be durationFormat.[[DataLocale]].
415-
auto const& data_locale = duration_format.data_locale();
406+
// 2. Let dataLocale be durationFormat.[[DataLocale]].
407+
auto const& data_locale = duration_format.data_locale();
416408

417-
// iii. Let dataLocaleData be %DurationFormat%.[[LocaleData]].[[<dataLocale>]].
409+
// 3. Let dataLocaleData be %DurationFormat%.[[LocaleData]].[[<dataLocale>]].
418410

419-
// iv. If style is "2-digit" or "numeric", then
420-
if (style == DurationFormat::ValueStyle::TwoDigit || style == DurationFormat::ValueStyle::Numeric) {
421-
// 1. Let num be ! FormatNumeric(nf, 𝔽(value)).
411+
// 4. Let num be ! FormatNumeric(nf, 𝔽(value)).
422412
auto number = format_numeric(vm, *number_format, MathematicalValue(value));
423413

424-
// 2. Append the new Record { [[Type]]: unit, [[Value]]: num} to the end of result.
414+
// 5. Append the new Record { [[Type]]: unit, [[Value]]: num} to the end of result.
425415
result.append({ unit, number });
426416

427-
// 3. If unit is "hours" or "minutes", then
417+
// 6. If unit is "hours" or "minutes", then
428418
if (unit.is_one_of("hours"sv, "minutes"sv)) {
429419
double next_value = 0.0;
430420
DurationFormat::Display next_display;
@@ -462,27 +452,23 @@ Vector<PatternPartition> partition_duration_format_pattern(VM& vm, DurationForma
462452
}
463453
}
464454
}
465-
// v. Else,
455+
// ii. Else,
466456
else {
467-
// 1. Let num be ! PartitionNumberPattern(nf, 𝔽(value)).
468-
auto number = partition_number_pattern(vm, *number_format, MathematicalValue(value));
469-
470-
// 2. Let pr be ! Construct(%PluralRules%, « durationFormat.[[Locale]] »).
471-
auto* plural_rules = static_cast<PluralRules*>(MUST(construct(vm, *realm.intrinsics().intl_plural_rules_constructor(), js_string(vm, duration_format.locale()))));
457+
// 1. Perform ! CreateDataPropertyOrThrow(nfOpts, "style", "unit").
458+
MUST(number_format_options->create_data_property_or_throw(vm.names.style, js_string(vm, "unit"sv)));
472459

473-
// 3. Let prv be ! ResolvePlural(pr, 𝔽(value)).
474-
auto plurality = resolve_plural(*plural_rules, Value(value));
460+
// 2. Perform ! CreateDataPropertyOrThrow(nfOpts, "unit", numberFormatUnit).
461+
MUST(number_format_options->create_data_property_or_throw(vm.names.unit, js_string(vm, number_format_unit)));
475462

476-
auto formats = ::Locale::get_unit_formats(data_locale, duration_instances_component.unit_singular, static_cast<::Locale::Style>(style));
477-
auto pattern = formats.find_if([&](auto& p) { return p.plurality == plurality; });
478-
if (pattern == formats.end())
479-
continue;
463+
// 3. Perform ! CreateDataPropertyOrThrow(nfOpts, "unitDisplay", style).
464+
auto unicode_style = ::Locale::style_to_string(static_cast<::Locale::Style>(style));
465+
MUST(number_format_options->create_data_property_or_throw(vm.names.unitDisplay, js_string(vm, unicode_style)));
480466

481-
// 4. Let template be dataLocaleData.[[formats]].[[<style>]].[[<unit>]].[[<prv>]].
482-
auto template_ = convert_number_format_pattern_to_duration_format_template(*pattern);
467+
// 4. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
468+
auto* number_format = static_cast<NumberFormat*>(MUST(construct(vm, *realm.intrinsics().intl_number_format_constructor(), js_string(vm, duration_format.locale()), number_format_options)));
483469

484-
// 5. Let parts be ! MakePartsList(template, unit, num).
485-
auto parts = make_parts_list(template_, unit, move(number));
470+
// 5. Let parts be ! PartitionNumberPattern(nf, 𝔽(value)).
471+
auto parts = partition_number_pattern(vm, *number_format, MathematicalValue(value));
486472

487473
// 6. Let concat be an empty String.
488474
StringBuilder concat;

Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ struct DurationInstanceComponent {
194194
DurationFormat::Display (DurationFormat::*get_display_slot)() const;
195195
void (DurationFormat::*set_display_slot)(StringView);
196196
StringView unit;
197-
StringView unit_singular;
197+
StringView number_format_unit;
198198
Span<StringView const> values;
199199
StringView digital_default;
200200
};

0 commit comments

Comments
 (0)