Im trying to translate some stuff in my React application. This works fine with i18next and react-i18next. Im using the withNamespaces HOC to render the translations and scan them with PoEdit. So far so good.
There are however two issues that i am facing. I also have a library that holds all my UI components. More like all the styling which extends from semantic-ui itself. Over there also some translations are applicable and i wanted to use the same react-i18next there as well. While testing in storybook all looks good however when i run npm link and link the package to my main application i suddenly get this error:
caught TypeError: (0 , _reactI18next.withNamespaces) is not a function
The second question i do have is that how can i extend the translations? For example i am having this library which translates field A to be "How are you doing?". However when running a project for a customer i notice that the customer wants another translation for something that is part of the lib.
Is there a way then still to overwrite it? Since the fact the translations are bundled of course and loaded internally in the component.
Below is some code how it looks:
import i18n from 'i18next';
import { reactI18nextModule } from 'react-i18next';
import XHR from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(XHR)
.use(LanguageDetector)
.use(reactI18nextModule)
.init({
load: 'languageOnly',
backend: {
loadPath: '../dist/locales/{{lng}}/{{ns}}.json'
},
fallbackLng: {
'en-US': ['en']
},
ns: ['uielements'],
defaultNS: 'uielements',
fallbackNS: 'uielements',
debug: false,
keySeparator: '##',
interpolation: {
escapeValue: false // not needed for react!!
},
react: {
wait: true,
bindI18n: 'languageChanged loaded',
bindStore: 'added removed',
nsMode: 'default'
}
});
export default i18n;
And the components itself:
export default withNamespaces()(Dialog);
I had the same issue. It turned out that withNamespaces HOC component was introduced in react-i18next version 8.0.0. Ensure that you have the latest version:
npm i i18next#latest react-i18next#latest
I just checked i18next v12.0.0 and react-i18next v8.3.8. Everything works fine.
Related
I've got a project which uses React, i18next for internationalization and jest for testing.
The issue
Whenever I try to run my tests, it seems the Backend plugin is doing some fetches to load the translations from the public/locales folder, which ends up in an ugly error in the console, which (the main part) says:
Error: Error: connect ECONNREFUSED 127.0.0.1:80 at Object.dispatchError
Furthermore, anywhere where I want to use any of the i18n functionalities tests fail. For example, i18n.exists(message) always returns false when running in tests.
My guess is that Backend is actually making a fetch call to public folder, and it fails because during tests the server is not listening and does not return anything from the public folder, so basically no translations are loaded.
The project configuration
// i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
debug: false,
defaultNS: 'common',
fallbackLng: ['es'],
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
ns: ['common', 'comments'],
react: {
useSuspense: false,
},
});
export default i18n;
// setupTests.js
import '#testing-library/jest-dom';
jest.mock('react-i18next', () => ({
...jest.requireActual('react-i18next'),
useTranslation: () => ({
...jest.requireActual('react-i18next').useTranslation(),
t: (key: string, interpolation: any) =>
`T_${key}${
interpolation
? `--${Object.keys(interpolation)
?.map((k) => `${k}:${interpolation[k]}`)
.join('--')}`
: ''
}`,
}),
}));
And the locales folder structure:
What I've tried
I've tried to remove the Backend plugin from the use clauses, and then this error disappears. However, translations do not load anymore in the live app, and the other i18n functionalities keep failing in the tests.
Also, I've tried to load manually the resources option, importing directly the json file as a resource, and then it seems to work both: errors disappear and i18n.exists works as expected. But I don't want to have to load all the json files for each namespace manually, since multiple languages are expected to be supported.
The question
How can I get Backend to be able to load the information from the public/locales folder, exactly the same as it does in the live app, so that i18n functionalities are working as expected?
Maybe should I mock the calls to public/locales folder? If so, how can I do so for all tests (I'm using fetch-mock-jest to mock fetch calls).
Thanks!
I am using react-I18next in my nextjs application. I don't want to use next-I18next because I tried to use it but couldn't make it work. But react-i18next is working in my application for now and I am able to change language from english to german and back. However if I reload the page I get this error.
TypeError: i18n.changeLanguage is not a function
What could be the possibel cause of this error and how can I fix it?
P.S In my app.ts file I am not using Suspense because it gives me this error
ReactDOMServer does not yet support Suspense.
Here is my i18.ts file
/* eslint-disable no-duplicate-imports */
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import backend from 'i18next-xhr-backend';
import { initReactI18next } from 'react-i18next';
import loginDE from '../../public/locales/de/loginDE.json';
import loginEN from '../../public/locales/en/loginEN.json';
// the translations
// (tip move them in a JSON file and import them)
const resources = {
en: {
translation: loginEN,
},
de: {
translation: loginDE,
},
};
void i18n
.use(backend)
.use(LanguageDetector)
.use(initReactI18next) // passes i18n down to react-i18next
.init({
fallbackLng: 'en',
interpolation: {
escapeValue: false, // react already safes from xss
},
resources,
lng: 'en',
keySeparator: false, // we do not use keys in form messages.welcome
react: {
useSuspense: true,
},
});
export default i18n;
ReactDOMServer does not yet support Suspense.
Change your useSuspense value like that:
react: { useSuspense: false },
TypeError: i18n.changeLanguage is not a function
Make sure you wrapped a component with I18nextProvider
I have a project written in React & support hooks.
I'm trying to use react-i18next to support translations.
Everything works well as I've follow the documentation.
However I stumble upon some problems when I want to use the t() function on helpers / non-component .js files.
Then, I solved it by importing i18n directly from the init file ./i18n.ts that looks something like this
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
resources,
ns: [
'common',
'dashboard',
'landing'
],
defaultNS: 'common',
fallbackLng: 'en',
supportedLngs: ['de', 'en'],
interpolation: {
escapeValue: false,
},
});
export default i18n;
and I realized that I don't have to use the hook at all since I can just use it like this anywehre across the code, even on my functional component file
import i18n from "#root/i18n"
...
i18n.t('namespace:path')
I would like to know why is it recommended to use the useTranslation hook / withTranslation HOC if you can just import it like this?
I read that useTranslation apply suspense but it seems like the initReactI18next also have suspense applied by default.
I'm curious on if there's any side-effect on not using the recommended hook / HOC ?
I found this answer on their github issues.
But those constants never will be updated on languageChange! So
either:
update them to new language value based on event triggered by i18next: https://www.i18next.com/overview/api#onlanguagechanged
or better have only the keys in the constants and translate as close to the rendering as possible
What i want to achieve is that i have translations available for all components itself. When i install those components they should render on its own. Another thing that i want to achieve is that my project can overrule translations on component level. This in case if somebody decides that the translations that is in there is not what we want.
What i did in my components is loading i18n:
import i18n from 'i18next';
import XHR from 'i18next-xhr-backend';
import Cache from 'i18next-localstorage-cache';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(XHR)
.use(Cache)
.use(LanguageDetector)
.init({
backend: {
loadPath: '../dist/locales/{{lng}}/{{ns}}.json',
},
fallbackLng: 'en',
react: {
wait: true
},
ns: ['authentication'],
defaultNS: 'authentication',
debug: false,
cache: {
enabled: true
},
interpolation: {
escapeValue: false, // not needed for react!!
formatSeparator: ',',
format: function(value, format) {
if (format === 'uppercase') return value.toUpperCase();
return value;
}
}
});
export default i18n;
This is working fine in my storybook but when i load this in my main project, it is using ../ from my build root which is actually not the component itself but my main implementation project.
How can i solve it and how can i ensure that i can even extend this?
UPDATE:
Below a list of the current folder structure like asked in below questions:
#Component
dist
--.gitkeep
--locales
--commonjs
--es
src
--actions
----index.js
--components
----compname
------index.js
--reducers
----foo.js
--i18n.js
--index.js
test
.babelrc
package.json
Jenkinsfile
#Project
react
--assets
----css
------app.scss
--dist
----.gitkeep
--src
----index.js
----store.js
webpack.config.js
Thanks
I've created a React application with create-react-app
I want to implement translations and I've discovered react-i18next
After installing required packages I've setup my i18n.js config file:
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import XHR from 'i18next-xhr-backend';
i18n
.use(XHR)
.use(LanguageDetector)
.init({
debug: true,
lng: 'en',
nsSeparator: false,
keySeparator: false,
fallbackLng: false,
backend: {
loadPath: 'locales/{{lng}}/{{ns}}.json'
}
});
export default i18n;
I'm getting this error: i18next::backendConnector: loading namespace translation for language en failed failed parsing locales/en/translation.json to json
It happens because webpack doesn't find the json file and is returning the index.html file contents instead:
I'm not sure where you put the locale files, but I see two issues:
You have specified a relative URL so you load /kiosk/parents/locales rather than /locales. You need to add a slash at the beginning of the load path.
For Create React App to serve static files, you need to put them into the public folder. This is described in its User Guide in more detail. So make sure locales is inside the public folder in the project root.
Hope this helps!
Just in case anyone needs this like I did:
If you happen to have changed your homepage path in your package.json file like so:
...
"homepage": "/tom/",
...
you also need to add this part to i18n like so:
i18n
.use(XHR)
.use(LanguageDetector)
.init({
debug: true,
lng: 'en',
nsSeparator: false,
keySeparator: false,
fallbackLng: false,
backend: {
loadPath: '/tom/locales/{{lng}}/{{ns}}.json'
}
});
export default i18n;