Skip to main content

Overview

npm Version

Welcome to React Intl's docs! This is the place to find React Intl's docs. Feel free to open a pull request and contribute to the docs to make them better.

Runtime Requirements

We support IE11 & 2 most recent versions of Edge, Chrome, Firefox & Safari.

React Intl relies on these Intl APIs:

If you need to support older browsers, we recommend you do the following:

  1. If you're supporting browsers that do not have Intl, include this polyfill in your build.

  2. Polyfill Intl.NumberFormat with @formatjs/intl-numberformat.

  3. Polyfill Intl.DateTimeFormat with @formatjs/intl-datetimeformat

  4. If you're supporting browsers that do not have Intl.PluralRules (e.g IE11 & Safari 12-), include this polyfill in your build.

  5. If you're supporting browsers that do not have Intl.RelativeTimeFormat (e.g IE11, Edge, Safari 12-), include this polyfill in your build along with individual CLDR data for each locale you support.

  6. If you need Intl.DisplayNames, include this polyfill in your build along with individual CLDR data for each locale you support.

Node.js

full-icu

Starting with Node.js 13.0.0 full-icu is supported by default.

If using React Intl in an earlier version of Node.js, your node binary has to either:

OR

If your node version is missing any of the Intl APIs above, you'd have to polyfill them accordingly.

React Native

If you're using react-intl in React Native, make sure your runtime has built-in Intl support (similar to JSC International variant). See these issues for more details:

React Native on iOS

If you cannot use the Intl variant of JSC (e.g on iOS), follow the instructions in Runtime Requirements to polyfill those APIs accordingly.

The react-intl Package

Install the react-intl npm package via npm:

npm i -S react-intl

The react-intl npm package distributes the following modules (links from unpkg):

  • CommonJS: unbundled dependencies, "main" in package.json, warnings in dev.
  • ES6: unbundled dependencies, "module" in package.json, warnings in dev.

Module Bundlers

We've made React Intl work well with module bundlers like: Browserify, Webpack, or Rollup which can be used to bundle React Intl for the browser:

  • The "browser" field in package.json is specified so that only basic English locale data is included when bundling. This way when using the "main" module in Node all locale data is loaded, but ignored when bundled for the browser.

  • An ES6 version of React Intl is provided as "jsnext:main" and "module" in package.json and can be used with Rollup.

  • Development-time warnings are wrapped with process.env.NODE_ENV !== 'production', this allows you to specify NODE_ENV when bundling and minifying to have these code blocks removed.

The React Intl Module

Whether you use the ES6, CommonJS, or UMD version of React Intl, they all provide the same named exports:

react

When using the UMD version of React Intl without a module system, it will expect react to exist on the global variable: React, and put the above named exports on the global variable: ReactIntl.

Creating an I18n Context

Now with React Intl and its locale data loaded an i18n context can be created for your React app.

React Intl uses the provider pattern to scope an i18n context to a tree of components. This allows configuration like the current locale and set of translated strings/messages to be provided at the root of a component tree and made available to the <Formatted*> components. This is the same concept as what Flux frameworks like Redux use to provide access to a store within a component tree.

All apps using React Intl must use the <IntlProvider> component.

The most common usage is to wrap your root React component with <IntlProvider> and configure it with the user's current locale and the corresponding translated strings/messages:

ReactDOM.render(
<IntlProvider locale={usersLocale} messages={translationsForUsersLocale}>
<App />
</IntlProvider>,
document.getElementById('container')
)

See: The <IntlProvider> docs for more details.

Formatting Data

React Intl has two ways to format data, through React components and its API. The components provide an idiomatic-React way of integrating internationalization into a React app, and the <Formatted*> components have benefits over always using the imperative API directly. The API should be used when your React component needs to format data to a string value where a React element is not suitable; e.g., a title or aria attribute, or for side-effect in componentDidMount.

React Intl's imperative API is accessed via injectIntl, a High-Order Component (HOC) factory. It will wrap the passed-in React component with another React component which provides the imperative formatting API into the wrapped component via its props. (This is similar to the connect-to-stores pattern found in many Flux implementations.)

Here's an example using <IntlProvider>, <Formatted*> components, and the imperative API to setup an i18n context and format data:

import React from 'react';
import ReactDOM from 'react-dom';
import {IntlProvider, FormattedRelative, useIntl} from 'react-intl';

