I'm using react-i18next to internationalize my react app. When I trying to addResourceBundle on each module's config files it throws this error:
TypeError:
i18next__WEBPACK_IMPORTED_MODULE_0__.default.addResourceBundle is not
a function
Therefore, I added i18next.init command before addResourceBundle. Then it works, but show below warning and reset previously selected locale.
i18next: init: i18next is already initialized. You should call init
just once!
This is my i18n.tsx file
import i18n from 'i18next'
import Backend from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
i18n
.use(Backend)
.use(LanguageDetector)
.use (initReactI18next)
.init({
fallbackLng: 'en',
debug: true,
detection: {
order: ['queryString', 'cookie'],
cache: ['cookie']
},
interpolation: {
escapeValue: false
},
react: {
wait: true,
useSuspense: false,
}
})
export default i18n;
This is my Module's Config file
import i18next from 'i18next';
import { lazy } from 'react';
import en from '../../i18n/dashboard/en';
import si from '../../i18n/dashboard/si';
import ta from '../../i18n/dashboard/ta';
i18next.init({ resources: {} });
i18next.addResourceBundle('en', 'dashboard', en);
i18next.addResourceBundle('si', 'dashboard', si);
i18next.addResourceBundle('ta', 'dashboard', ta);
const DashboardConfig = {
settings: {
layout: {
mode : 'default'
}
},
routes: [
{
path: '/dashboard',
component: lazy(() => import('./Dashboard')),
auth : ['admin', 'user', 'DASHBOARD_VIEW'],
}
]
};
export default DashboardConfig;
it happens, because you are importing i18next in your module instead of created instance in i18n.tsx.
it should be like this:
import i18next from 'path/to/i18n.tsx';
Related
I have a language detection mechanism from the url lang code. If user is accessing authenticated page without access token, I redirect to login page in the Routes.js.
return user ? (
<Component {...props} />
) : (
<Redirect to={langUrl(`login`)} />
);
LangUrl is a helper function to get url with correct lang code
export const langUrl = (url) => {
return '/'+ i18n.language +'/'+ url;
};
But I get an undefined in the i18n.language, the redirect url is "/undefined/login". My i18n init file is below
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import HttpApi from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
i18n
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init({
supportedLngs: ['en', 'ar'],
fallbackLng: 'ar',
debug: false,
// Options for language detector
detection: {
order: ['path', 'cookie', 'htmlTag'],
caches: ['cookie'],
},
react: { useSuspense: false },
defaultNS: 'translation',
backend: {
loadPath: '/assets/locales/{{lng}}/{{ns}}.json',
},
});
export default i18n;
What is the best way to initiliaze the i18n correctly so that language is not undefined?
adding the following value initImmediate: false, in i18n config file
please check the full answer here
i18n.language undefined in react.js
In my src folder, I made a folder called i18n, and it contains these three files
en.json
es.json
pl.json
This is what they look like:
{
"selectAction": "Select Action",
"workflow": "Workflow",
"details": "Details"
}
In src folder, I also added this file called i18n.js
import i18n from 'i18next'
import LanguageDetector from "i18next-browser-languagedetector"
import { initReactI18next } from 'react-i18next'
// import Backend from "i18next-xhr-backend";
// import XHR from 'i18next-xhr-backend'
import languageEn from './i18n/en.json'
import languageEs from './i18n/es.json'
import languagePl from './i18n/pl.json'
i18n
// .use(Backend)
// .use(XHR)
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
en: languageEn,
es: languageEs,
pl: languagePl
},
lng: "es",
fallbackLng: "en",
debug: true,
keySeparator: ".",
interpolation: {
escapeValue: false,
}
});
console.log(i18n.languages)
export default i18n;
My index.js file in the src root looks like this:
// import statements are omitted, but I am importing I18NextProvider and i18n
ReactDOM.render(
<I18nextProvider i18n={i18n}>
<App />
</I18nextProvider>
document.getElementById('root')
);
Lastly, somewhere in my App I have this:
// Other imports omitted
import { useTranslation } from 'react-i18next';
const DetailsPlaceholder = () => {
const { t } = useTranslation();
return (
<h4 className="zero-state-section-text">{t('selectAction')}</h4>
);
};
export default DetailsPlaceholder;
When I try to load the page, I see the key 'selectAction' as the text (instead of the real text), and this error gets logged:
i18next::translator: missingKey es translation selectAction selectAction
All resource files should store strings under translation key (like in quick start for react-i18next):
{
"translation": {
"selectAction": "Select Action",
"workflow": "Workflow",
"details": "Details"
}
}
Here is a repository with a reproduced error and fixed configuration:
https://github.com/terales/reproduce-react-i18next-missingkey-error
I am using the i18n module in my react app which is hosted as an app (which I will refer to as live app) on S3 and has cloudfront sitting in front of it.
I want to store the s3 url in a config file as to avoid having it hardcoded in my app so that I can work against translation files stored locally in the public/locales folder when I'm developing.
Initially I had my backend options set-up so that it would always try and look up the files in the locales path. And this worked locally but stopped working on S3 although the locales folder was present in the S3 bucket. I also noticed that no request was being sent from the app to retrieve the translation files.
backend: {
loadPath: 'locales'
}
I then decided to upload the translation files to another S3 bucket and host them there to see if this would fix the issue.
I changed my config to hardcode the s3 bucket path. This worked both locally and on the live app. But this means that I can't use my config file to determine the loadPath option.
backend: {
loadPath: '<myhardcoded-s3-bucket-url>/{{lng}}/translation.json',
crossDomain: true
}
I then thought I could construct the url in place as so:
/*global AWS_CONFIG */
/*eslint no-undef: "error"*/
...
...
...
backend: {
loadPath: `${AWS_CONFIG.aws_app_translations_path}/{{lng}}/translation.json`,
crossDomain: true
}
Strangely again this worked locally when AWS_CONFIG.aws_app_translations_path was both http://localhost:3000/locales and <myhardcoded-s3-bucket-url>.
However once I pushed it live, it failed again. This time making a request to https://<my-apps-base-path>/undefined/en-GB/translation.json for example. So it's trying to use the app path and append what I have defined in loadPath.
I then saw that I could have loadPath as a function to construct my url. This didn't work for the live app either, but again worked locally.
backend: {
loadPath: function (lng) {
return `${AWS_CONFIG.aws_app_translations_path}/${lng}/translation.json`
},
crossDomain: true
}
This is my entire i18n file
/*global AWS_CONFIG */
/*eslint no-undef: "error"*/
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
const options = {
order: ['navigator', 'localStorage'],
caches: ['localStorage'],
fallbackLng: "en-GB",
debug: true,
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
backend: {
loadPath: function (lng) {
return `${AWS_CONFIG.aws_app_translations_path}/${lng}/translation.json`
},
crossDomain: true
}
}
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init(options);
export default i18n;
What could explain this odd behaviour? Am I missing configuration here?
Based on your responses in the comments, looks like you are missing the translation part, and it pre-appending undefined as a namespace in the url.
Try this:
// i18n
const options = {
order: ['navigator', 'localStorage'],
caches: ['localStorage'],
fallbackLng: "en-GB",
debug: true,
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
backend: {
loadPath: function () {
return `${AWS_CONFIG.aws_app_translations_path}/{{lng}}/{{ns}}.json`
},
crossDomain: true
}
}
Based on the loadPath config doc:
path where resources get loaded from, or a function
returning a path:
function(lngs, namespaces) { return customPath; }
The returned path will interpolate lng, ns if provided like giving a static path
Once I changed the way I was importing the config file it worked. I am guessing there is a loading issue on live, but having changed my i18n file from
/*global AWS_CONFIG */
/*eslint no-undef: "error"*/
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
const options = {
order: ['navigator', 'localStorage'],
caches: ['localStorage'],
fallbackLng: "en-GB",
debug: true,
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
backend: {
loadPath: function (lng) {
return `${AWS_CONFIG.aws_app_translations_path}/${lng}/translation.json`
},
crossDomain: true
}
}
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init(options);
export default i18n;
to
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
import {config} from './config';
const {aws_app_translations_path} = config;
const options = {
order: ['navigator', 'localStorage'],
caches: ['localStorage'],
fallbackLng: "en-GB",
debug: true,
defaultNS: 'translation',
load: 'currentOnly',
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
backend: {
loadPath: (lng, ns) => {
return `${aws_app_translations_path}/${lng}/${ns}.json`;
},
crossDomain: true
}
}
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init(options);
export default i18n;
Fixed it. Initially AWS_CONFIG was being returned as undefined despite working for the rest of the entire app. Changing the config file to live in the root directory of the project and the way it was imported solved the issue.
I have tryed to implement react-i18next to my react application but it doesn't give a f... that I want it to work
Console doesn't show any error. It just doesn't translate.
Anyone had similar problem and can help me figure out why it doesn't translate?
my i18n.js file content:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import translationPL from './translations/pl/common.json';
const resources = {
pl: {
translation: translationPL
}
};
i18n
.use(initReactI18next)
.init({
resources: resources,
lng: "pl",
defaultNS: 'common',
keySeparator: false,
interpolation: {
escapeValue: false
}
});
export default i18n;
then my App.js file
import React from 'react';
import './App.css';
import './i18n';
import { withTranslation } from 'react-i18next';
class App extends React.Component {
.
.
.
render() {
const { t } = this.props;
return (
button className="btn btn-primary" onClick={() => this.endMeeting()}><span className="code-tag">{ t('End meeting') }</span></button>
);
}
}
export default withTranslation('common')(App);
and lastly ./translations/pl/common.json
{
"End meeting": "Zakończ posiedzenie"
}
update
After enabling debug option it gives me this output:
i18next: languageChanged pl
i18next: initialized {debug: true, initImmediate: true, ns: Array(1), defaultNS: "common", fallbackLng: Array(1), …}
i18next::translator: missingKey pl common key_name key_name
i18next::translator: missingKey pl common key_name key_name
Try to add 'ns' param
i18next.init({
ns: ['common', 'moduleA', 'moduleB'],
defaultNS: 'moduleA'
}
in your case
ns: ['common']
I am trying to integrate i18next to my project. I have created an instance and made configurations. But when I build my project, I get missingKey error in which they are not inside React component, which means the function t is called with i18n instance.
i18next config:
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
import englishTranslation from './translations/messages-en.json';
import turkishTranslation from './translations/messages-tr.json';
import arabicTranslation from './translations/messages-ar.json';
const detectorOptions = {
// order and from where user language should be detected
order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],
// keys or params to lookup language from
lookupQuerystring: 'lang',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
lookupFromPathIndex: 0,
lookupFromSubdomainIndex: 0,
// cache user language on
caches: ['localStorage', 'cookie'],
excludeCacheFor: ['cimode'], // languages to not persist (cookie, localStorage)
// optional expire and domain for set cookie
// cookieMinutes: 10,
// cookieDomain: 'myDomain',
// optional htmlTag with lang attribute, the default is:
htmlTag: document.documentElement,
// only detect languages that are in the whitelist
checkWhitelist: true,
// optional set cookie options, reference:[MDN Set-Cookie docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie)
cookieOptions: { path: '/' },
};
const languageDetector = new LanguageDetector();
languageDetector.init(detectorOptions);
i18n
.use(initReactI18next)
.use(languageDetector)
.init({
lng: 'en',
debug: true,
resources: {
en: englishTranslation,
tr: turkishTranslation,
ar: arabicTranslation,
},
interpolation: {
escapeValue: false,
},
fallbackLng: 'en',
whitelist: ['en', 'tr', 'ar'],
});
i18n.on('languageChanged', language => i18n.reloadResources()
.then(() => console.log('Language changed to: ', language)));
export default i18n;
Console error:
i18next::translator: missingKey en translation systemPreparation systemPreparation
index.js:1 i18next::translator: missingKey en translation letsStart letsStart
index.js:1 i18next::translator: missingKey en translation infoAndApproval infoAndApproval
index.js:1 i18next::translator: missingKey en translation nextStep nextStep
...
and it goes like that.
The Javascript file that I am calling i18n instance:
import i18n from '../../../i18n';
export const property = {
text: i18n.t('videoRecording')
};
'videoRecording' keys is missing in messages-en.json file. Checkout also if the messages-en.json file have proper format, which should look as follow:
{
"videoRecording": "some translation"
}
I recommend you to use some tool for handling such situations.
Here is my config example
import i18n from 'i18next'
import Backend from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
const projectToken = "5e13e3019cff4dc6abe36009445f0883";
const loadPath = `https://cdn.simplelocalize.io/${projectToken}/_latest/i18next/{{lng}}/{{ns}}/_index`;
i18n
.use(Backend)
.use(LanguageDetector)
.use (initReactI18next)
.init({
// default/fallback language
fallbackLng: 'en',
ns: ["default"],
defaultNS: "default",
//detects and caches a cookie from the language provided
detection: {
order: ['queryString', 'cookie'],
cache: ['cookie']
},
interpolation: {
escapeValue: false
},
backend: {
loadPath
}
})
export default i18n;
Full project code: https://github.com/simplelocalize/simplelocalize-i18next