0
votes

I have a react based application and use i18next's Trans component for translations.

Let's say we have a user registration form and we want to confirm that a new account has been created by displaying the following text:

User with name NAME has been created.

where NAME is provided by user and is displayed in bold.

What I have now is the following code in react:

<Trans i18n={i18next} i18nKey="userCreated" values={{name: 'Tom'}}>
   User with name <strong>{{name}}</strong> has been created.
</Trans>

and the following translation string

"userCreated": "User with name <1>{{name}}</1> has been created.",

For a simple case with name: 'Tom' it works fine and displays

User with name Tom has been created.

However I would like to let users use special characters in their names. When I change name to Tom&Jerry I'm getting

User with name Tom&amp;Jerry has been created.

After doing some research I thought that the issue is that both i18next and react escape their inputs and so the name is escaped twice. I turned off the i18next escaping in i18next.init by adding the following option

interpolation: {escapeValue: false},

That fixes the Tom&Jerry case:

User with name Tom&Jerry has been created.

but there are some inputs that break it completely, for example setting name: 'Tom<' renders like this (everything after name is bold):

User with name Tom has been created.

and setting name: '<Tom>' gives me:

User with name has been created.

(no name displayed at all). I would like it to render like this:

User with name <Tom> has been created.

Is there a way to make it work?

1
Can you provide the other react code? The other input component you think is escaping input?Drew Reese
@DrewReese I believe i18next is escaping it once - translating & into &amp; - and then react escapes it again so that instead of displaying a HTML entity &amp; is displayed literally. Turning off escaping in i18next fixes the issue, but then for some reason characters like < or > are breaking the whole functionality. There isn't much more react code, the Trans code I pasted is just rendered inside another component.Paweł Chorążyk
Ah, then this may be one of those rare instances where using react's [reactjs.org/docs/… is valid.Drew Reese

1 Answers

2
votes

There is no elegant solution to this problem. The root of the problem is in the source code of the Trans component. You either need to create a patch for this file changing this behavior or implement a cheaty trick by yourself. If you're going to use a cheaty solution, you'd create a component UnescapedTrans which will unescape HTML entities using lodash:

import React, { Suspense } from "react";
import { Trans } from "react-i18next";
import { unescape } from "lodash";


const getUnescapeChildrenRef = ref =>
  Array.from(ref.childNodes).forEach(node => {
    if (!node.innerText) {
      return node;
    }

    node.innerText = unescape(node.innerText);
  });

const UnescapedTrans = props => (
  <div ref={getUnescapeChildrenRef}>
    <Trans {...props} tOptions={{ interpolation: { escapeValue: true } }} />
  </div>
);

CodeSandbox example.