Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML tags in i18next translation files in React

I'm using i18next in a project and can't get around including html tags in translation files and having them properly rendered.

An example of my .json translation file:

"en": {
  "product": {
    "header": "Welcome, <strong>User!</strong>"
  }
}

There is an excellent answer to this question, but relating to JQuery. I'm not using JQuery, my project is React and here is the setup that I have:

import i18next from 'i18next';
import en from 'locales/en';

i18next.
  init({
    lng: 'en',
    fallbackLng: false,
    resources: en,
    debug: false,

    interpolation: {
      escapeValue: false
    }
  });

export default i18next.t.bind(i18next);

In component I have:

import t from 'i18n';

t('product.header')

Html that I want:

Welcome, <strong>User!</strong>

Html I'm getting:

Welcome, &lt;strong&gt;User!&lt;/strong&gt

Thanks

like image 222
Petr Gazarov Avatar asked Oct 03 '16 16:10

Petr Gazarov


People also ask

What is i18next in React?

Based on the React i18n framework, react-i18next is another popular internationalization library which uses components to render or re-render the translated content of your application once users request a change of language.

How do I add internationalization in React?

The easiest way to internationalize a React app is to use the library i18next. i18next is an internationalization framework written in Javascript that can be used with many languages and frameworks, but most importantly with React.


2 Answers

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

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
]

SIDE NOTE (Can be considered a hack but saves tons of time): The guys at react.i18next.com, don't have this in their docs, but you can use the base language as a key (English in this case). It saves you time, not to double translate like they showed in their docs and I quote:

// Component file

import React from 'react';
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>
  );
}
// translation file

"userMessagesUnread": "Hello <1>{{name}}</1>, you have {{count}} unread message. <5>Go to message</5>.",
"userMessagesUnread_plural": "Hello <1>{{name}}</1>, you have {{count}} unread messages.  <5>Go to messages</5>.",

Anyway "Kudos!" to the i18next team! You are awesome, guys!

Here - go nuts!

like image 74
viktor_vangel Avatar answered Sep 20 '22 17:09

viktor_vangel


not a problem of react-i18next - you just can't add html into a react element. react will safe you from xss vulnerability and escape the content:

more detail and possible solution: https://facebook.github.io/react/tips/dangerously-set-inner-html.html

but be aware if you put user content there not escaped you open your site to xss attacks.

more secure reading the react-i18next readme: https://github.com/i18next/react-i18next#interpolate-component

which makes you split content

so the "best" solution - at least what we do - is using markdown in the translations and use eg: https://github.com/acdlite/react-remarkable to convert that to formatted content.

like image 23
jamuhl Avatar answered Sep 18 '22 17:09

jamuhl