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 react-scripts@2
import { Trans } from'react-i18next/icu.macro';constuser='John Doe';<Transi18nKey="icu_and_trans"> We invited <strong>{user}</strong>.</Trans>
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';constuser='John Doe';<Transi18nKey="icu_and_trans_defaults"defaults="We invited <strong>{user}</strong>."/>
This will be converted by the macro into:
import { Trans } from'react-i18next';constuser='John Doe';<Transi18nKey="icu_and_trans_defaults"values={{user}}defaults="We invited <0>{user}</0>."components={[<strong>{user}</strong>]}/>
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>" />
Tagged Template for ICU
To support complex interpolations, react-i18next provides additional imports from the icu.macro. These provide a way to represent translations closer to the ICU messageformat syntax, but in a manner that is compatible with React and strictly typed in typescript.
For example, to format a number:
import { Trans } from"react-i18next/icu.macro";constnum=1;<Transi18nKey="number"> Incremented {num, number} times</Trans>
the above syntax, although valid javascript, will error when using a linting tool like eslint. Instead, we can do this:
import { Trans, number } from"react-i18next/icu.macro";constnum=1;<Transi18nKey="number"> Incremented {number`${num}`} times</Trans>
This results in the translation string Incremented {num, number} times
Supported interpolators are number, date, time, select, plural, and selectOrdinal.
More complex skeletons can also be represented:
import { Trans, number } from"react-i18next/icu.macro";constawesomePercentage=100;<Transi18nKey="number"> It's awesome {number`${awesomePercentage}, ::percent`} of the time</Trans>
This results in the translation string It's awesome {awesomePercentage, number, ::percent} of the time.
Complex interpolations with plural/select/selectOrdinal
The plural and select and selectOrdinal interpolations support more advanced syntax. For instance, it is possible to interpolate both React elements and other interpolations:
import { Trans, plural, number } from"react-i18next/icu.macro";constawesomePercentage=100;<Transi18nKey="number"> {plural`${awesomePercentage}, =0 { It's ${<i>never</i>} awesome } =100 { It is ${<b>ALWAYS</b>} awesome! } other { It's awesome {number`${awesomePercentage}, ::percent`} of the time }`}</Trans>
This will result in the translation string {awesomePercentage, plural, =0 { It's <0>never</0> awesome } =100 { It is <1>ALWAYS</1> awesome! } =100 { It's awesome {awesomePercentage, number, ::percent} of the time }}
It possible to nest any interpolated type, including nested plural, select, or selectOrdinal.
Typescript support for interpolated template strings
The number, plural, and selectOrdinal functions will error if a non-number typed variable is interpolated.
import { Trans, number } from"react-i18next/icu.macro";// type error below - awesomePercentage must be a numberconstawesomePercentage="100";<Transi18nKey="number"> It's awesome {number`${awesomePercentage}, ::percent`} of the time</Trans>
The date and time functions will error if a non-Date object is interpolated.
import { Trans, date } from"react-i18next/icu.macro";// type error below - awesomePercentage must be a numberconstnotADate="100";<Transi18nKey="number"> What time is it? it's {date`${notADate}`} o'clock</Trans>
Finally, the select function will error if a non-string is interpolated.
import { Trans, select } from"react-i18next/icu.macro";// type error below - awesomePercentage must be a numberconstnotAString=100;<Transi18nKey="number"> {select`${notAString} oops { you have to pass in a string } other { oh well }`}</Trans>
Alternative syntax for select and plural
It is also possible to display select and plural and selectOrdinal using Elements Select, Plural and SelectOrdinal. All of them have full type safety in typescript.
Select
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 { Plural } from'react-i18next/icu.macro';// simple plural<Plurali18nKey="optionalKey"// optional keycount={itemsCount}$0="There is no item."one="There is # item."other="There are # items."/>
import { Plural } from'react-i18next/icu.macro';// plural with inner components<Plurali18nKey="optionalKey"// optional keycount={itemsCount3}$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>}/>
SelectOrdinal
import { SelectOrdinal } from'react-i18next/icu.macro';// simple SelectOrdinal<SelectOrdinali18nKey="optionalKey"count={position}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<SelectOrdinali18nKey="optionalKey"count={position}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>}/>