Unexpected behavior in translation for React

73 Views Asked by At

I have a working component wired up like so:

import { useTranslation } from 'react-i18next';
...
const Child = () => {
  ...
  const { t } = useTranslation();
  console.log(t('donkey'));
  const output = (<Box>...</Box>);
  return output;
};
export default Child;

Then, I wanted to pass the translations from the parent component like this:

import { useTranslation } from 'react-i18next';
import Child from '../Child';
...
const Parent = () => {
  const { t } = useTranslation();
  ...
  console.log(t('donkey'));
  return (...<Child trans={t} />...);
};
export default Parent

In the child component, I introduce the following changes:

import { useTranslation } from 'react-i18next';
...
const Child = (trans: any) => {
  const { t } = useTranslation();

  console.log(trans.t);
  console.log(t);
  console.log(trans.t('donkey'));
  console.log(t('donkey'));
  ...
};
export default Child;

It seems like I passed the same function (judging by the signature). However, the printout differs: the local version produces the actual translation while the passed one gives me donkey.

I can't explain why, let alone resolve it. My (weak) suspicion point to the state not being involved with the selected language. Googling gave me but a headache, likely due to my ignorance of the subject, possibly missing some revant info despite looking at it.

I'm also uncertain why I have to use trans.t despite picking it out from useTranslation() in the parent. I'm not sure if setting any to the type passed is affecting the behavior, either, but I can't figure out the strongly typed type (the intellisense only says translation). Possibly this may be pointing to the root cause of the problem?

How can I investigate it further?

edit

Based on the comments, I can refine the question now.

Passing from the parent like this

<Child props={useTranslation} />

and receiving it in the child like this

const Child = (props: any) => {
  const { t } = props;
  console.log(t('donkey'));
};

should, in my understanding, produce the same output as

const Child = (props: any) => {
  const { t } = useTranslation();
  console.log(t('donkey'));
};

but it doesn't. It only prints the translation key in the former case but the actual translation in the latter. When I execute

console.log(t('donkey'));

in the parent I get the proper translation too. It looks like if the translation capacity is lost in the pass to the child. I can't see how to proceed from here. (I also feel unsure how to explicitly set the type for props as the intellisense makes no sense.)

1

There are 1 best solutions below

0
On BEST ANSWER

I think the problem lies in that you are passing the hook useTranslation uninitialized so it won't return the functions. Take a look at this sample that does what you want to achieve by passing the t function to the child component:

const Child = ({ t }) => {
  if (t === undefined) return "t is not a function";

  return <>{t("Welcome to React")} from Child</>;
};

export default function App() {
  const { t, i18n } = useTranslation();

  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };

  const index = 11;

  return (
    <div className="App">
      <div className="App-header">
        <h2>{t("Welcome to React")}</h2>
        <button onClick={() => changeLanguage("de")}>de</button>
        <button onClick={() => changeLanguage("en")}>en</button>
      </div>
      <div className="App-intro">
        <Trans>
          To get started, edit <code>src/App.js</code> and save to reload.
        </Trans>
        <Trans i18nKey="welcome">trans</Trans>
        <Trans>
          {index + 1} <a>xxx</a>
        </Trans>
      </div>
      <div style={{ marginTop: 40 }}>
        <Child t={t} />
      </div>
    </div>
  );
}

This is an excerpt from this codesandbox where I got this to work. In any case, I don't think this is the right way to do it and I don't see the use case for having to pass the translation function to the child. The right thing to do would be to use the hook useTranslation inside the child.