stackoverflow
stackoverflow

Reputation: 1597

React 18 & react-i18next Trans component interpolation issue

I've just upgraded to react v18 but I get an error while doing interpolation using Trans component of react-i18next

<Trans i18nKey="pageNrOfAll" pageNr={pageNr} pagesCount={pagesCount}>
    Page
    <strong className="spacing">{{ pageNr }}</strong>
    of
    <strong className="spacing">{{ pagesCount }}</strong>
 </Trans>

enter image description here

Type '{ pageNr: number; }' is not assignable to type 'ReactNode'.
  Object literal may only specify known properties, and 'pageNr' does not exist in type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.ts(2322)
index.d.ts(1375, 9): The expected type comes from property 'children' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>'

If I keep only one pair of brackets { pageNr } I get the following error

react-i18next:: Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}. 1

Upvotes: 5

Views: 6382

Answers (4)

Jiwoks
Jiwoks

Reputation: 559

Another easy approach is to use React fragments <></> to wrap your variable

<Trans i18nKey="pageNrOfAll" pageNr={pageNr} pagesCount={pagesCount}>
   Page
   <strong className="spacing"><>{{ pageNr }}</></strong>
   of
   <strong className="spacing"><>{{ pagesCount }}</></strong>
</Trans>

You're passing an object as a Child of Trans component. But Typescript is waiting for a React element, wrapping your variable around a fragment will give it just what is expecting to have.

Upvotes: 2

Volker Fried
Volker Fried

Reputation: 421

I created my own component with any type as a workaround. This bypasses the TypeScript logic, but a quick replacement for larger project. In addition, you now have a central component to make formatting adjustments.

Before:

<Trans i18nKey="files.successFileUploaded">
    File <strong>{{ fileName: selectedFilename }}</strong> uploaded successfully!
</Trans>

After:

<Trans i18nKey="files.successFileUploaded">
    File <TransHighlight>{{ fileName: selectedFilename }}</TransHighlight> uploaded successfully!
</Trans>

New component:

import React from 'react';

interface TransHighlightProps {
  children?: React.ReactNode | any;
}

function TransHighlight(props: TransHighlightProps) {
  const { children } = props;
  return (<strong>{children}</strong>);
}

export default TransHighlight;

Upvotes: 1

Francisco Gomes
Francisco Gomes

Reputation: 1897

Try this approach. That's the best I could come up with that also works with Typescript.

App.jsx/App.tsx

<Trans i18nKey="pageNrOfAll" values={{ pageNr: pageNr, pagesCount:pagesCount }}>
    Page
    <strong className="spacing"></strong>
    of
    <strong className="spacing"></strong>
</Trans>

Translation en-US of pageNrOfAll

{
    "pageNrOfAll": "Page <1>{{pageNr}}</1> of <3>{{pagesCount}}</3>"
}

Translation pt-BR of pageNrOfAll

{
    "pageNrOfAll": "Página <1>{{pageNr}}</1> de <3>{{pagesCount}}</3>"
}

Upvotes: 2

adrai
adrai

Reputation: 3168

There’s an open issue here: https://github.com/i18next/react-i18next/issues/1483

Just follow tge discussion there.

Upvotes: 4

Related Questions