'Using react-i18next as a translation provider for React Admin

I am trying to use react-i18next as a translation provider for react-admin. React-admin provides documentation on how to setup a custom translation provider.

This was easy enough to follow and I created one for i18next:

export const i18nProvider = {
    translate: (key, { _, smart_count, ...rest } = {}) => {
        return i18n.t(key, {
            defaultValue: _,
            count: smart_count,
            ...rest,
        });
    },
    changeLocale: (locale) => i18n.changeLanguage(locale),
    getLocale: () => i18n.language,
};

The problem I am having is that react-i18next uses suspense to load the translations, and this behavior does not seem to work when calling the i18n.t function directly like this, rather than through a hook:

import React, { Suspense } from 'react';
import { useTranslation } from 'react-i18next';

function MyComponent() {
  const { t, i18n } = useTranslation();

  return <h1>{t('Welcome to React')}</h1>
}

// i18n translations might still be loaded by the http backend
// use react's Suspense
export default function App() {
  return (
    <Suspense fallback="loading">
      <MyComponent />
    </Suspense>
  );
}

What ends up happening is that the i18n.t function is called before the translation is loaded, and ends up not showing the translations.

Is there a better approach to integrate react-i18next with react admin?



Solution 1:[1]

Instantiate i18n and simply import it when mounting your app

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

import frTranslations from '~/locales/fr.json';

i18n
  // pass the i18n instance to react-i18next.
  .use(initReactI18next)
  // init i18next
  // for all options read: https://www.i18next.com/overview/configuration-options
  .init({
    fallbackLng: 'fr',
    resources: {
      fr: { translation: frTranslations },
    },
  });

export default i18n;
import App from './App';

import './i18n';

ReactDOM.render(<App />, document.getElementById('root'));

Then you can use it like you do

import { useTranslation } from 'react-i18next';

function SearchFilter(props) {
  const { t } = useTranslation();
  ...
}

Solution 2:[2]

You need to read react-i18n and react-admin translation to know the basics.

Make a json file from react-admin available locales, choose one and locate the translation file. In my case the translation file is index.js, the content is translated and stored in public/locales/zh-tw/translation.json. Make sure to include the ra: json key.

Step to walkthrough this solution:

  1. yarn add [email protected] [email protected]
  2. In project dir cd node_modules && ln -s ../public public to import a translation file, e.g. public/locales/zh-tw/translation.json
  3. Create src/i18n.js and add:
import i18n from "i18next";
import {initReactI18next} from "react-i18next";

import chineseTranslation from 'public/locales/zh-tw/translation.json';

// the translations
const resources = {
    "zh-TW": {
        translation: chineseTranslation
    }
};

i18n
    .use(initReactI18next) // passes i18n down to react-i18next
    .init({
        resources,
        lng: "zh-TW",

        // keySeparator: false, // we do not use keys in form messages.welcome

        interpolation: {
            escapeValue: false // react already safes from xss
        }
    });

export default i18n;
  1. In src/index.js add import './i18n';
  2. In your src/App.jsx, apply the following:
import {Admin, Resource, ListGuesser} from "react-admin";
import * as React from "react";
import polyglotI18nProvider from 'ra-i18n-polyglot';
import chineseTranslation from 'public/locales/zh-tw/translation.json';

// @ts-ignore
const i18nProvider = polyglotI18nProvider((_) => chineseTranslation);

const LandingPage = () => (
    <Admin i18nProvider={i18nProvider}>
        <Resource name="users" list={ListGuesser}/>
    </Admin>
);

export default LandingPage;

I am using typescript for react-admin, so I added //@ts-ignore to get rid of compile error.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Striped
Solution 2