Skip to main content

Components

React Intl has a set of React components that provide a declarative way to setup an i18n context and format dates, numbers, and strings for display in a web UI. The components render React elements by building on React Intl's imperative API.

Why Components?

Beyond providing an idiomatic-React way of integrating internationalization into a React app, and the <Formatted*> components have benefits over always using the imperative API directly:

  • Render React elements that seamlessly compose with other React components.
  • Support rich-text string/message formatting in <FormattedMessage>.
  • Implement advanced features like <FormattedRelativeTime>'s updating over time.
  • Provide TypeScript type definitions.

IntlProvider

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.

caution

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

This component is used to setup the i18n context for a tree. Usually, this component will wrap an app's root component so that the entire app will be within the configured i18n context. The following are the i18n configuration props that can be set:

interface IntlConfig {
locale: string
formats: CustomFormats
messages: Record<string, string> | Record<string, MessageFormatElement[]>
defaultLocale: string
defaultFormats: CustomFormats
timeZone?: string
textComponent?: React.ComponentType | keyof React.ReactHTML
wrapRichTextChunksInFragment?: boolean
defaultRichTextElements?: Record<string, FormatXMLElementFn<React.ReactNode>>
onError(err: string): void
}

locale, formats, and messages

The user's current locale and what the app should be rendered in. While defaultLocale and defaultFormats are for fallbacks or during development and represent the app's default. Notice how there is no defaultMessages, that's because each Message Descriptor provides a defaultMessage.

defaultLocale and defaultFormats

Default locale & formats for when a message is not translated (missing from messages). defaultLocale should be the locale that defaultMessages are declared in so that a sentence is coherent in a single locale. Without defaultLocale and/or if it's set incorrectly, you might run into scenario where a sentence is in English but embedded date/time is in Spanish.

textComponent

Provides a way to configure the default wrapper for React Intl's <Formatted*> components. If not specified, <React.Fragment> is used. Before V3, span was used instead; check the migration guide for more info.

onError

Allows the user to provide a custom error handler. By default, error messages are logged using console.error if NODE_ENV is not set to production.

onWarn

Allows the user to provide a custom warning handler. By default, warning messages are logged using console.warning if NODE_ENV is not set to production.

wrapRichTextChunksInFragment

When formatting rich text message, the output we produced is of type Array<string | React.ReactElement>, which will trigger key error. This wraps the output in a single React.Fragment to suppress that.

defaultRichTextElements

A map of tag to rich text formatting function. This is meant to provide a centralized way to format common tags such as <b>, <p>... or enforcing certain Design System in the codebase (e.g standardized <a> or <button>...). See https://github.com/formatjs/formatjs/issues/1752 for more context.

These configuration props are combined with the <IntlProvider>'s component-specific props:

Props:

props: IntlConfig &
{
children: ReactNode,
}

Finally, child elements must be supplied to <IntlProvider>.

Example:

const App = ({importantDate}) => (
<div>
<FormattedDate
value={importantDate}
year="numeric"
month="long"
day="numeric"
weekday="long"
/>
</div>
)

ReactDOM.render(
<IntlProvider locale={navigator.language}>
<App importantDate={new Date(1459913574887)} />
</IntlProvider>,
document.getElementById('container')
)

Assuming navigator.language is "fr":

<div>mardi 5 avril 2016</div>

RawIntlProvider

This is the underlying React.Context.Provider object that IntlProvider use. It can be used in conjunction with createIntl:

import {createIntl, createIntlCache, RawIntlProvider} from 'react-intl'

// This is optional but highly recommended
// since it prevents memory leak
const cache = createIntlCache()

const intl = createIntl({
locale: 'fr-FR',
messages: {}
}, cache)

// Pass it to IntlProvider
<RawIntlProvider value={intl}>{foo}</RawIntlProvider>

FormattedDate

This component uses the formatDate and Intl.DateTimeFormat APIs and has props that correspond to the DateTimeFormatOptions specified above.

Props:

props: Intl.DateTimeFormatOptions &
{
value: any,
format: string,
children: (formattedDate: string) => ReactElement,
}

By default <FormattedDate> will render the formatted date into a <React.Fragment>. If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child.

Example:

Live Editor
<FormattedDate value={new Date(1459832991883)} />
Result

