Search code examples
javascriptreactjstypescriptinternationalizationi18next

Issue with Translation dynamic data without reload in React using i18next


I am working on a React project where I have implemented language switching using i18next. The language switcher works correctly and changes the language with requiring a page reload. However i want it to work withour reload and after changing my language switch to work without reload I am facing an issue where the dynamically translated content in my components does not update when the language changes. The static content translated with useTranslation updates correctly, but the dynamically generated content in my components does not.

So i have LanguageSwtich is working correct with reload.

export default function LanguageSwitch() {
  const { i18n } = useTranslation();
  const [language, setLanguage] = useState(localStorage.getItem('lang') ?? 'en');

  function handleLangChange(lang: Key) {
    localStorage.setItem('lang', lang.toString())
    window.onload = function() {
      i18n.changeLanguage(lang.toString())
        .then(() => {
          setLanguage(lang.toString());
        })
        .catch((error) => {
          console.error('Error changing language:', error);
        });
    };
    window.location.reload();
  }

  return (
    <Dropdown aria-label='Language change switch'
              className={'language-switch'}
              onSelectionChange={handleLangChange}
              defaultSelectedKey={language}
              items={SUPPORTED_LANGUAGES}>
      {item =>
        <Item key={item.code}>{item.name}</Item>
      }
    </Dropdown>
  )
}

I changed method of handle to not relaod page and my dynamic data not translating now

function handleLangChange(lang: Key) {
    localStorage.setItem('lang', lang.toString())
    i18n.changeLanguage(lang.toString())
      .then(() => {
        setLanguage(lang.toString());
      })
      .catch((error) => {
        console.error('Error changing language:', error);
      });
  }

Here is the example of code

const Configurations = () => {
  const { t } = useTranslation();
  const [language, setLanguage] = useState(localStorage.getItem('lang') || 'en');
  const [configurations, setConfigurations] = useState([]);

  // Simulated API call to fetch configurations
  useEffect(() => {
    // Simulated configurations data
    const data = [
      { id: 1, type: 'foo' },
      { id: 2, type: 'bar' },
    ];
    setConfigurations(data);
  }, [language]); // Trigger fetch data when language changes

  return (
    <div>
      <h1>{t('Welcome')}</h1> - static data is translated correctly without reload
      <ul>
        {configurations.map((config) => (
          <li key={config.id}>
            {config.id}: {t(`TYPE_${config.type.toUpperCase()}.text`)} - dynamic data from the backend and using in the method are not translated without reload.
          </li>
        ))}
      </ul>
    </div>
  );
};

export default Configurations;

NOTE: LanguageSwitch is a part of another Header component which is using in every component as a button in header

I am thinking of rendering app without reloading, but I am not sure how to achieve this


Solution

  • You just need to use signal to have variable with updated state between components

    export const languageChanged = signal(false);
    

    and then update method

    function handleLangChange(lang: Key) {
      localStorage.setItem('lang', lang.toString());
      i18n.changeLanguage(lang.toString())
        .then(() => {
          setLanguage(lang.toString());
          languageChanged.value = !languageChanged;
        })
        .catch((error) => {
          console.error('Error changing language:', error);
        });
    }