简体   繁体   中英

react-i18next: interpolation of link in HTML tag in the middle of the text

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

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

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.

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>u
</Trans>

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM