简体   繁体   中英

HTML tags in i18next translation

I'm using i18next to power i18n for my weblog. It works great on text-only content, but when I try to translate content that includes HTML markup, it is displaying the raw markup when I translate the text.

As an example, here is a snippet of the markup from a post that is not working as expected:

<div class="i18n" data-i18n="content.body">
  In Medellín they have many different types of <i>jugos naturales</i>&nbsp;(fruit juice) ... <br />
  <br />
  ...
</div>

The translation code looks like this:

var resources = {
  "en": ...,
  "es": {
    "translation": {
      "content": {
        "body": "En Medellín hay varios tipos diferentes de <i>jugos naturales</i> ... <br /><br /> ... "
      }
    }
  }
}

i18n.init({"resStore": resources}, function( t ) {
  $('.i18n').i18n();
});

When the translation is rendered, HTML tags are escaped and output as text:

En Medellín hay varios tipos diferentes de &lt;i&gt;jugos naturales&lt;/i&gt;...&lt;br /&gt;&lt;br /&gt;

How do I get i18next to change the HTML of translated elements?

In order to make this work, you have to prefix the data-i18n attribute of the elements you want to translate with [html] :

<div class="i18n" data-i18n="[html]content.body">

Source: i18next.jquery.js

您需要关闭转义:

i18n.t("key", { 'interpolation': {'escapeValue': false} })

For anyone trying to do this in React (for example with react-i18-next ), be aware that React also escapes the string! So we have to tell both i18n and React not to escape the string.

  • To tell i18n to skip escaping, we use {escapeValue: false} as others have shown.

  • To tell React to skip escaping, we use React's dangerouslySetInnerHTML attribute.

<div dangerouslySetInnerHTML={
    {__html: t('foo', {interpolation: {escapeValue: false}})}
} />

That attribute accepts an object with one property __html . React intentionally made it ugly, to discourage its use, because not escaping can be dangerous.

For security, raw user input should not be used inside this element. If you do need to use an untrusted string here, be sure to sanitise or escape it, so the user cannot inject raw < or > into the page.

i18n.t('key',{dateStr: date, interpolation: {escapeValue: false}})

如果 date='15/10/2020' 对我有用,斜线也保留

This is an answer for React.

Eventually found a straight forward solution that can make code easier to maintain. Hope this helps!

{
  "stackoverflow": "<site_anchor>Welcome to stackoverflow!</site_anchor> You can also <profile_anchor>check my profile</profile_anchor>" 
}
import {Trans} from "react-i18next";
<Trans i18nKey="stackoverflow" components={{
  site_anchor: <Link href="https://stackoverflow.com" target="_blank"/>,
  profile_anchor: <Link href="https://stackoverflow.com/users/18131146/mondayrris" target="_blank"/>,
}} />

From the documentation :

Hint 3: Escaping:

 // given resources { 'en-US': { translation: { key1: Not escaped __nameHTML__, key2: Escaped __name__ } } }; i18n.t("key2", { name: '', escapeInterpolation: true }); // -> Escaped &lt;tag&gt; i18n.t("key1", { name: '', escapeInterpolation: false }); // -> Not escaped <tag>

Adding suffix 'HTML__' to your value will prevent the escaping even if option is set so.

You could turn on escaping on init i18n.init({escapeInterpolation: true}); or by passing in option to t function like in the sample.

Don't put the HTML tags in the translation. It's a bad idea anyway. Separation of concerns guys will be all whiny about it.

Use the <Trans> component if react-i18next [https://react.i18next.com/latest/trans-component][1]

Do like so:

// Component.js

<Trans>Welcome, <strong>User!</strong>, here's your <strong>broom</strong></Trans>

And the corresponding translation file:

// your locales/starwars_en.js file

translations: {
  "Welcome, <1>User!</1>, here's your <3>broom</3>": "Welcome, <1>young padawan!</1>, here's your <3>light saber</3>",
}

These numbers <1> and <3> will strike you as random but wait for it:

Trans.children = [
  'Welcome, ',                        // index 0
  '<strong>User!</strong>'            // index 1
  ', please don't be ',               // index 2
  '<strong>weak</strong>',            // index 3
  ' unread messages. ',               // index 4
]

More info here: https://stackoverflow.com/a/62563302/537648

You can turn off the escaping during initialization globally:

i18n.init({
  // ...
  interpolation: {
    escapeValue: false,
  }
});

I'm using both React and React Native. For the React app The solution works. Not for React Native.

React
i18n.js

interpolation: {
      escapeValue: false   
    }

somefile.jsx

<div dangerouslySetInnerHTML={{__html: t('dropZone.description')}} />

React Native
This solution does not work because < div> is not allowed within a Text tag. I tried to add the dangerouslySetInnerHTML to the Text tag, but then nothing is visible.

Does someone have a solution for React Native?

Solution in ReactJS:

Initial component:

...
<Typography>Hello <b>World</b><br />This is an <strong>example</strong></Typography>
...

Using Interweave with react-i18next

...
import { Markup } from "interweave"
...
<Typography><Markup content={t("paragraph")} /></Typography>
...

And your en.json file:

{
 "paragraph": "Hello <b>World</b><br />This is an <strong>example</strong>"
}

es.json:

{
 "paragraph": "Hola <b>Mundo</b><br />Esto es un <strong>ejemplo</strong>"
}

More information: Here

I was need use only bold text. So I used this code:

<Trans i18nKey='translationKey' values={{ name: 'ANY_VALUE' }} />

TranslationKey -> Do you want to remove <strong>{{name}}</strong>...? Found this solution in i18n documentation

For React apps using react-i18next package v11.6^ you can use Trans component in a smoothy way to apply html tags along with the translation text, I'll put this in a simple example:

inside our text translations file we have:

 greetings: 'Hello {{name}}!'

and we want to apply bold style on name variable using html tag strong , to do so we can:

 greetings: 'Hello <0>{{name}}</0>!'

Then where we want to use the translation we import Trans component from react-i18next and use it like so:

<Trans
 i18nKey='greetings'
 values={{
  name: 'John'
 }}
 components={[<strong />]}
/>

Then the result will be: Hello John !

Check here for more info: https://react.i18next.com/latest/trans-component#alternative-usage-which-lists-the-components-v11.6.0

The recommended way for React components as per the docs is:

// Component.jsx

<Trans i18nKey="newProfileLink">
    <Link to='/profile/new'>linkPlaceholder</Link>
</Trans>

// translations.js

{
"newProfileLink": "<0>Click here</0> to create a profile."
}

Note: the <0> refers to the index of the children passed to the Trans component. You can easily see the children and their corresponding index by looking at the props passed to the Trans component in developer tools.

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