37

I am using react, i18next and react-i18next. I would like to have some translatable text with HTML link in the middle of the text which is interpolated in react, something like this:

This is my text with <a href="{{link}}">a beautiful link</a> in the middle of the text

The solution below works, but the problem is that I need to interpolate the link in react so it can't be hard-coded in label files:

"my-label": "This is my text with <a href=\"http://google.com\">a beautiful link</a> in the middle of the text"

[...]

<Interpolate i18nKey="my-label" useDangerouslySetInnerHTML />

It seems like this is much better:

"my-label": "This is my text with {{link}} in the middle of the text",
"link" "a beautiful link"

[...]

const { url } = props;
const link = <a href={url}>{t('link')}</a>

<Interpolate i18nKey="my-label" link={link} />

Could be the solution, however the app is translated into many languages and a quality of translations really matters so I prefer to have the whole text in one line for translators (this is important especially for languages which have cases).

Is there any way how to get working something like this (or is there any way how to solve it completely differently)?

"my-label": "This is my text with <a href=\"{{link}}\">a beautiful link</a> in the middle of the text"

[...]

const { url } = props;

<Interpolate i18nKey="my-label" useDangerouslySetInnerHTML link={url} />
Knut Holm
  • 3,988
  • 4
  • 32
  • 54

4 Answers4

35

With react-i18next v4.4.0 we introduced a new component Trans:

<Trans i18nKey="optionalKey">See the <Link to="/more">description</Link> below.</Trans>

The json would be: See the <1>description</1> below.

or even more complex:

<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>

The new feature is documented here: https://react.i18next.com/latest/trans-component

uncledru
  • 143
  • 1
  • 9
jamuhl
  • 4,352
  • 2
  • 25
  • 31
  • If you are having problems with missingKey errors it's likely a namespace problem. Details are here https://github.com/i18next/react-i18next/issues/867 – Shawn Jul 18 '19 at 17:50
  • Answer should be updated to show the t function being passed as a prop to the Trans component. ie – Shawn Jul 18 '19 at 17:52
  • Can you have conditional logic among the children of the Trans component? – Paul Razvan Berg Nov 30 '19 at 23:45
  • 15
    Thanks for your answer. I might be misunderstanding, but does this mean that the text inside Trans needs to be kept in sync with the JSON? If so, it does not seem very convenient, as it is no longer serving as an immutable key. – Danyal Aytekin Jul 23 '20 at 22:33
  • It seems that these texts do not need to be synchronised. I was able to use `XYZ` (with XYZ really!) as children of `Trans`, and it worked! In the JSON, I had the actual string (e.g. `This is a text with <1>a link1> inside`) – v.nivuahc Aug 05 '22 at 12:26
7

This is the common problem of react-intl and react-i18next - both libs have very limited support of inline components and rich-text formatting inside translations (I've already described it here with more details).

If you're still at the beginning of your project, you might want to consider different i18n library - js-lingui (disclaimer: I'm the author). It's the first (and so far the only) library with full support for inline components.

You simply write:

<Trans>See the <Link to="/more">description</Link> below.</Trans>

and your translators will work with message See the <0>description</0> below.

The only price is you need to use extra babel plugin, which makes it possible.

Tomáš Ehrlich
  • 6,546
  • 3
  • 25
  • 31
0

You only need to use t attribute to link the Trans tag to the language file. What you have between the tags is not important

<Trans i18nKey="cookieConsent.content" t={t}>
    x<Link to="/#privacy-policy">y</Link>z<Link to="/#legal">w</Link>
</Trans>
sepehrgd
  • 36
  • 3
  • Nice! Is it some new feature? In which version has it been added? – Knut Holm Dec 22 '21 at 09:37
  • @KnutHolm I don't know, I'm new to react-i18next. My version is 11.8.15 – sepehrgd Dec 23 '21 at 05:12
  • 7
    Every example on the net shows you how to write the react code for `Trans`, but no one will offer up what the translation file looks like. This is the most confusing API i've probably ever seen in my professional career. – The Muffin Man Jan 26 '23 at 00:52
-3

<Interpolate i18nKey="my-label" useDangerouslySetInnerHTML link={url} /> was added a few weeks ago and does allow inserting such translations containing html fragments - just be aware this is dangerous if url comes from userinput and contains malicious code (xss attack)

As i see this was added last year: https://github.com/i18next/react-i18next/pull/195/files

But this will wrap per default a span around every part before/after {{link}} so that might not be what you need...but the solution is rather simple - do not use interpolate component but regular interpolation on the t function:

<div dangerouslySetInnerHTML={t('my-label', { link: yourURL }} />

jamuhl
  • 4,352
  • 2
  • 25
  • 31