Trans Component
While
<Trans>
gives you a lot of power by letting you interpolate or translate complex React elements, the truth is: in most cases you don't even need it.
As long you have no React/HTML nodes integrated into a cohesive sentence
(text formatting like
strong
,
em
, link components, maybe others),
you won't need it
- most of the times you will be using the good old
t
function.
It does ONLY interpolation. It does not rerender on language change or load any translations needed. Check
useTranslation
hook
or
withTranslation
HOC
for those cases.
import
React
from
'react'
;
import
{
Trans
,
useTranslation
}
from
'react-i18next'
function
MyComponent
()
{
const
{
t
}
=
useTranslation
(
'myNamespace'
);
return
<
Trans t
=
{
t
}
>
Hello World
</
Trans
>
;
}
So you learned there is no need to use the Trans component everywhere (the plain
t
function will just do fine in most cases).
This component enables you to nest any React content to be translated as one cohesive string. It supports both plural and interpolation. The
<Trans>
component will automatically use the most relevant
t()
function (from the
context instance
or the global instance), unless overridden via the
i18n
or
t
props.
Let's say you want to create following HTML output:
Before:
Your untranslated React code would have looked something like:
function
MyComponent
(
{
person
,
messages
}
)
{
const
{
name
}
=
person
;
const
count
=
messages
.
length
;
return
(
<>
Hello
<
strong title
=
"This is your name"
>
{
name
}
</
strong
>
,
you have
{
count
}
unread
message
(
s
).
<
Link to
=
"/msgs"
>
Go to messages
</
Link
>
.
</>
);
}
After:
With the Trans component just change it to:
import
{
Trans
}
from
'react-i18next'
;
function
MyComponent
(
{
person
,
messages
}
)
{
const
{
name
}
=
person
;
const
count
=
messages
.
length
;
return
(
<
Trans i18nKey
=
"userMessagesUnread"
count
=
{
count
}
>
Hello
<
strong title
=
{
t
(
'nameTitle'
)}
>
{{
name
}}
</
strong
>
,
you have
{{
count
}}
unread message
.
<
Link to
=
"/msgs"
>
Go to messages
</
Link
>
.
</
Trans
>
);
}
Your en.json (translation strings) will look like:
"nameTitle"
:
"This is your name"
,
"userMessagesUnread_one"
:
"Hello <1>{{name}}</1>, you have {{count}} unread message. <5>Go to message</5>."
,
"userMessagesUnread_other"
:
"Hello <1>{{name}}</1>, you have {{count}} unread messages. <5>Go to messages</5>."
,
saveMissing
will send a valid
defaultValue
based on the component children.
Also, The
i18nKey
is optional, in case you already use text as translation keys.
<
Trans
i18nKey
=
"myKey"
// optional -> fallbacks to defaults if not provided
defaults
=
"hello <italic>beautiful</italic> <bold>{{what}}</bold>"
// optional defaultValue
values
=
{{
what
:
'world'
}}
components
=
{{
italic
:
<
i
/>
,
bold
:
<
strong
/>
}}
/>
This format is useful if you want to interpolate the same node multiple times. Another advantage is the simpler named tags, which avoids the trouble with index guessing - however, this can also be achieved with
transSupportBasicHtmlNodes
, see the next section.
Existing self-closing HTML tag names are reserved keys and won't work. Examples:
link: <Link />
,
img: <img src="" />
,
media: <img src="" />
Make sure you also adapt your translation resources to include the
named tags
(
<italic>
) instead of the
indexed tags
(
<0>
)!
There are two options that allow you to have basic HTML tags inside your translations, instead of numeric indexes. However, this only works for elements without additional attributes (like
className
), having none or a single text children.
Examples of elements that will be readable in translation strings:
-
<br/>
-
<strong>bold</strong>
-
<p>some paragraph</p>
Examples that will be converted to indexed nodes:
-
<i className="icon-gear" />
: no attributes allowed -
<strong title="something">{{name}}</strong>
: only text nodes allowed -
<b>bold <i>italic</i></b>
: no nested elements, even simple ones
<
Trans
i18nKey
=
"
welcomeUser
"
>
Hello
<
strong
>
{{
name
}}
</
strong
>
.
<
Link
to
=
"
/inbox
"
>
See my profile
</
Link
>
</
Trans
>
// JSON -> "welcomeUser": "Hello <strong>{{name}}</strong>. <1>See my profile</1>"
<
Trans
i18nKey
=
"
multiline
"
>
Some newlines
<
br
/>
would be
<
br
/>
fine
</
Trans
>
// JSON -> "multiline": "Some newlines <br/> would be <br/> fine"
Here is what can be configured in
i18next.options.react
that affect this behaviour:
Option
|
Default
|
Description
|
---|---|---|
transSupportBasicHtmlNodes
|
true
|
Enables keeping the name of simple nodes (e.g.
<br/>
) in translations instead of indexed keys
|
transKeepBasicHtmlNodesFor
|
['br', 'strong', 'i', 'p']
|
Which nodes are allowed to be kept in translations during
defaultValue
generation of
<Trans>
.
|
transWrapTextNodes
(v11.10.0)
|
''
|
Wrap text nodes in a user-specified element. e.g. set it to
span
. By default, text nodes are not wrapped. Can be used to work around a well-known Google Translate issue with React apps. See
facebook/react#11538
.
|
You can pass in variables to get interpolated into the translation string by using objects containing those key:values.
const
person
=
{
name
:
'Henry'
,
age
:
21
};
const
{
name
,
age
}
=
person
;
<
Trans
>
Hello
{{
name
}}.
// <- = {{ "name": name }}
</
Trans
>
// Translation string: "Hello {{name}}"
<
Trans
>
Hello
{{
firstname
:
person
.
name
}}.
</
Trans
>
// Translation string: "Hello {{firstname}}"
You will need to pass the
count
prop:
const
messages
=
[
'message one'
,
'message two'
];
<
Trans
i18nKey
=
"
newMessages
"
count
=
{
messages
.
length
}
>
You have
{{
count
:
messages
.
length
}}
messages
.
</
Trans
>
// Translation strings:
// "newMessages": "You have one message."
// "newMessages_plural": "You have {{count}} messages."
You can still use
Array.map()
to turn dynamic content into nodes, using an extra option on a wrapping element:
<
Trans
i18nKey
=
"
list_map
"
>
My dogs are named
:
<
ul
i18nIsDynamicList
>
{[
'rupert'
,
'max'
].
map
(
dog
=>
(
<
li
>
{
dog
}
</
li
>
))}
</
ul
>
</
Trans
>
// JSON -> "list_map": "My dogs are named: <1></1>"
Setting
i18nIsDynamicList
on the parent element will assert the
nodeToString
function creating the string for
saveMissing
will not contain children.
Some use cases, such as the ICU format, might be simpler by just passing content as props:
<
Trans
i18nKey
=
"myKey"
// optional -> fallbacks to defaults if not provided
defaults
=
"hello <0>{{what}}</0>"
// optional defaultValue
values
=
{{
what
:
'world'
}}
components
=
{[
<
strong
>
univers
</
strong
>
]}
/>
<0>
-> 0 is the index of the component in the components array
E.g. this format is needed when using
ICU as translation format
as it is not possible to have the needed syntax as children (invalid jsx).
Guessing replacement tags
(<0></0>)
of your component is rather difficult. There are four options to get those translations directly generated by i18next:
-
1.use React Developer Tools to inspect the
<Trans>
component instance and look at theprops.children
array for array index of the tag in question. -
2.use
debug = true
ini18next.init()
options and watch your console for the missing key output -
3.use the saveMissing feature of i18next to get those translations pushed to your backend or handled by a custom function.
-
4.understand how those numbers get generated from child index:
Sample JSX:
<
Trans i18nKey
=
"userMessagesUnread"
count
=
{
count
}
>
Hello
<
strong title
=
{
t
(
'nameTitle'
)}
>
{{
name
}}
</
strong
>
,
you have
{{
count
}}
unread message
.
<
Link to
=
"/msgs"
>
Go to messages
</
Link
>
.
</
Trans
>
Resulting translation string:
"Hello <1>{{name}}</1>, you have {{count}} unread message. <5>Go to message</5>."
The complete the node tree
:
Trans
.
children
=
[
'Hello '
,
// 0: only a string
{
children
:
[{
name
:
'Jan'
}]
},
// 1: <strong> with child object for interpolation
', you have '
,
// 2: only a string
{
count
:
10
},
// 3: plain object for interpolation
' unread messages. '
,
// 4: only a string
{
children
:
[
'Go to messages'
]
},
// 5: <Link> with a string child
'.'
// 6: yep, you guessed: another string
]
Rules:
-
child is a string: nothing to wrap; just take the string
-
child is an object: nothing to do; it's used for interpolation
-
child is an element: wrap it's children in
<x></x>
wherex
is the index of that element's position in thechildren
list; handle its children with the same rules (startingelement.children
index at 0 again)
All properties are optional, although you'll need to use
i18nKey
if you're not using natural language keys (text-based).
name
|
type (default)
|
description
|
i18nKey
|
string (undefined)
|
If you prefer to use text as keys you can omit this, and the translation will be used as key. Can contain the namespace by prepending it in the form
'ns:key'
(depending on
i18next.options.nsSeparator
)
But this is not recommended when used in combination with natural language keys, better use the dedicated ns parameter:
<Trans i18nKey="myKey" ns="myNS"></Trans>
|
ns
|
string (undefined)
|
Namespace to use. May also be embedded in
i18nKey
but not recommended when used in combination with natural language keys, see above.
|
t
|
function (undefined)
|
t
function to use instead of the global
i18next.t()
or the
t()
function provided by the nearest
provider
.
|
count
|
integer (undefined)
|
Numeric value for pluralizable strings
|
context
|
string (undefined)
|
|
tOptions
|
object (undefined)
|
Extra options to pass to
t()
(e.g.
context
,
postProcessor
, ...)
|
parent
|
node (undefined)
|
A component to wrap the content into (can be globally set on
i18next.init
).
Required for React < v16
|
i18n
|
object (undefined)
|
i18next instance to use if not provided by context
|
defaults
|
string (undefined)
|
Use this instead of using the children as default translation value (useful for ICU)
|
values
|
object (undefined)
|
Interpolation values if not provided in children
|
components
|
array[nodes] (undefined)
|
Components to interpolate based on index of tag
|
shouldUnescape
|
boolean (false)
|
HTML encoded tags like:
< & >
should be unescaped, to become:
< & >
|
i18next
.
init
({
// ...
react
:
{
// ...
hashTransKey
:
function
(
defaultValue
)
{
// return a key based on defaultValue or if you prefer to just remind you should set a key return false and throw an error
},
defaultTransParent
:
'div'
,
// a valid react element - required before react 16
transEmptyNodeValue
:
''
,
// what to return for empty Trans
transSupportBasicHtmlNodes
:
true
,
// allow <br/> and simple html elements in translations
transKeepBasicHtmlNodesFor
:
[
'br'
,
'strong'
,
'i'
],
// don't convert to <1></1> if simple react elements
transWrapTextNodes
:
''
,
// Wrap text nodes in a user-specified element.
// i.e. set it to 'span'. By default, text nodes are not wrapped.
// Can be used to work around a well-known Google Translate issue with React apps. See: https://github.com/facebook/react/issues/11538
// (v11.10.0)
}
});
Please be aware if you are using
React 15 or below
, you are required to set the
defaultTransParent
option, or pass a
parent
via props.
Are you having trouble when your website is ran through Google Translate?
Google Translate seems to manipulate the DOM and makes React quite unhappy!