Skip to content

ICU4X: unit categories ECMA-402 needs

Generated from docs/engines/icu4x-units.md when the site was built at 7aa23e2.

A write-up for the ICU4X project (icu_experimental 0.7, icu_provider_source 2.4), from niso-intl’s Intl.NumberFormat with style: 'unit', which today prints the unit identifier because ICU4X has no data for most of the units ECMA-402 allows.

  • icu_experimental::measure::category defines MeasureUnitCategory and five categories: Area, Duration, Length, Mass and Volume.
  • icu_experimental::dimension::units::categorized_formatter::CategorizedFormatter<C> formats a value in a unit of one category, with try_new_core, try_new_extended and try_new_outlier constructors (and their _unstable forms) over the matching data markers.
  • dimension::provider::units::categorized_display_names defines the markers UnitsNames{Area,Duration,Length,Mass,Volume}{Core,Extended,Outlier}V1, and icu_provider_source’s units/categorized_display_name.rs registers exactly those fifteen with impl_units_display_names_provider!.

The source side is already category-agnostic: get_display_name_payload splits the marker attribute into width and unit (short-meter) and finds the unit in any category of CLDR’s units.json. What limits ICU4X to five categories is the list of markers, the category types and the datagen registrations.

ECMA-402’s sanctioned single units (IsSanctionedSingleUnitIdentifier) are acre, bit, byte, celsius, centimeter, day, degree, fahrenheit, fluid-ounce, foot, gallon, gigabit, gigabyte, gram, hectare, hour, inch, kilobit, kilobyte, kilogram, kilometer, liter, megabit, megabyte, meter, microsecond, mile, mile-scandinavian, milliliter, millimeter, millisecond, minute, month, nanosecond, ounce, percent, petabyte, pound, second, stone, terabit, terabyte, week, yard and year. Any two of them joined by “-per-” are allowed too (kilometer-per-hour, megabyte-per-second).

Missing from ICU4X, by CLDR category:

CLDR category Units ECMA-402 uses
digital bit, byte, kilobit, kilobyte, megabit, megabyte, gigabit, gigabyte, terabit, terabyte, petabyte
temperature celsius, fahrenheit
angle degree
concentr percent
speed kilometer-per-hour, meter-per-second, mile-per-hour (CLDR has these as simple units)
consumption liter-per-kilometer, mile-per-gallon (likewise)
  1. Add Digital, Temperature, Angle, Concentr, Speed and Consumption categories: a MeasureUnitCategory type each, Core, Extended and Outlier markers in categorized_display_names, and their impl_units_display_names_provider! lines in icu_provider_source. No new source parsing is needed.
  2. Format compound “-per-” units that CLDR has no precomputed pattern for. CLDR gives each unit an optional perUnitPattern (“{0} per hour”) and each locale a per compound pattern (“{0}/{1}”). UTS #35 part 6 (“Compound Units”) says to use the numerator’s pattern with the denominator’s perUnitPattern where it has one, and otherwise to place the denominator’s singular display name into the compound per pattern. This needs the per patterns as data and a formatter that takes a numerator and a denominator MeasureUnit.
  3. Optionally, a formatter not bound to a category type, taking any MeasureUnit at run time. A JS engine reads the unit from a string, so it has to dispatch over every category by hand today.

With (1) every sanctioned single unit formats; with (2) every compound ECMA-402 allows does.