Common i18n Patterns in React _ Lingui
Common i18n Patterns in React _ Lingui
This page describes the most common i18n patterns in React. It's a follow-up to the tutorial with
practical examples. See the API reference for detailed information about all components.
Macros
Using jsx macros is the most straightforward way to translate your React components.
Trans handles translations of messages including variables and other React components:
function render() {
return (
<>
<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 ).
In such case you need to use the useLingui() hook with the msg macro.
CAUTION
When you use t macro (and plural , select , selectOrdinal ), it uses a global i18n
instance. While this generally works, there are situations, like in server-side rendering (SSR)
applications, where it may not be the best fit.
For better control and flexibility, it's a good idea to avoid the global i18n instance and instead
use a specific instance tailored to your needs.
function MyComponent() {
// get i18n instance from React Context
const { i18n } = useLingui();
NOTE
All js macros such as t plural , select , selectOrdinal cannot be used on the module
level.
// ❌
Bad! This won't work because the `t` macro is used at the module
level.
// The `t` macro returns a string, and once this string is assigned, it
won't react to locale changes.
const colors = [t`Red`, t`Orange`, t`Yellow`, t`Green`];
// ✅
Good! Every time the function is executed, the `t` macro will be re-
executed as well,
// and the correctly translated color labels will be returned.
function getColors() {
return [t`Red`, t`Orange`, t`Yellow`, t`Green`];
}
A better option would be to use the Lazy Translations pattern described in the following
paragraph.
Lazy Translations
You don't need to declare messages at the same code location where they are displayed. Tag a
string with the msg 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 its id to Trans as its
id prop:
NOTE
Note that we import <Trans> component from @lingui/react , because we want to use the
runtime Trans component here, not the (compile-time) macro.
To render the message descriptor as a string-only translation, pass it to the i18n._() method:
If you need the prop to be displayed as a string-only translation, you can pass a message tagged
with the msg macro:
return (
<div>
<ImageWithCaption caption={_(msg`I'm so happy!`)} />
<ImageWithCaption caption={_(msg`I'm so sad.`)} />
</div>
);
}
A simple way to do this is to create an object that maps the possible values of "status" to message
descriptors (tagged with the msg macro), and render them as needed with deferred translation:
const statusMessages = {
["STATUS_OPEN"]: msg`Open`,
["STATUS_CLOSED"]: msg`Closed`,
["STATUS_CANCELLED"]: msg`Cancelled`,
["STATUS_COMPLETED"]: msg`Completed`,
};
Memoization pitfall
In the following contrived example, we document how a welcome message will or will not be
updated when locale changes.
The documented behavior may not be intuitive at first, but it is expected, because of how useMemo
dependencies work.
To avoid bugs with stale translations, use the _ function returned from useLingui : it is safe to use
with memoization because its reference changes whenever the Lingui context updates. We are open
to accepting solutions to make working with the Lingui context easier.
Keep in mind that useMemo is primarily a performance optimization tool in React. Because of this,
there might be no need to memoize your translations. Additionally, this issue is not present when
using the Trans component which we recommend to use when possible.
import { msg } from "@lingui/macro";
import { i18n } from "@lingui/core";
return <div>{buggyWelcome}</div>;
}
// ❌ Bad! This code won't work either because the reference to i18n does not
change
export function Welcome() {
const { i18n } = useLingui();
return <div>{buggyWelcome}</div>;
}
return <div>{welcome}</div>;
}
// 🤩 Better! `useMemo` consumes the `_` function from the Lingui context
export function Welcome() {
const { _ } = useLingui();