Skip to content

Commit

Permalink
parse first, then interpolate (#1345)
Browse files Browse the repository at this point in the history
* parse first, then interpolate

This avoids problems with user given values potentially breaking the parse tree

Regarding #1344

* new test ensuring that user defined values are not parsed

Co-authored-by: Christian Kruse <cjk@defunct.ch>
  • Loading branch information
ckruse and Christian Kruse authored Jul 16, 2021
1 parent 23b5481 commit 498b441
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
24 changes: 13 additions & 11 deletions src/Trans.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,10 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) {

getData(children);

const interpolatedString = i18n.services.interpolator.interpolate(
targetString,
{ ...data, ...combinedTOpts },
i18n.language,
);

// parse ast from string with additional wrapper tag
// -> avoids issues in parser removing prepending text nodes
const ast = HTML.parse(`<0>${interpolatedString}</0>`);
const ast = HTML.parse(`<0>${targetString}</0>`);
const opts = { ...data, ...combinedTOpts };

function renderInner(child, node, rootReactNode) {
const childs = getChildren(child);
Expand All @@ -157,7 +152,12 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) {
const astNodes = getAsArray(astNode);

return astNodes.reduce((mem, node, i) => {
const translationContent = node.children && node.children[0] && node.children[0].content;
const translationContent =
node.children &&
node.children[0] &&
node.children[0].content &&
i18n.services.interpolator.interpolate(node.children[0].content, opts, i18n.language);

if (node.type === 'tag') {
let tmp = reactNodes[parseInt(node.name, 10)]; // regular array (components or children)
if (!tmp && rootReactNode.length === 1 && rootReactNode[0][node.name])
Expand All @@ -182,7 +182,8 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) {
// console.warn('CHILD', node.name, node, isElement, child);

if (typeof child === 'string') {
mem.push(child);
const value = i18n.services.interpolator.interpolate(child, opts, i18n.language);
mem.push(value);
} else if (
hasChildren(child) || // the jsx element has children -> loop
isValidTranslationWithChildren // valid jsx element with no children but the translation has -> loop
Expand Down Expand Up @@ -243,10 +244,11 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) {
}
} else if (node.type === 'text') {
const wrapTextNodes = i18nOptions.transWrapTextNodes;
const content = i18n.services.interpolator.interpolate(node.content, opts, i18n.language);
if (wrapTextNodes) {
mem.push(React.createElement(wrapTextNodes, { key: `${node.name}-${i}` }, node.content));
mem.push(React.createElement(wrapTextNodes, { key: `${node.name}-${i}` }, content));
} else {
mem.push(node.content);
mem.push(content);
}
}
return mem;
Expand Down
25 changes: 23 additions & 2 deletions test/trans.render.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,8 @@ describe('trans with wrapTextNodes', () => {
});
afterAll(() => {
i18n.options.react.transWrapTextNodes = orgValue;
})
});

const TestComponent = () => (
<Trans i18nKey="transTest1">
Open <Link to="/msgs">here</Link>.
Expand Down Expand Up @@ -584,3 +584,24 @@ describe('trans with wrapTextNodes', () => {
`);
});
});

describe('trans does ignore user defined values when parsing', () => {
const TestComponent = ({ value }) => (
<Trans>
This is <strong>just</strong> some {{ value }} text
</Trans>
);

it('should escape value with angle brackets', () => {
const { container } = render(<TestComponent value="<weird>" />);
expect(container.firstChild).toMatchInlineSnapshot(`
<div>
This is
<strong>
just
</strong>
some &lt;weird&gt; text
</div>
`);
});
});

0 comments on commit 498b441

Please sign in to comment.