React i18next - Don't show translations until request finished - reactjs

I am getting language info from backend. I would like to make the request to get language info, and then signalize to i18next that it can show translations.
Currently, it shows the default language translations for a second, until the request finishes and I call i18next.changeLanguage().
How would I achieve this ?
This is my config:
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import XHR from "i18next-xhr-backend";
i18n
.use(initReactI18next)
.use(XHR)
.init({
fallbackLng: "en-GB",
keySeparator: false,
interpolation: {
escapeValue: false
},
backend: {
loadPath: "/locales/{{lng}}.json"
}
});
I am using the useTranslation hook to get the t function:
const { t } = useTranslation();

In case of react-i18next make sure useSuspense is enabled or handle the ready state in HOCs or hooks yourself.
You need to wrap your root component with Suspense component to determine what should be rendered while translations are loading.
import React, { Suspense } from 'react';
import RealApp from './App';
import Loading from './Loading';
import { I18nextProvider } from 'react-i18next';
import App from './App';
function Root(props) {
return (
<Suspense fallback={<Loading />}>
<I18nextProvider i18n={i18n}>
<Root />
</I18nextProvider>
</Suspense>
);
}
For more info.

Related

Implementation i18n in react js best practice

import React from "react";
import { createRoot } from 'react-dom/client';
import i18n from "i18next";
import { useTranslation, initReactI18next } from "react-i18next";
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
// the translations
// (tip move them in a JSON file and import them,
// or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
resources: {
en: {
translation: {
"Welcome to React": "Welcome to React and react-i18next"
}
}
},
lng: "en", // if you're using a language detector, do not define the lng option
fallbackLng: "en",
interpolation: {
escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
}
});
function App() {
const { t } = useTranslation();
return <h2>{t('Welcome to React')}</h2>;
}
// append app to dom
const root = createRoot(document.getElementById('root'));
root.render(
<App />
);
I just want best configure for localization.
I want to implement localization in my app. So i want to configure it as documentation. Is there any way i can manupulate my json file from admin panel.

react-i18n useSuspense never ends if backend loading fails

In my react app, I am using i18next-http-backend to load translation data from backend response. Currently my app works fine in the below configuration:
config.js
import i18n from 'i18next';
import {initReactI18next} from 'react-i18next';
import HttpApi from 'i18next-http-backend';
import axios from "axios";
const backendOptions = {
loadPath: 'http://localhost:3000/messages',
request: async (options, url, payload, callback) => {
try {
const translation = await axios.get(url);
callback(null,{
status: 200,
data: JSON.stringify(translation.data),
});
} catch (e) {
callback(e);
}
},
};
const i18nextOptions = {
debug:true,
backend: backendOptions,
fallbackLng: 'en',
lng: 'en',
load:"languageOnly",
react: {
useSuspense: true,
},
ns: ['translations'],
defaultNS: 'translations'
}
i18n.use(initReactI18next)
.use(HttpApi )
.init(i18nextOptions);
i18n.languages = ['en', 'jp'];
i18n.on('failedLoading', function(lng, ns, msg) {
console.log("backend error");
})
export default i18n;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import './i18n/config';
import {store} from "./app/store";
import {Provider} from "react-redux";
import {ErrorBoundary} from "react-error-boundary";
import {Suspense} from "react";
import RuntimeErrorPage from "./features/error/runtime-error-page";
import Spinner from "./components/common/Spinner";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<ErrorBoundary FallbackComponent={RuntimeErrorPage}>
<Suspense fallback={<Spinner/>}>
<Provider store={store}>
<App/>
</Provider>
</Suspense>
</ErrorBoundary>
</React.StrictMode>
);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
However, if there is any backend error, the app gets stuck in Suspense. If I disable suspense then the i18next initializes without any resource. How can I handle any error comes from request? I need a way to either invoke ErrorBoundary fallback component or redirect to any error page.
i18next never throws an error...
Save those failed loadings somewhere else: https://codesandbox.io/s/react-i18next-http-example-forked-9ted7y?file=/src/i18n.js:188-295
and then create your own logic to show stuff: https://codesandbox.io/s/react-i18next-http-example-forked-9ted7y?file=/src/app.js:155-377
fyi: throwing inside an event listener is not a good idea
btw: why do you want to show an error when translations are not loaded? Why not showing a fallback text? The error is not intended for the end users anyway...

Loading in i18n translations without showing translation ids

