Code Notes

🔢Intl.PluralRules

The standards-based way to pick the right plural form, instead of hand-rolling count === 1 ? 'item' : 'items'. English only has two plural forms, but many languages have more — Polish has three, Arabic has six — and Intl.PluralRules knows the rules for all of them.

select(n) returns a plural category: one of zero, one, two, few, many, or other. You map those categories to your strings.

const rules = new Intl.PluralRules('en-GB')

rules.select(0) // 'other'
rules.select(1) // 'one'
rules.select(2) // 'other'

A pluralize helper

const pluralize = (count, singular, plural) => {
  const rules = new Intl.PluralRules('en-GB')
  const word = rules.select(count) === 'one' ? singular : plural
  return `${count} ${word}`
}

pluralize(1, 'note', 'notes') // '1 note'
pluralize(7, 'note', 'notes') // '7 notes'

For more than two forms (or more languages), map categories explicitly:

const rules = new Intl.PluralRules('pl-PL')

const words = {
  one: 'plik', // 1 file
  few: 'pliki', // 2–4 files
  many: 'plików', // 5+ files
}

const formatFiles = (count) => `${count} ${words[rules.select(count)]}`

formatFiles(1) // '1 plik'
formatFiles(3) // '3 pliki'
formatFiles(5) // '5 plików'

Ordinals

Pass { type: 'ordinal' } for 1st/2nd/3rd/4th-style suffixes — the default is 'cardinal':

const ordinals = new Intl.PluralRules('en-GB', { type: 'ordinal' })

const suffixes = {
  one: 'st',
  two: 'nd',
  few: 'rd',
  other: 'th',
}

const formatOrdinal = (n) => `${n}${suffixes[ordinals.select(n)]}`

formatOrdinal(1) // '1st'
formatOrdinal(2) // '2nd'
formatOrdinal(3) // '3rd'
formatOrdinal(11) // '11th' — knows 11 isn't '11st'
formatOrdinal(21) // '21st'

That 11 vs 21 case is exactly the sort of thing you get wrong doing it by hand.

Ranges

selectRange(start, end) (ES2023) picks the category for a range:

new Intl.PluralRules('en-GB').selectRange(1, 3) // 'other' → '1–3 items'

Support is universal — every modern browser and Node for years. If you’re formatting the number itself as well, reach for Intl.NumberFormat, and for “2 days ago”-style strings there’s Intl.RelativeTimeFormat, which uses these same plural rules under the hood.