const MS_IN_DAY = 1e3 * 3600 * 24

const PostDate = ({date}) => {
const intl = useIntl()
return (
<span title={intl.formatDate(date)}>
<FormattedRelativeTime value={(Date.now() - date)/MS_IN_DAY} unit="day"/>
</span>
)
});

const App = ({post}) => (
<div>
<h1>{post.title}</h1>
<p>
<PostDate date={post.date} />
</p>
<div>{post.body}</div>
</div>
);

ReactDOM.render(
<IntlProvider locale={navigator.language}>
<App
post={{
title: 'Hello, World!',
date: new Date(1459913574887),
body: 'Amazing content.',
}}
/>
</IntlProvider>,
document.getElementById('container')
);

Assuming navigator.language is "en-us":

<div>
<h1>Hello, World!</h1>
<p><span title="4/5/2016">yesterday</span></p>
<div>Amazing content.</div>
</div>

See: The API docs and Component docs for more details.

ESM Build

react-intl and its underlying libraries (@formatjs/icu-messageformat-parser, intl-messageformat, @formatjs/intl-relativetimeformat) export ESM artifacts. This means you should configure your build toolchain to transpile those libraries.

Jest

Add transformIgnorePatterns to always include those libraries, e.g:

{
transformIgnorePatterns: [
'/node_modules/(?!intl-messageformat|@formatjs/icu-messageformat-parser).+\\.js$',
],
}

webpack

If you're using babel-loader, or ts-loader, you can do 1 of the following:

  1. Add those libraries in include:
{
include: [
path.join(__dirname, 'node_modules/react-intl'),
path.join(__dirname, 'node_modules/intl-messageformat'),
path.join(__dirname, 'node_modules/@formatjs/icu-messageformat-parser'),
]
}

OR

  1. Add those libraries in exclude:
exclude: /node_modules\/(?!react-intl|intl-messageformat|@formatjs\/icu-messageformat-parser)/,

Core Concepts

  • Formatters (Date, Number, Message, Relative)
  • Provider and Injector
  • API and Components
  • Message Descriptor
  • Message Syntax
  • Defining default messages for extraction
  • Custom, named formats

Example Apps

There are several runnable example apps in this Git repo. These are a great way to see React Intl's core concepts in action in simplified applications.

API Reference

There are a few API layers that React Intl provides and is built on. When using React Intl you'll be interacting with Intl built-ins, React Intl's API, and its React components:

TypeScript Usage

react-intl is written in TypeScript, thus having 1st-class TS support.

In order to use react-intl in TypeScript, make sure your compilerOptions's lib config include ["esnext.intl", "es2017.intl", "es2018.intl"].

Typing message IDs and locale

By default, the type for the id prop of <FormattedMessage> and formatMessage is string. However, you can set a more restrictive type to get autocomplete and error checking. In order to do this, override the following global namespace with the union type of all of your message IDs. You can do this by including the following somewhere in your code:

declare global {
namespace FormatjsIntl {
interface Message {
ids: keyof typeof messages
}
}
}

Where messages is the object you would normally pass to <IntlProvider>, and would look something like:

const messages = {
greeting: 'Hello',
planet: 'World',
// ...
}

You can also override the following global to use a custom type for locale

declare global {
namespace FormatjsIntl {
interface IntlConfig {
locale: 'en' | 'fr'
}
}
}

Advanced Usage

Our Advanced Usage has further guides for production setup in environments where performance is important.

Supported Tooling

Message extraction

We've built @formatjs/cli that helps you extract messages from a list of files. It uses babel-plugin-formatjs under the hood and should be able to extract messages if you're declaring using 1 of the mechanisms below:

import {defineMessages} from 'react-intl'

defineMessages({
foo: {
id: 'foo',
defaultMessage: 'foo',
description: 'bar',
},
})
import {FormattedMessage} from 'react-intl'
;<FormattedMessage id="foo" defaultMessage="foo" description="bar" />
function Comp(props) {
const {intl} = props
return intl.formatMessage({
// The whole `intl.formatMessage` is required so we can extract
id: 'foo',
defaultMessage: 'foo',
description: 'bar',
})
}

ESLint Plugin

We've also built eslint-plugin-formatjs that helps enforcing specific rules on your messages if your translation vendor has restrictions.