Using with ICU format

i18next itself is flexible enough to support multiple existing i18next formats beside its own.

Extend the i18n instance with ICU module

To enable ICU format you will need to include the i18next-icu module into your i18next instance.

import i18n from 'i18next';
import ICU from 'i18next-icu';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { reactI18nextModule } from 'react-i18next';
// import locale-data for needed lngs
import de from 'i18next-icu/locale-data/de';
.use(new ICU({
localeData: de // you also can pass in array of localeData
.use(reactI18nextModule) // if not using I18nextProvider
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false, // not needed for react!!
// react i18next special options (optional)
react: {
bindI18n: 'languageChanged loaded',
bindStore: 'added removed',
nsMode: 'default'
export default i18n;

To dynamically import the needed locale-data have a look here:

Use the ICU format

using t function

import React, { Component } from 'react';
import { translate } from 'react-i18next';
function myComponent({ t }) => {
return <div>{t('icu', { numPersons: 500 })}</div>
export default translate()(myComponent);
// json
"icu": "{numPersons, plural, =0 {no persons} =1 {one person} other {# persons}}",
// result:
<div>500 persons</div>

using the Trans Component

As is including plain ICU syntax inside a JSX node will result in invalid JSX as the ICU format uses curly brackets that are reserved by JSX.

So the default option is to use the Trans Component just with props like:

import { Trans } from 'react-i18next';
const user = 'John Doe';
defaults="We invited <0>{user}</0>."
values={{ user }}
// json
"icu_and_trans": "We invited <0>{user}</0>."
// result
We invited <strong>John Doe</strong>.

While this works the resulting JSX is very verbose - guess we could do better.

using babel macros (Trans, Plural, Select)

Thanks to using kentcdodds/babel-plugin-macros we could use some babel magic to transpile nicer looking jsx to above Trans markup.

Check for setting babel-plugin-macros up.

Using create-react-app? Make sure you are using react-scripts v2 as it includes the macro plugin.

$ # Create a new application
$ npx create-react-app
$ # Upgrade an existing application
$ yarn upgrade [email protected]
import { Trans } from 'react-i18next/icu.macro';
const user = 'John Doe';
<Trans i18nKey="icu_and_trans">
We invited <strong>{user}</strong>.

The macro will add the needed import for Trans Component and generate the correct Trans component for you.

The correct string for translations will be shown in the browser console output as a missing string (if set debug: true on i18next init) or submitted via saveMissing (have saveMissing set true and a i18next backend supporting saving missing keys).

If linting or other code analysis tools are complaining or failing because of the invalid JSX syntax, you can use the defaults prop instead of putting your message as a child, and it will be parsed and updated to the correct format.

import { Trans } from 'react-i18next/icu.macro';
const user = 'John Doe';
defaults="We invited <strong>{user}</strong>."

This will be converted by the macro into:

import { Trans } from 'react-i18next';
const user = 'John Doe';
defaults="We invited <0>{user}</0>."

The defaults parsing supports the @babel/react preset, so any expressions that require more complex parsing may not work.

More samples:

// basic interpolation
<Trans>Welcome, { name }!</Trans>
// interpolation and components
<Trans>Welcome, <strong>{ name }</strong>!</Trans>
<Trans defaults="Welcome, <strong>{ name }</strong>" />
// number formatting
<Trans>Trainers: { trainersCount, number }</Trans>
<Trans>Trainers: <strong>{ trainersCount, number }</strong>!</Trans>
<Trans defaults="Trainers: <strong>{ trainersCount, number }</strong>!" />
// date formatting
<Trans>Caught on { catchDate, date, short }</Trans>
<Trans>Caught on <strong>{ catchDate, date, short }</strong>!</Trans>
<Trans defaults="Caught on <strong>{ catchDate, date, short }</strong>!" />
<Trans>You have <Link to="/inbox">{ unread, number } messages</Link></Trans>
<Trans defaults="You have <Link to='/inbox'>{ unread, number } messages</Link>" />


There is no way to directly add the needed ICU format inside a JSX child - so we had to add another component that gets transpiled to needed Trans component:

import { Select } from 'react-i18next/icu.macro';
// simple select
i18nKey="optionalKey" // optional key
male="He avoids bugs."
female="She avoids bugs."
other="They avoid bugs."
import { Select } from 'react-i18next/icu.macro';
// select with inner components
i18nKey="optionalKey" // optional key
male={<Trans><strong>He</strong> avoids bugs.</Trans>}
female={<Trans><strong>She</strong> avoids bugs.</Trans>}
other={<Trans><strong>They</strong> avoid bugs.</Trans>}


import { Plural } from 'react-i18next/icu.macro';
// simple plural
i18nKey="optionalKey" // optional key
$0="There is no item."
one="There is # item."
other="There are # items."
import { Plural } from 'react-i18next/icu.macro';
// plural with inner components
i18nKey="optionalKey" // optional key
$0={<Trans>There is <strong>no</strong> item.</Trans>}
one={<Trans>There is <strong>#</strong> item.</Trans>}
other={<Trans>There are <strong>#</strong> items.</Trans>}


import { SelectOrdinal } from 'react-i18next/icu.macro';
// simple SelectOrdinal
one="You are #st in line"
two="You are #nd in line"
few="You are #rd in line"
other="You are #th in line"
import { SelectOrdinal } from 'react-i18next/icu.macro';
// SelectOrdinal with inner components
one={<Trans>You are <strong>#st in line</strong></Trans>}
two={<Trans>You are <strong>#nd in line</strong></Trans>}
few={<Trans>You are <strong>#rd in line</strong></Trans>}
other={<Trans>You are <strong>#th in line</strong></Trans>}
$7={<Trans>You are the lucky <strong>#th in line</strong></Trans>}

The needed plural forms can be looked up in the official unicode cldr table:

In addition to the plural forms you can specify results for given number values like show above:

0="show if zero"

in ICU it would be =0 {show if zero} but = is not allowed to be leading char in attributes so we replaced it with $