Formatting Language-Sensitive Lists in JavaScript with ListFormat

John Au-Yeung - Jan 30 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

With the Intl.ListFormat constructor, we can format language-sensitive lists with ease. It lets us set the locale in which to format a list. Also, it lets us set options for formatting lists such as the type of list or style of the list. To use it, we can create a new ListFormat object with the Intl.ListFormat constructor.

The constructor takes up to two arguments. The first argument is a string of the locale that you want to format the list for. The second argument takes an object with the options for formatting and styling the list. An example use of the Intl.ListFormat constructor is:

const arr = ['bus', 'car', 'train'];
const formatter = new Intl.ListFormat('en', {
  style: 'long',
  type: 'conjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

If we run the code above, we will see bus, car, and train logged from the console.log statement. The Intl.ListFormat constructor creates a formatter object that has the format method to convert an array into a list according to the locale and formatting options that we set.

In the example above, we set the locale to en for English, we set the style property to long, which formats an array of strings into something like A, B, and C or A, B, or C. The type property specifies the kind of list we want to format the list into. Conjunction means that we format a list into A, B, and C.

The arguments of the constructor are the locales that you want to format the list into. It can be a string or an array of strings containing the locale of the list you want to format it into. The locale string or strings should be a BCP 47 language tag. The locales argument is optional. An abridged list of BCP-47 language tags includes:

ar — Arabic

bg — Bulgarian

ca — Catalan

zh-Hans — Chinese, Han (Simplified variant)

cs — Czech

da — Danish

de — German

el — Modern Greek (1453 and later)

en — English

es — Spanish

fi — Finnish

fr — French

he — Hebrew

hu — Hungarian

is — Icelandic

it — Italian

ja — Japanese

ko — Korean

nl — Dutch

no — Norwegian

pl — Polish

pt — Portuguese

rm — Romansh

ro — Romanian

ru — Russian

hr — Croatian

sk — Slovak

sq — Albanian

sv — Swedish

th — Thai

tr — Turkish

ur — Urdu

id — Indonesian
Enter fullscreen mode Exit fullscreen mode

The second argument for the constructor is an object that lets us set the options for how to format the list’s string. There are three properties for this object: localeMatcher, type, and style. The localeMatcher option specifies the locale-matching algorithm to use. The possible values are lookup and best fit.

The lookup algorithm searches for the locale until it finds the one that fits the character set of the strings that are being compared.

best fit finds the locale that is at least as, but possibly more, suitable than the lookup algorithm.

The type property can take on two possible values: conjunction, disjunction, or unit. conjunction means that the list is joined with an and, as in A, B, and C. This is the default option. disnjunction means the list is joined with an or, as in A, B, or C.

unit stands for a list of values with units.

The style property specifies the length of the formatted message. There are two possible values for this property. It can either be long (e.g., A, B, and C), short (e.g., A, B, C), or narrow (e.g., A B C). When style is short or narrow, unit is the only allowed value for this option.

For example, we can use it to format a list into a string that is joined with an and at the end. We can write the following to do so:

const arr = ['bus', 'car', 'bicycle'];
const formatter = new Intl.ListFormat('en', {
  style: 'long',
  type: 'conjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

If we log the formattedList constant like we did above, we get bus, car, and bicycle. We set the en locale to format the string for the English locale, with style long and as a conjunction, which means the list will be joined with an and at the end. If we want to get an or-based list, we can change the type property to a disjunction, as in the following code:

const arr = ['bus', 'car', 'bicycle'];
const formatter = new Intl.ListFormat('en', {
  style: 'long',
  type: 'disjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

If we run the code above, then we get bus, car, or bicycle logged in the console.log statement above.

We can convert it to a shorter list by using the short or narrow option for the style property. For example, we can write:

const arr = ['bus', 'car', 'bicycle'];
const formatter = new Intl.ListFormat('en', {
  style: 'short',
  type: 'conjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

Then we get bus, car, & bicycle in the console.log output when we run the code above. The short and disjunction combination is the same as the long and disjunction combination. If we write:

const arr = ['bus', 'car', 'bicycle'];
const formatter = new Intl.ListFormat('en', {
  style: 'short',
  type: 'disjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

Then we get bus, car, or bicycle. The narrow option would make it even shorter. For example, if we put:

const arr = ['bus', 'car', 'bicycle'];
const formatter = new Intl.ListFormat('en', {
  style: 'narrow',
  type: 'conjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

Then we get bus, car, bicycle logged in the console.log when we run the code above.

This also works for non-English locales. For example, if we want to format a list of Chinese strings into a list, we can write the following code:

const arr = ['日', '月', '星'];
const formatter = new Intl.ListFormat('zh-hant', {
  style: 'narrow',
  type: 'conjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

Then we get ‘日、月和星’, which means sun, moon, and stars. If we switch the style option to long or short, we would get the same thing because in Chinese there’s only one way to write a conjunction, unlike in English. disjunction also works with Chinese. For instance, if we have:

const arr = ['日', '月', '星'];
const formatter = new Intl.ListFormat('zh-hant', {
  style: 'long',
  type: 'disjunction'
});
const formattedList = formatter.format(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

Then we get ‘日、月或星’ which means sun, moon, or stars. If we switch the style option to long or short, as with Chinese conjunctions, we would get the same thing because in Chinese there’s only one way to write a disjunction, unlike in English.

formatToParts() Method

In addition to the format method, the Intl.ListFormat instance also has the formatToParts method, which formats an array into a conjunction or disjunction string and then returns it as an array of the parts of the formatted string.

For example, if we want to return an array of the parts of the formatted English string for a list, then we can write the following code:

const arr = ['bus', 'car', 'bicycle'];
const formatter = new Intl.ListFormat('en', {
  style: 'long',
  type: 'conjunction'
});
const formattedList = formatter.formatToParts(arr);
console.log(formattedList);
Enter fullscreen mode Exit fullscreen mode

Then we get:

[
  {
    "type": "element",
    "value": "bus"
  },
  {
    "type": "literal",
    "value": ", "
  },
  {
    "type": "element",
    "value": "car"
  },
  {
    "type": "literal",
    "value": ", and "
  },
  {
    "type": "element",
    "value": "bicycle"
  }
]
Enter fullscreen mode Exit fullscreen mode

from the console.log statement. These are the parts of the formatted string that we get with the format method, but broken apart into individual entries. This method is handy if we only want some parts of the formatted string.

With the Intl.ListFormat constructor, formatting language-sensitive lists is easy. The constructor takes a locale string or an array of locale strings as the first argument and an object with some options for the second argument. We can convert an array into a string that has the list formatted into conjunction or disjunction with the Intl.ListFormat instance’s format method, which takes a locale string and options for the length style of the formatted string and whether it’s a conjunction, disjunction, or unit string. It also has a formatToParts method to convert it to a formatted list and then break up the parts into an array.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .