Common i18n patterns in React

Following page describes the most common i18n patterns in React. It’s a follow-up to tutorial with practical examples. See the API reference for detailed information about all components.

Macros

Using jsx macros is the most straightforward way how to translate your React components.

<Trans> handles translations of messages including variables and other React components:

import { Trans } from "@lingui/macro"

<h1><Trans>LinguiJS example</Trans></h1>

<p><Trans>Hello <a href="/profile">{name}</a>.</Trans></p>

You don’t need anything special to use <Trans> inside your app (except of wrapping the root component in <I18nProvider>).

Using ID generated from message

With <Trans>

In the examples above, the content of <Trans> is transformed into message in MessageFormat syntax. By default, this message is used as the message ID. Considering the example above, messages LinguiJS example and Hello <0>{name}</0>. are extracted and used as IDs.

With t

In the following example, message Image caption will be extracted and used as ID.

import { I18n } from "@lingui/react"
import { t } from "@lingui/macro"

export default function ImageWithCaption() {
   return (
      <I18n>
         {({ i18n }) => (
            <img src="..." alt={i18n._(t`Image caption`)} />
         )}
      </I18n>
   )
}

Using custom ID

With <Trans>

If you’re using custom IDs in your project, add id prop to i18n components:

import { Trans } from "@lingui/macro"

<h1><Trans id="msg.header">LinguiJS example</Trans></h1>

<p><Trans id="msg.hello">Hello <a href="/profile">{name}</a>.</Trans></p>

Messages msg.header and msg.hello will be extracted with default values LinguiJS example and Hello <0>{name}</0>..

With t

If you’re using custom IDs in your project, call t with ID as a first argument and then use string templates as usual:

import { I18n } from "@lingui/react"
import { t } from "@lingui/macro"

export default function ImageWithCaption() {
   return (
      <I18n>
         {({ i18n }) => (
            <img src="..." alt={i18n._(t('msg.caption')`Image caption`)} />
         )}
      </I18n>
   )
}

Message msg.caption will be extracted with default value Image caption.

For all other js macros (plural, select, selectOrdinal), pass ID as the first param (in this case, 'msg.caption'):

import { I18n } from "@lingui/react"
import { plural } from "@lingui/macro"

export default function ImageWithCaption({ count }) {
   return (
      <I18n>
         {({ i18n }) => (
            <img src="..." alt={i18n._(plural('msg.caption', {
               value: count,
               one: "# image caption",
               other: "# image captions",
            }))} />
         )}
      </I18n>
   )
}

Element attributes and string-only translations

Sometimes you can’t use <Trans> component, for example when translating element attributes:

<img src="..." alt="Image caption" />

In such case you need to use <I18n> render prop component to access i18n object and t macro to wrap message:

  1. Use withI18n() HOC or <I18n> render prop component from @lingui/react, to access i18n object.

  2. Call i18n._`() to translate message wrapped in JS macros. t is equivalent for <Trans>, plural is equivalent to <Plural>.

// using the withI18n HOC
import { withI18n } from "@lingui/react"
import { t } from "@lingui/macro"

function ImageWithCaption({ i18n }) {
   return <img src="..." alt={i18n._(t`Image caption`)} />
}

export default withI18n(ImageWithCaption)
// using the render prop
import { I18n } from "@lingui/react"
import { t } from "@lingui/macro"

export default function ImageWithCaption() {
   return (
      <I18n>
         {({ i18n }) => (
            <img src="..." alt={i18n._(t`Image caption`)} />
         )}
      </I18n>
   )
}

Translations outside React components

Another common pattern is when you need to access translations (i18n object) outside React components, for example inside redux-saga:

  1. Create your own instance of i18n using setupI18n() form @lingui/core

  2. Pass this instance as i18n prop to <I18nProvider>.

    // App.js
    import { setupI18n } from "@lingui/core"
    import { I18nProvider } from "@lingui/react"
    
    export const i18n = setupI18n()
    
    export default function App() {
       return (
          <I18nProvider i18n={i18n}>
             {/* Our app */}
          </I18nProvider>
       )
    }
    
  3. Whenever you are outside React context (i.e. you can’t access props), you can use this i18n object.

    import { i18n } from "./App.js"
    import { t } from "@lingui/macro"
    
    export function alert() {
       // use i18n as if you were inside a React component
       alert(i18n._(t`...`))
    }
    

Lazy translations

Messages don’t have to be declared at the same code location where they’re displayed. Tag a string with the t macro, and you’ve created a “message descriptor”, which can then be passed around as a variable, and can be displayed as a translated string by passing it to <Trans> as its id prop:

import { t, Trans } from "@lingui/macro"

const favoriteColors = [
   t`Red`,
   t`Orange`,
   t`Yellow`,
   t`Green`,
]

export default function ColorList() {
   return (
      <ul>
         {favoriteColors.map(color => (
            <li><Trans id={color}/></li>
         }
      </ul>
   )
}

Or to render the message descriptor as a string-only translation, just pass it to the I18n._() method as usual:

import { t } from "@lingui/macro"

const favoriteColors = [
   t`Red`,
   t`Orange`,
   t`Yellow`,
   t`Green`,
]

const translatedColorNames = favoriteColors.map(
   color => i18n._(color)
)

Passing messages as props

It’s often convenient to pass messages around as component props, for example as a “label” prop on a button. The easiest way to do this is to pass a <Trans> element as the prop:

import { Trans } from "@lingui/macro"

export default function FancyButton(props) {
   return <button>{props.label}</button>
}

export function LoginLogoutButtons(props) {
   return <div>
      <FancyButton label={<Trans>Log in</Trans>} />
      <FancyButton label={<Trans>Log out</Trans>} />
   </div>
}

If you need the prop to be displayed as a string-only translation, you can pass a message descriptor (tagged with the t macro), and have the component render it as a string using lazy translation:

import { t } from "@lingui/macro"
import { I18n } from "@lingui/react"

export default function ImageWithCaption(props) {
   return (
      <I18n>
         {({ i18n }) => (
            <img src="..." alt={i18n._(props.caption)} />
         )}
      </I18n>
   )
}

export function HappySad(props) {
   return <div>
      <ImageWithCaption
         hoverText={t`I'm so happy!`}
      />
      <ImageWithCaption
         hoverText={t`I'm so sad.`}
      />
   </div>
}

Picking a message based on a variable

Sometimes you need to pick between different messages to display, depending on the value of a variable. For example, imagine you have a numeric “status” code that comes from an API, and you need to display a message representing the current status.

A simple way to do this, is to make an object that maps the possible values of “status” to message descriptors (tagged with the t macro), and render them as needed with lazy translation:

import { Trans } from "@lingui/macro";

const STATUS_OPEN = 1,
      STATUS_CLOSED = 2,
      STATUS_CANCELLED = 4,
      STATUS_COMPLETED = 8

const statusMessages = {
   [STATUS_OPEN]: t`Open`,
   [STATUS_CLOSED]: t`Closed`,
   [STATUS_CANCELLED]: t`Cancelled`,
   [STATUS_COMPLETED]: t`Completed`,
}

export default function StatusDisplay(statusCode) {
   return <div><Trans id={statusMessages[statusCode]} /></div>
}