ICU Messages in React with react-intl (FormatJS)

Implement ICU MessageFormat in React applications using react-intl (FormatJS). Covers FormattedMessage component, useIntl hook, plural/select usage, and best practices.

Framework Integration

Detailed Explanation

Using ICU MessageFormat in React

react-intl (part of the FormatJS suite) is the most popular internationalization library for React applications. It uses ICU MessageFormat as its message syntax.

Setup

import { IntlProvider, FormattedMessage } from 'react-intl';

const messages = {
  en: {
    greeting: 'Hello, {name}!',
    itemCount: '{count, plural, one {# item} other {# items}} in cart',
  },
  ja: {
    greeting: 'こんにちは、{name}!',
    itemCount: 'カートに{count, plural, other {#個の商品}}',
  },
};

function App() {
  const locale = 'en';
  return (
    <IntlProvider locale={locale} messages={messages[locale]}>
      <MyComponent />
    </IntlProvider>
  );
}

FormattedMessage Component

<FormattedMessage
  id="greeting"
  defaultMessage="Hello, {name}!"
  values={{ name: userName }}
/>

useIntl Hook

For programmatic formatting (tooltips, aria-labels, etc.):

import { useIntl } from 'react-intl';

function MyComponent() {
  const intl = useIntl();
  const label = intl.formatMessage(
    { id: 'itemCount', defaultMessage: '{count, plural, one {# item} other {# items}}' },
    { count: items.length }
  );
  return <span aria-label={label}>...</span>;
}

Rich Text with React Elements

react-intl supports React elements as variable values:

<FormattedMessage
  id="tos"
  defaultMessage="I agree to the <link>Terms of Service</link>"
  values={{
    link: (chunks) => <a href="/tos">{chunks}</a>,
  }}
/>

The message file:

I agree to the <link>Terms of Service</link>

Plural and Select

<FormattedMessage
  id="notification"
  defaultMessage="{gender, select, male {He} female {She} other {They}} liked {count, plural, one {your post} other {# of your posts}}."
  values={{ gender: user.gender, count: likeCount }}
/>

Message Extraction

FormatJS provides a CLI tool for extracting messages from source code:

npx formatjs extract 'src/**/*.tsx' --out-file lang/en.json

This scans all FormattedMessage usage and generates a JSON file for translators.

Best Practices

  1. Always provide defaultMessage -- serves as the English source and fallback
  2. Use message IDs like page.section.messageKey for organization
  3. Extract messages into separate JSON files, not inline
  4. Test with pseudo-localization to catch truncation and layout issues
  5. Use the intl.formatMessage hook for non-JSX contexts (titles, ARIA labels)

Use Case

React developers setting up internationalization for the first time or migrating from string concatenation to ICU MessageFormat using the FormatJS / react-intl ecosystem.

Try It — ICU Message Format Tester

Open full tool