I've implemented i18next in my nextjs project, and I'm having the issue, that I can briefly see all the text-id's before the translations get fully loaded. Is there any way to avoid showing these text ID's as it causing a bit of flickering on load? It's especially obvious when refreshing the page quickly.
I have tried different ways with both useSuspense and wait in the config and App file. Currently this is what I have (translation files are located in public/locales/xx/translation.json):
i18n.jsx
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
i18n
.use(Backend)
.use(initReactI18next)
.init({
debug: true,
fallbackLng: 'en',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
react: {
useSuspense: true
}
});
export default i18n;
Usage:
import { useTranslation } from 'react-i18next';
export default function Text () {
const { t } = useTranslation();
return (<Text>{t('text.string.here')}</Text>)
App
import { Suspense } from 'react'
import i18n from 'components/i18n'
function MyApp({ Component, pageProps }) {
<Suspense fallback="loading">
<Component {...pageProps}/>
</Suspense>
}

react-i18next giving a missingKey error in build only

Below are my index.js and i18next.js(the config for i18n)
index.js
import React, { Suspense } from 'react'
import i18n from './i18next'
import './i18next'
import ReactDOM from 'react-dom'
import App from './App'
import * as serviceWorker from './serviceWorker'
import Loading from './components/Styled/Loading/Loading'
i18n.init().then(() =>
ReactDOM.render(
<React.StrictMode>
<Suspense fallback={<Loading />}>
<App />
</Suspense>
</React.StrictMode>,
document.getElementById('root')
)
)
i18next.js
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import Backend from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
// not like to use this?
// have a look at the Quick start guide
// for passing in lng and translations on init
const Languages = ['en', 'fr']
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
debug: true,
whitelist: Languages,
keySeparator: false,
defaultNS: 'translation',
ns: ['translation'],
backend: {
loadPath: `/locales/{{lng}}/{{ns}}.json`,
},
load: 'unspecific',
react: {
wait: true,
},
interpolation: {
escapeValue: false,
},
})
export default i18n
console
So, here's the gist. I use the useTranslation hook in my components and it works perfectly fine in localhost. However, I constantly keep getting the missingKey error on production where the build is deployed. Have tried all the feasible settings from other answers, without success. Apologies for the huge content, I just wanted to be thorough.
Figured out the solution. Because I'm serving the build in a sub-directory, I had to append it to loadPath.
.env
REACT_APP_VERSION=$npm_package_version
REACT_APP_PUBLIC_URL='/dy/'
i18next.js
backend: {
loadPath: `${process.env.PUBLIC_URL}/locales/{{lng}}/{{ns}}.json`,
}

How to fix 'no fallback UI was specified' in react i18next using hooks

I am trying to implement i18next in my react component using the useTranslation hook, but it keeps saying:
Uncaught Error: Test suspended while rendering, but no fallback UI was specified.
Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.
How can I add the <Suspense> any higher than what I've got? What am I doing wrong? How do I fix this? It seems to work OK when I use the <Translation> component. Naturally, it also seems to work OK if I turn Suspense off and try to handle it myself, but that sort of defeats the purpose, I think. How can I make this actually work? Do I have the Fetch backend misconfigured?
Test.js
import React, { Suspense, useState, useEffect, lazy } from "react";
import PropTypes from "prop-types";
import i18n from './i18n';
import { useTranslation } from 'react-i18next';
export default function Test( props ){
const { t, i18n } = useTranslation( 'bingo_game' );
return (
<Suspense fallback={<div>Loading...</div>}>
<div>
Pant leg
</div>
</Suspense>
)
}
Test.propTypes = {
token: PropTypes.string.isRequired,
};
and
i18n.js
import i18n from "i18next";
import LngDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import Fetch from "i18next-fetch-backend";
i18n
.use(LngDetector) //language detector
.use(Fetch)
.use(initReactI18next)
.init({
backend: {
loadPath: "/infra/locales/{{ns}}.json",
// path to post missing resources
addPath: "locales/add/{{ns}}",
// define how to stringify the data when adding missing resources
stringify: JSON.stringify
},
defaultNS: "base",
fallbackLng: "en",
debug: true,
initImmediate: false
});
export default i18n;
I've gone over the docs that I could find as well as this SO post that is not my issue.
in your i18n file add this, it will do the magic :)
.init({
react: {
useSuspense: false,
...
});
It's not best way but I can recommend you to turn off suspense by adding this lines to your's config
i18n
.init({
...
// react i18next special options (optional)
react: {
useSuspense: false,
wait: false,
},
});
Using useSuspense: false is ok but you need to use ready state in this case as well, otherwise your translation keys appear at interface until i18next is ready... Similar to this:
const { t, i18n, ready } = useTranslation()
and in the render section:
{ready && (<SampleComponent />)}
You can set useSuspense: false in useTranslation options.
const { t } = useTranslation("your-namespace", {useSuspense: false});
https://react.i18next.com/latest/usetranslation-hook#not-using-suspense

Resources