Example with Options:

Live Editor
<FormattedDate
value={new Date(1459832991883)}
year="numeric"
month="long"
day="2-digit"
/>
Result

FormattedDateParts

browser support

This requires Intl.DateTimeFormat.prototype.formatToParts which is not available in IE11. Please use our polyfill if you plan to support IE11.

This component provides more customization to FormattedDate by allowing children function to have access to underlying parts of the formatted date. The available parts are listed here

Props:

props: Intl.DateTimeFormatOptions &
{
value: any,
format: string,
children: (parts: Intl.DateTimeFormatPart[]) => ReactElement,
}
Live Editor
<FormattedDateParts
value={new Date(1459832991883)}
year="numeric"
month="long"
day="2-digit"
>
{parts => (
<>
<b>{parts[0].value}</b>
{parts[1].value}
<small>{parts[2].value}</small>
</>
)}
</FormattedDateParts>
Result

FormattedTime

This component uses the formatTime and Intl.DateTimeFormat APIs and has props that correspond to the DateTimeFormatOptions specified above, with the following defaults:

{
hour: 'numeric',
minute: 'numeric',
}

Props:

props: DateTimeFormatOptions &
{
value: any,
format: string,
children: (formattedDate: string) => ReactElement,
}

By default <FormattedTime> will render the formatted time into a React.Fragment. If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child.

Example:

Live Editor
<FormattedTime value={new Date(1459832991883)} />
Result

FormattedTimeParts

browser support

This requires Intl.DateTimeFormat.prototype.formatToParts which is not available in IE11. Please use our polyfill if you plan to support IE11.

This component provides more customization to FormattedTime by allowing children function to have access to underlying parts of the formatted date. The available parts are listed here

Props:

props: Intl.DateTimeFormatOptions &
{
value: any,
format: string,
children: (parts: Intl.DateTimeFormatPart[]) => ReactElement,
}
Live Editor
<FormattedTimeParts value={new Date(1459832991883)}>
{parts => (
<>
<b>{parts[0].value}</b>
{parts[1].value}
<small>{parts[2].value}</small>
</>
)}
</FormattedTimeParts>
Result

FormattedDateTimeRange

browser support

This requires stage-3 API Intl.RelativeTimeFormat.prototype.formatRange which has limited browser support. Please use our polyfill if you plan to support them.

This component uses the formatDateTimeRange and Intl.DateTimeFormat APIs and has props that correspond to the DateTimeFormatOptions specified above

Props:

props: DateTimeFormatOptions &
{
from: number | Date,
to: number | Date,
children: (formattedDate: string) => ReactElement,
}

By default <FormattedDateTimeRange> will render the formatted time into a React.Fragment. If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child.

Example:

Live Editor
<FormattedDateTimeRange
from={new Date('2020-1-1')}
to={new Date('2020-1-15')}
/>
Result

FormattedRelativeTime

browser support

This requires Intl.RelativeTimeFormat which has limited browser support. Please use our polyfill if you plan to support them.

This component uses the formatRelativeTime API and has props that correspond to the following relative formatting options:

type RelativeTimeFormatOptions = {
numeric?: 'always' | 'auto'
style?: 'long' | 'short' | 'narrow'
}

Prop Types:

props: RelativeTimeFormatOptions &
{
value: number,
unit: Unit,
format: string,
updateIntervalInSeconds: number,
children: (formattedDate: string) => ReactElement,
}

By default <FormattedRelativeTime> will render the formatted relative time into a React.Fragment. If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child.

Example:

Live Editor
<FormattedRelativeTime value={0} numeric="auto" updateIntervalInSeconds={1} />
Result
maximum interval

You can adjust the maximum interval that the component will re-render by setting the updateIntervalInSeconds. A falsy value will turn off auto-updating. The updating is smart and will schedule the next update for the next interesting moment.

An interesting moment is defined as the next non-fractional value for that unit. For example:

Live Editor
<FormattedRelativeTime value={-50} updateIntervalInSeconds={1} />
Result

This will initially renders 59 seconds ago, after 1 second, will render 1 minute ago, and will not re-render until a full minute goes by, it'll render 2 minutes ago. It will not try to render 1.2 minutes ago.

limitation

