I18n questions · ICU message format
Add a type and an optional style to the argument: {n, number}, {n, number, percent}, {d, date, long}, {t, time, short}. For anything the named styles do not cover, use a skeleton, which starts with ::, for example {price, number, ::currency/EUR} or {d, date, ::yMMMd}. The message formats the raw value with the conventions of its own locale.
The named styles of ICU's MessageFormat are integer, currency and percent for numbers, and short, medium, long and full for dates and times. With the values 1234567.891, 0.25 and 9.5 and the date 9 October 2026, 15:04:
Formatted for en-US these give 1,234,567.891, 1,234,568, 25%, €9.50, 9.50, October 9, 2026, 3:04 PM and Oct 9, 2026. Formatted for de-DE the same messages give 1.234.567,891, 1.234.568, 25 %, 9,50 €, 9,50, 9. Oktober 2026, 15:04 and 9. Okt. 2026. Nothing in the message changes between the two; only the locale does.
Skeletons are locale-independent requests. A number skeleton combines stems such as currency/EUR, .00 (exactly two fraction digits), precision-integer, percent and compact-short (1234567 becomes 1.2M); the number skeleton reference lists them. A date skeleton names the fields you want, yMMMd for year, abbreviated month and day, and the locale supplies the order and punctuation (Oct 9, 2026, 9. Okt. 2026, 2026年10月9日); j asks for the locale's preferred hour cycle, so {when, time, ::jm} prints 3:04 PM in English and 15:04 in German. Number skeletons in messages require ICU 62 and date and time skeletons ICU 64; FormatJS supports number skeletons and a subset of the date and time skeletons.
Pass raw values. Give the message a number and a date or timestamp and let it do the formatting. A string pre-formatted in code freezes one locale's conventions and stops the translator from changing the style, for example from long to short where the sentence is tight.
Pitfalls:
currency without a code takes the currency from the locale's region; with a region-less locale such as en ICU prints the placeholder ¤9.50. Prefer ::currency/EUR with an explicit ISO code.percent style multiplies by 100 (0.25 gives 25%), the skeleton stem percent alone does not (::percent gives 0.25%); use ::percent scale/100 for a fraction.The ICU message editor shows the output per language.
Published Oct 9, 2026 · Markdown version