I am using i18next in a Gatsby and React app to handle internationalization. The website is in french and english and works well. The only issue is that when I set the language to french and refresh, I notice a short delay where language is not yet loaded, so it gives me english version (which is the language I set for fallback), and quickly returns to french.
My i18next config file:
import i18n from "i18next";
import fr from "./i18n/fr.json";
import en from "./i18n/en.json";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
const resources = {
fr: {
translation: fr
},
en: {
translation: en
}
};
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources,
fallbackLng: "en",
returnObjects: true,
interpolation: {
escapeValue: false
}
});
export default i18n;
Do you have any idea how to remove this delay and load the page directly to the chosen language ?
I had this problem. Firstly, I changed fallbackLng like this
import Cookies from 'js-cookie';
const cookieLanguage = Cookies.get('i18next');
fallbackLng: cookieLanguage ? cookieLanguage : 'en'
then I wrote in my onClick function
const [langChanged, setLangChanged] = useState(null);
const language = Cookies.get('i18next');
const changeLanguageHandler = (e) => {
const newLang = e.target.innerText.toLowerCase();
if (language !== newLang) {
window.location.reload(true);
broadcastChannel.postMessage("language changed");
setLangChanged(newLang);
}
}
And I used langChanged state like dependency in useEffect
useEffect(() => {
if (langChanged) {
i18next.changeLanguage(langChanged)
}
}, [langChanged])
So it returns same delay to every language
I suppose the fallback language is server-side rendered, and other languages are not.
If you click "view page source" in the browser you can see the original HTML code. I suppose you will see the english text, even if french is displayed on the page.
(Note that "inspect" will display french, because this includes all dynamic changes to the DOM, while "view page source" will display the original server response.)
So you need to render non-default languages on the server as well:
In case you store the language in a cookie, then you can query the cookie at the server-side, and send the correct text accordingly.
Alternatively you can use the URL to inform the server about the desired language (e.g. `/fr/mypage).
I don't use i18next, but you probably need to set the "initial store" to the desired language on the server-side, instead of set the fallback language as "initial store" and set the desired langage afterwards.
I read that you can set initialI18nStore and initialLanguage for the I18nextProvider
See also react.i18next Server Side Rendering
Related
I am trying to translate a React web app with the click of a button using i18n with the translations coming from .js files, not .json.
Here's the setup:
I have the i18n file:
const resources = {
en: enTranslation,
de: deTranslation,
};
i18n
.use(Backend)
.use(initReactI18next)
.init({
fallbackLng: "de",
debug: true,
resources,
interpolation: {
escapeValue: false,
},
});
export default i18n;
The imported "enTranslation" and "deTranslation" files are .js files with the respective language options. I import image files into those to use for some variables so a JSON file wouldn't work.
Excerpt example:
import pen from "../images/pen.jpg";
import table from "../images/table.jpg";
export const enTranslation = {
translation: {
imagePen: pen,
imageTable: table
}
}
The setup of the web app is as follows:
I have a "home.js" file where I define the structure of the page, like this:
const Home = () => {
const { t, i18n } = useTranslation();
return (
<>
<HeroSection {...**heroSectionContent**} />
<InfoSection {...infoSectionContents[0]} />
<Services {...cardSectionContent} />
<InfoSection {...infoSectionContents[1]} />
);
};
export default Home;
// page content objects
const **heroSectionContent** = {
header: i18next.t("header"),
description: i18next.t("intro"),
};
The contents for the different sections are all stored in constants below the React components, I included the hereSectionContent as an example.
This all works fine and if I change the fallback language in the i18n file, it shows the correct text. However, I would like to include a language switch for the user to be able to change the language, preferably without reloading the website. One section is made up of a multi-page questionnaire so reloading would throw the user back to page 1 and lose all the entered data.
Here's the LanguageSwitcher function I'm using:
function LanguageSwitcher() {
const { i18n } = useTranslation();
return (
<div className="select">
<select
value={i18n.language}
onChange={(e) => i18n.changeLanguage(e.target.value)}
>
<option value="de">Deutsch</option>
<option value="en">English</option>
</select>
</div>
);
}
export default LanguageSwitcher;
I noticed that if I refer to any of the text of the translation files directly out of the React return component, it works. Example:
Instead of writing
<HeroP>{heroSectionContent.description}</HeroP>
Changing it to
<HeroP>{t("intro")}</HeroP>
Works!
Is there any way to get this language switcher to work without having to write the i18n references into the return section?
Sorry if something is rather unclear or poorly worded, still pretty new to React.
Many thanks in advance!
I believe I have searched all parts of the internet for an answer and fixes but none seem to work.
Issue :
When building a react app for production that uses i18n as a translation will cause the production build to only display the strings only as a result and not the translated text itself (see picture reference)
The weird part is that inside localhost when the development server is running it display the translation correctly. (see picture for reference)
After building the production build, inside the browser console (using chrome) it displays the following error : Fetch API cannot load file:///Documents/streaming_site/build/static/locales/en/translation.json. URL scheme must be "http" or "https" for CORS request.
After seeing this error, I imediately came to the assumption that it was inside my i18next.js file that was causing the issue. Here is the file :
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import XHR from 'i18next-xhr-backend';
// don't want 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(XHR)
// load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
// learn more: https://github.com/i18next/i18next-http-backend
.use(Backend)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
lng : 'en',
react: {
useSuspense: false,
wait: true
},
fallbackLng: 'en',
debug: false,
whitelist: Languages,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
nsSeperator : false,
keySeperator : false,
backend:{
loadPath: () => {
var cors = require('cors');
var app = cors();
// check the domain
const host = window.location.host;
return (host === 'index.html#' ? '':'') + '/static/locales/{{lng}}/{{ns}}.json';
},
}
});
export default i18n;
Furhtermore inside my index.js file I added these extra fixes to ensure that the app would properly display the translated text on a production build :
i18next.init({// <-- This was added
interpolation: {escapeValue: false},
});
i18next.init().then(() => // <-- This was added
ReactDOM.render(
<React.StrictMode>
<Suspense fallback={<div>Loading...</div>}>// <-- This was added
<I18nextProvider i18n={i18next}>// <-- This was added
<App />
</I18nextProvider>
</Suspense>
</React.StrictMode>,
document.getElementById('root')
)
);
Alas, the same error occurs (the one from the third point) after making an npm run build
This leads me to believe that it is impossible without a backend server hosting the translation.json files for en and fr to have them be accessed locally.
My questions is the following: Is it possible to have i18n translation run locally after building the production build without needing a server to host the json files? If yes how would I proceed?
For references I have tried a few fixes from this website such as :
React i18next Backend-Path different in local and production environment
react-i18next doesn't translate
Allow Access-Control-Allow-Origin header using HTML5 fetch API
I've gotten close when I attempted --> res.header('Access-Control-Allow-Origin', "*"); although it comes at the cost of posing some security issue and I don't want that. Although if this is a potential fix, I am willing to try it.
So here I am out of ideas... :/
Looks like there is some misconfig of the i18next service.
First of all, i18next-http-backend & i18next-xhr-backend are solving the same problem, fetching json files.
Remove the second one (i18next-xhr-backend) since it is deprecated in favor of i18next-http-backend.
Change the backend.loadPath to be a string, your code doesn't make sense.
it should look like:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
// don't want 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)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
lng: 'en',
react: {
useSuspense: false,
wait: true,
},
fallbackLng: 'en',
debug: false,
whitelist: Languages,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
nsSeperator: false,
keySeperator: false,
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json',
},
});
export default i18n;
I have successfully installed the vue-fb-customer-chat plugin in my NuxtJS website and the chat is working fine.
It is a multilangual website and I need to be able to load the chat in the right language (current locale from the nuxt-i18n module). It is okay if the chat does not change its language after switching the language from within the website, but I'd like to at least have the correct language when the page loads.
Here's the content of plugins/vue-fb-customer-chat.js file:
import Vue from 'vue'
import VueFbCustomerChat from 'vue-fb-customer-chat'
Vue.use(VueFbCustomerChat, {
page_id: null, // change 'null' to your Facebook Page ID,
theme_color: '#845e5c', // theme color in HEX
locale: 'fr_FR', // default 'en_US'
})
None of the following works:
context.app.i18n.locale
this.$i18n.locale
$i18n.locale
What would the approach be to solve this issue?
Thank your for your help in advance.
My colleague anwsered my question.
import Vue from 'vue'
import VueFbCustomerChat from 'vue-fb-customer-chat'
export default function (context) {
const locale = context.app.i18n.locale;
const iso = context.app.i18n.locales.find(l => l.code === locale).iso;
Vue.use(VueFbCustomerChat, {
page_id: null, // change 'null' to your Facebook Page ID,
theme_color: '#845e5c', // theme color in HEX
locale: iso.replace('-', '_'), // default 'en_US'
})
}
Our project is using i18next for translations, and I'm currently needing to sort strings using String.prototype.localeCompare
How would I go about getting a code like 'en', 'fr', 'en-US', etc from i18next? Does i18next default to a specific code? Would I need to use an i18next instance or the default export?
I believe these might be called "BCP 47 language tags"
Thanks
Ok, so the brief answer is that you just use i18next.language
In our case, it did matter that we used the correct instance, not just the default import. We also used an additional layer called react-i18next as shown below.
import { I18nContext } from "react-i18next";
...
const { i18n } = useContext(I18nContext);
...
return isLocaleCompareSupported()
? aText.localeCompare(bText, i18n.language)
: aText.localeCompare(bText);
I'm using react-i18next in my reactjs app.
Problem is when I change the language the app reloads and always starts from main route.
is there a way to redirect on same page or change language without reload page?
thanks
UPDATE
I18n.js
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import {de} from "../../locales/de";
import {en} from "../../locales/en";
i18n
.use(LanguageDetector)
.init({
resources: {
en: en,
de: de
},
fallbackLng: 'de',
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
keySeparator: '.',
interpolation: {
escapeValue: false, // not needed for react!!
formatSeparator: ','
},
react: {
wait: true
}
});
export default i18n;
Change Language:
const { t, i18n } = this.props;
const changeLanguage = (lng) => {
i18n.changeLanguage(lng);
};
how do you change language? using querystring?
if you call i18next.changeLanguage(lng); there won't be a change, just rerender in new language...
as a sample see: https://github.com/i18next/react-i18next/blob/master/example/webpack2/app/components/View.js#L50
Had the same issue. I was using i18n-js and react navigation to manifest stacks and tabs. This thread was the only one I could find on the internet. However, it did not lead me to the solution. Anyway, I still managed to sort it out and would share my solution.
Check if you also translate the names of your stacks and tabs, most likely it should be the tab one. The translated name will make react navigation lost as it no longer recognize the pages being recorded in the route, as the tab names are completely new in another language. That is why it jumps to the page wherever it finds it is the top of all navigators. The walkaround is to use label for the texts you want to translate and display while keeping a static name for your pages.