updateIntervalInSeconds cannot be enabled for unit longer than hour (so not for day, week, quarter, year). This is primarily because it doesn't make sense to schedule a timeout in days, and the number of ms in a day is larger than the max timeout that setTimeout accepts.

FormattedNumber

This component uses the formatNumber and Intl.NumberFormat APIs and has props that correspond to Intl.NumberFormatOptions.

Props:

props: NumberFormatOptions &
{
value: number,
format: string,
children: (formattedNumber: string) => ReactElement,
}

By default <FormattedNumber> will render the formatted number into a React.Fragment. If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child.

Example:

Live Editor
<FormattedNumber value={1000} />
Result

Example Formatting Currency Values

Live Editor
<FormattedNumber value={1000} style="currency" currency="USD" />
Result

Formatting Number using unit

Currently this is part of ES2020 NumberFormat. We've provided a polyfill here and react-intl types allow users to pass in a sanctioned unit. For example:

Live Editor
<FormattedNumber
value={1000}
style="unit"
unit="kilobyte"
unitDisplay="narrow"
/>
Result
Live Editor
<FormattedNumber
value={1000}
unit="fahrenheit"
unitDisplay="long"
style="unit"
/>
Result

FormattedNumberParts

browser support

This requires Intl.NumberFormat.prototype.formatToParts which is not available in IE11. Please use our polyfill if you plan to support IE11.

This component provides more customization to FormattedNumber by allowing children function to have access to underlying parts of the formatted number. The available parts are listed here.

Props:

props: NumberFormatOptions &
{
value: number,
format: string,
children: (parts: Intl.NumberFormatPart[]) => ReactElement,
}

Example:

Live Editor
<FormattedNumberParts value={1000}>
{parts => (
<>
<b>{parts[0].value}</b>
{parts[1].value}
<small>{parts[2].value}</small>
</>
)}
</FormattedNumberParts>
Result

FormattedPlural

This component uses the formatPlural API and Intl.PluralRules has props that correspond to Intl.PluralRulesOptions.

Props:

props: PluralFormatOptions &
{
value: any,

other: ReactElement,
zero: ReactElement,
one: ReactElement,
two: ReactElement,
few: ReactElement,
many: ReactElement,

children: (formattedPlural: ReactElement) => ReactElement,
}

By default <FormattedPlural> will select a plural category (zero, one, two, few, many, or other) and render the corresponding React element into a React.Fragment. If you need to customize rendering, you can either wrap it with another React element (recommended), or pass a function as the child.

Example:

Live Editor
<FormattedPlural value={10} one="message" other="messages" />
Result

FormattedList

browser support

This requires Intl.ListFormat which has limited browser support. Please use our polyfill if you plan to support them.

This component uses formatList API and Intl.ListFormat. Its props corresponds to Intl.ListFormatOptions.

Props:

props: ListFormatOptions &
{
children: (chunksOrString: string | React.ReactElement[]) => ReactElement,
}

Example:

When the locale is en:

Live Editor
<FormattedList type="conjunction" value={['Me', 'myself', 'I']} />
Result
Live Editor
<FormattedList type="conjunction" value={['Me', <b>myself</b>, 'I']} />
Result

FormattedListParts

browser support

This requires Intl.ListFormat which has limited browser support. Please use our polyfill if you plan to support them.

This component uses formatListToParts API and Intl.ListFormat. Its props corresponds to Intl.ListFormatOptions.

Props:

props: ListFormatOptions &
{
children: (chunks: Array<React.ReactElement | string>) => ReactElement,
}

Example:

When the locale is en:

Live Editor
<FormattedListParts type="conjunction" value={['Me', 'myself', 'I']}>
{parts => (
<>
<b>{parts[0].value}</b>
{parts[1].value}
<small>{parts[2].value}</small>
{parts[3].value}
<small>{parts[4].value}</small>
</>
)}
</FormattedListParts>
Result

FormattedDisplayName

browser support

This requires Intl.DisplayNames which has limited browser support. Please use our polyfill if you plan to support them.

This component uses formatDisplayName and Intl.DisplayNames has props that correspond to DisplayNameOptions. You might need a polyfill.

Props:

props: FormatDisplayNameOptions &
{
value: string | number | Record<string, unknown>,
}

Example:

When the locale is en:

