Missed the action at the 2018 Chrome Dev Summit? Catch up with our playlist on the Google Chrome Developers channel on YouTube. Watch now.

The Intl.ListFormat API

Modern web applications often use lists consisting of dynamic data. For example, a photo viewer app might display something like:

This photo includes Ada, Edith, and Grace.

A text-based game might have a different kind of list:

Choose your superpower: invisibility, psychokinesis, or empathy.

Since each language has different list formatting conventions and words, implementing a localized list formatter is non-trivial. Not only does this require a list of all the words (such as “and” or “or” in the above examples) for each language you want to support — in addition you need to encode the exact formatting conventions for all those languages! The Unicode CLDR provides this data, but to use it in JavaScript, it has to be embedded and shipped alongside the other library code. This unfortunately increases the bundle size for such libraries, which negatively impacts load times, parse/compile cost, and memory consumption.

The brand new Intl.ListFormat API shifts that burden to the JavaScript engine, which can ship the locale data and make it directly available to JavaScript developers. Intl.ListFormat enables localized formatting of lists without sacrificing performance.

Usage examples

The following example shows how to create a list formatter for conjunctions using the English language:

const lf = new Intl.ListFormat('en');
lf.format(['Frank']);
// → 'Frank'
lf.format(['Frank', 'Christine']);
// → 'Frank and Christine'
lf.format(['Frank', 'Christine', 'Flora']);
// → 'Frank, Christine, and Flora'
lf.format(['Frank', 'Christine', 'Flora', 'Harrison']);
// → 'Frank, Christine, Flora, and Harrison'

Disjunctions (“or” in English) are supported as well through the optional options parameter:

const lf = new Intl.ListFormat('en', { type: 'disjunction' });
lf.format(['Frank']);
// → 'Frank'
lf.format(['Frank', 'Christine']);
// → 'Frank or Christine'
lf.format(['Frank', 'Christine', 'Flora']);
// → 'Frank, Christine, or Flora'
lf.format(['Frank', 'Christine', 'Flora', 'Harrison']);
// → 'Frank, Christine, Flora, or Harrison'

Here’s an example of using a different language (Chinese, with language code zh):

const lf = new Intl.ListFormat('zh');
lf.format(['永鋒']);
// → '永鋒'
lf.format(['永鋒', '新宇']);
// → '永鋒和新宇'
lf.format(['永鋒', '新宇', '芳遠']);
// → '永鋒、新宇和芳遠'
lf.format(['永鋒', '新宇', '芳遠', '澤遠']);
// → '永鋒、新宇、芳遠和澤遠'

The options parameter enables more advanced usage. Here’s an overview of the various options and their combinations, and how they correspond to the list patterns defined by UTS#35:

Type Options Description Examples
standard (or no type) {} (default) A typical “and” list for arbitrary placeholders 'January, February, and March'
or { type: 'disjunction' } A typical “or” list for arbitrary placeholders 'January, February, or March'
unit { type: 'unit' } A list suitable for wide units '3 feet, 7 inches'
unit-short { type: 'unit', style: 'short' } A list suitable for short units '3 ft, 7 in'
unit-narrow { type: 'unit', style: 'narrow' } A list suitable for narrow units, where space on the screen is very limited '3′ 7″'

Note that in many languages (such as English) there may not be a difference among many of these lists. In others, the spacing, the length or presence of a conjunction, and the separators may change.

Conclusion

Intl.ListFormat is available by default in V8 v7.2 and Chrome 72. As this API becomes more widely available, you’ll find libraries dropping their dependency on hardcoded CLDR databases in favor of the native list formatting functionality, thereby improving load-time performance, parse- and compile-time performance, run-time performance, and memory usage.

Questions about this API? Comments about this article? Feel free to let us know on Twitter via @mathias!

Feedback

Was this page helpful?

rss_feed Subscribe to our RSS or Atom feed and get the latest updates in your favorite feed reader!

Send feedback about...