FormatJS
42

Ship in42 languages

locale

FormatJS is a set of JavaScript libraries for internationalization, built on ICU MessageFormat, Unicode CLDR and the ECMA-402 Intl APIs.

Show messageon
lang/en.jsonIntl.PluralRules('en').select(42) → other
{
  "hero.ship": "Ship in",
  "hero.count": "{count, plural, =0 {no languages} one {# language} other {# languages}}"
}

In Arabic, 3 is few

CLDR gives Arabic six plural categories, English two and Japanese one. FormatJS selects the branch with Intl.PluralRules, so every translation says the number the way its own grammar does.

countlocale: ar
3
  • zero
  • one
  • two
  • few
  • many
  • other

3 رسائل جديدة

One message, three scripts

The Rosetta Stone carries a single decree from 196 BC in hieroglyphic, Demotic and Greek, so that priests, officials and Greek readers all got the same message. A FormatJS catalog does the same job for every locale you ship: one ID, one meaning, many translations.

Close-up of the Greek inscription carved into the dark granodiorite of the Rosetta Stone
The Greek text, the part scholars could already read.
The front face of the Rosetta Stone with hieroglyphic text at the top, Demotic in the middle and Greek at the bottom
The Rosetta Stone, British Museum. Hieroglyphic at the top, Demotic in the middle, Greek below.

From component to catalog

First, declare messages where they render.

defineMessages keeps the English default, a note for translators and a stable ID next to the component that uses it.

Then extract them with one command.

formatjs extract reads your source and writes a catalog your translation tool can open. The CLI ships native binaries for macOS, Linux and Windows.

Finally, compile and ship each locale.

formatjs compile --ast pre-parses every translation, so the browser formats messages without loading the parser.

Inbox.tsxTerminalcompiled-lang/fr.json
import {defineMessages, FormattedMessage} from 'react-intl'

const messages = defineMessages({
  unread: {
    defaultMessage:
      '{count, plural, one {# new message} other {# new messages}}',
    description: 'Inbox header, count of unread mail',
  },
})

export function InboxHeader({count}) {
  return (
    <h2>
      <FormattedMessage {...messages.unread} values={{count}} />
    </h2>
  )
}

Pick your stack.
The libraries follow.

Read the docs

In production at

  • Yahoo
  • Dropbox
  • Tinder
  • Ethereum
  • Mozilla
  • Coinbase

Start with

Copies npm i react-intl to your clipboard. The installation guide takes it from there.