4

我有一个基于反应的应用程序并使用 i18next 的 Trans 组件进行翻译。

假设我们有一个用户注册表单,我们想通过显示以下文本来确认已创建一个新帐户:

已创建名为NAME的用户。

其中NAME由用户提供并以粗体显示。

我现在拥有的是以下代码:

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

和以下翻译字符串

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

对于一个简单的案例,name: 'Tom'它可以正常工作并显示

已创建名为Tom的用户。

但是我想让用户在他们的名字中使用特殊字符。当我把名字改成Tom&Jerry我得到

Tom&amp;Jerry已创建具有名称的用户。

在做了一些研究之后,我认为问题在于 i18next 和 react 都转义了它们的输入,因此名称被转义了两次。i18next.init我通过添加以下选项关闭了 i18next 转义

interpolation: {escapeValue: false},

这解决了 Tom&Jerry 案:

已创建名为Tom&Jerry的用户。

但是有一些输入会完全破坏它,例如name: 'Tom<'像这样设置渲染(名称后面的所有内容都是粗体):

已创建名为 Tom 的用户。

和设置name: '<Tom>'给了我:

已创建具有名称的用户。

(根本没有显示名称)。我希望它呈现如下:

<Tom>已创建具有名称的用户。

有没有办法让它工作?

4

1 回答 1

3

这个问题没有优雅的解决方案。问题的根源在于Trans组件的源代码。您要么需要为此文件创建一个补丁来更改此行为,要么自己实施一个欺骗技巧。如果您要使用欺骗性解决方案,您将创建一个组件,该组件UnescapedTrans将使用 lodash 对 HTML 实体进行转义:

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

代码沙盒示例

于 2019-10-11T06:01:33.653 回答