Live Editor
<FormattedDisplayName type="language" value="zh-Hans-SG" />
Result
Live Editor
<FormattedDisplayName type="currency" value="JPY" />
Result

FormattedMessage

This component uses the formatMessage API and has props that correspond to a Message Descriptor.

Props:

props: MessageDescriptor &
{
values: object,
tagName: string,
children: (chunks: ReactElement) => ReactElement,
}

Message Syntax

String/Message formatting is a paramount feature of React Intl and it builds on ICU Message Formatting by using the ICU Message Syntax. This message syntax allows for simple to complex messages to be defined, translated, and then formatted at runtime.

Simple Message:

Hello, {name}

Complex Message:

Hello, {name}, you have {itemCount, plural,
=0 {no items}
one {# item}
other {# items}
}.

See: The Message Syntax Guide.

Message Descriptor

React Intl has a Message Descriptor concept which is used to define your app's default messages/strings. <FormattedMessage> have props which correspond to a Message Descriptor. The Message Descriptors work very well for providing the data necessary for having the strings/messages translated, and they contain the following properties:

  • id: A unique, stable identifier for the message
  • description: Context for the translator about how it's used in the UI
  • defaultMessage: The default message (probably in English)
type MessageDescriptor = {
id?: string
defaultMessage?: string
description?: string
}
compile message descriptors

The babel-plugin-formatjs and @formatjs/ts-transformer packages can be used to compile Message Descriptors defined in JavaScript source files into AST for performance.

Message Formatting Fallbacks

The message formatting APIs go the extra mile to provide fallbacks for the common situations where formatting fails; at the very least a non-empty string should always be returned. Here's the message formatting fallback algorithm:

  1. Lookup and format the translated message at id, passed to <IntlProvider>.
  2. Fallback to formatting the defaultMessage.
  3. Fallback to translated message at id's source.
  4. Fallback to defaultMessage source.
  5. Fallback to the literal message id.

Usage

By default <FormattedMessage> will render the formatted string into a <React.Fragment>. If you need to customize rendering, you can either wrap it with another React element (recommended), specify a different tagName (e.g., 'div'), or pass a function as the child.

Example:

Live Editor
<FormattedMessage
id="app.greeting"
description="Greeting to welcome the user to the app"
defaultMessage="Hello, {name}!"
values={{
name: 'Eric',
}}
/>
Result

Example: function as the child

Live Editor
<FormattedMessage id="title">{txt => <h1>{txt}</h1>}</FormattedMessage>
Result
simple message

Messages can be simple strings without placeholders, and that's the most common type of message. This case is highly-optimized, but still has the benefits of the fallback procedure.

Rich Text Formatting

<FormattedMessage> also supports rich-text formatting by specifying a XML tag in the message & resolving that tag in the values prop. Here's an example:

Live Editor
<FormattedMessage
id="app.greeting"
description="Greeting to welcome the user to the app"
defaultMessage="Hello, <b>Eric</b> {icon}"
values={{
b: chunks => <b>{chunks}</b>,
icon: <svg />,
}}
/>
Result

By allowing embedding XML tag we want to make sure contextual information is not lost when you need to style part of the string. In a more complicated example like:

Live Editor
<FormattedMessage
id="foo"
defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta>"
values={{
a: chunks => (
<a
class="external_link"
target="_blank"
href="https://www.example.com/shoe"
>
{chunks}
</a>
),
cta: chunks => <strong class="important">{chunks}</strong>,
}}
/>
Result

Function as the child

Since rich text formatting allows embedding ReactElement, in function as the child scenario, the function will receive the formatted message chunks as a single parameter.

Live Editor
<FormattedMessage
id="foo"
defaultMessage="To buy a shoe, <a>visit our website</a> and <cta>buy a shoe</cta>"
values={{
a: chunks => (
<a
class="external_link"
target="_blank"
href="https://www.example.com/shoe"
>
{chunks}
</a>
),
cta: chunks => <strong class="important">{chunks}</strong>,
}}
>
{chunks => <h2>{chunks}</h2>}
</FormattedMessage>
Result

All the rich text gets translated together which yields higher quality output. This brings feature-parity with other translation libs as well, such as fluent by Mozilla (using overlays concept).

Extending this also allows users to potentially utilizing other rich text format, like Markdown.