Simple pluralization via Intl.PluralRules

[2019-12-29] dev, javascript, intl
(Ad, please don’t block)

In this blog post, we’ll explore a very simple way to handle reporting of numbers of items that respects grammatical number (in English: singular and plural).

Avoiding pluralization  

By prefixing the items to be counted, we can avoid pluralization:

function report(fileCount) {
  return `Changed files: ${fileCount}`;
}
assert.equal(
  report(0), 'Changed files: 0');
assert.equal(
  report(1), 'Changed files: 1');
assert.equal(
  report(12), 'Changed files: 12');

On the upside, this looks reasonable and may even be quicker to read, depending on how one’s brain works. But it can’t always be used and not everyone likes this style.

Pluralization via Intl.PluralRules  

The JavaScript internationalization API can be accessed via the global variable Intl. One of its services is .PluralRules(), which determines the grammatical number associated with a numeric number:

const pluralRules = new Intl.PluralRules('en-US');
assert.equal(
  pluralRules.select(0), 'other');
assert.equal(
  pluralRules.select(1), 'one');
assert.equal(
  pluralRules.select(12), 'other');

In English, this API uses 'one' for singular and 'other' for plural. This functionality is easy to implement for English. The main value of the API is that it also works for other languages.

A simple tool function for pluralization  

For sophisticated apps, you’ll want to use translation files. For small and less important apps, the following tool function will do:

const pluralRules = new Intl.PluralRules('en-US');

function pluralize(count, singular, plural) {
  const grammaticalNumber = pluralRules.select(count);
  switch (grammaticalNumber) {
    case 'one':
      return count + ' ' + singular;
    case 'other':
      return count + ' ' + plural;
    default:
      throw new Error('Unknown: '+grammaticalNumber);
  }
}

pluralize() is used like this:

function report(fileCount) {
  return `${pluralize(fileCount, 'file was', 'files were')} changed.`;
}
assert.equal(
  report(0), `0 files were changed.`);
assert.equal(
  report(1), `1 file was changed.`);
assert.equal(
  report(12), `12 files were changed.`);

Further reading and source of this blog post