React i18next return a fallback language - javascript

I'm using i18next in my React app in this way to translate files:
i18next.js (original)
import i18next from 'i18next';
import XHR from 'i18next-xhr-backend';
import detector from 'i18next-browser-languagedetector';
window.userLang = navigator.language || navigator.userLanguage;
i18next
.use(detector)
.use(XHR)
.init({
lng: window.userLang,
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false,
},
});
export default i18next;
Using the code above, I am able to successfully translate pages based on the user's browser data. If the language is not available, it falls back to English as intended.
However, I ran into some components which were not translated into the keys provided. They are set up in the following way in the menu component:
Menu Component
const projectArchives = i18next.t('LEFT_MENU.projectArchives');
export default {
[KEY_ARCHIVE_MODEL]: {
en: projectArchives,
it: projectArchives,
},
Output in browser:
LEFT_MENU.projectArchives
I changed my i18next.js file to have a variable (var data =) which would get the language from a string:
i18next.js (Updated)
import i18next from 'i18next';
import XHR from 'i18next-xhr-backend';
import detector from 'i18next-browser-languagedetector';
window.userLang = navigator.language || navigator.userLanguage;
let language = window.userLang.split('-')[0];
var data = require(`../../public/locales/${language}/translation.json`);
const FALLBACK_LOCALE = 'en';
i18next
.use(detector)
.use(XHR)
.init({
lng: window.userLang,
fallbackLng: FALLBACK_LOCALE,
debug: true,
resources: {
otherLanguages: FALLBACK_LOCALE,
it: {
translation: data,
},
en: {
translation: data,
},
},
});
export default i18next;
Now, the menu is able to display the translated keys but now, if a language is not available as in the original code, the following error is returned:
Error: Cannot find module './fr/translation.json'.
because there is ofcourse there is not an available French translation file.
The error occurs because of the following line:
var data = require(`../../public/locales/${language}/translation.json`);
I've tried connecting the FALLBACK_LOCALE variable directly to the English translation file but this also failed.
var FALLBACK_LOCALE = require(`../../public/locales/en/translation.json`);
How can I force the fallback language or create a conditional for the expected behavior?

import i18next from 'i18next';
import XHR from 'i18next-xhr-backend';
import detector from 'i18next-browser-languagedetector';
window.userLang = navigator.language || navigator.userLanguage;
let language = window.userLang.split('-')[0];
const FALLBACK_LOCALE = 'en';
i18next
.use(detector)
.use(XHR)
.init({
lng: window.userLang,
fallbackLng: FALLBACK_LOCALE,
debug: true,
resources: {
otherLanguages: FALLBACK_LOCALE,
it: {
translation: require(`../../public/locales/it/translation.json`),
},
en: {
translation: require(`../../public/locales/en/translation.json`),
},
},
});
export default i18next;

Related

Getting ChunkLoadError: Loading chunk when lazy laoding Translation in vuejs

I am trying to implement Lazy load translations for my Vuejs application and following this guide: https://kazupon.github.io/vue-i18n/guide/lazy-loading.html
Any help will be much appreciated. Thanks In Advance!
File structure is something like this:
src/translations
-- AllMessages.ts
-- bg-BG.json
-- da-DK.json
-- en.json
....... more json files here
my i18n.ts file:
import Vue from "vue";
import VueI18n from "vue-i18n";
// import { allMessages } from "#/translations/allMessages";
Vue.use(VueI18n);
const selectedLanguage: any = 'en' || something.language.split("-")[0];
const loadedLanguages = ["en"];
const getLanguageMessage = async () =>
await import(/* webpackChunkName: "selectedLanguage-[request]" */ `#/translations/${selectedLanguage}.json`);
const messages: any = { [selectedLanguage]: getLanguageMessage() };
console.log("messages", messages); // this promise is rejected, I see in the console
const i18n = new VueI18n({
locale: selectedLanguage, // "en",
fallbackLocale: "en",
messages: messages, // set locale messages
});
console.log("i18n-message", i18n.messages);
export default i18n;
In my console I am getting error:
Probaria cambiar el import por un fetch.

how to incorporate API data in i18next instead of static file

I have saved file in public folder in react for different language for translation. now I have requirement to get that data from API. I am able to call API and get data. I also know how to use translation. but I am not able to incorporate API call in translation code file.
API.
axios
.get(
'http://localhost:8080/file_download/' +
navigator.lnaguage
)
.then((res) => {
console.log(res.data);
});
});
}
Below is my translation code fr static files.
for ex in TRANSLATIONS_FR I need to store output of API.
i18file.js:-
import i18next from 'i18next';
const LanguageDetector = require('i18next-browser-languagedetector');
const initReactI18next = require('react-i18next');
import xios from 'axios';
import { TRANSLATIONS_FR } from './../public/locales/fr/fr.js';
import { TRANSLATIONS_EN } from '../public/locales/en/en.js';
i18next
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
en: TRANSLATIONS_EN,
fr: TRANSLATIONS_FR,
},
fallbackLng: 'fr',
});
i18next.changeLanguage(navigator.language);
export default i18next;
I have to insert that API code into i18file.js file. if browser detecting en then I have to call for english and assign in resources. if browser detecting frech then I have to do for same.
Could you please suggest. I will write the code.
Edit1:-
I am writing below code and it is throwing error.
Below API will send the json data from database. this data I am not storing in file but directly using.
http://localhost:8080//file_download/en
Below is the code
import i18next from 'i18next';
import Backend from 'i18next-http-backend';
const LanguageDetector = require('i18next-browser-languagedetector');
const initReactI18next = require('react-i18next');
i18next
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
backend: {
loadPath: 'http://localhost:8080//file_download/en' //this is API path which will return result.
},
resources: {
en:res.data //I need to assign here.
},
fallbackLng: 'fr',
});
i18next.changeLanguage(navigator.language);
export default i18next;
How can I incorporate the API in above code and use its data for eg in en language.
Updated
As await at top level is not supported
I would suggest to use another plugin i18next-http-backend as i18next has mentioned here
You need to install the plugin first npm i i18next-http-backend
Then just define the backend. There are some examples here
// import { TRANSLATIONS_FR } from './../public/locales/fr/fr.js';
// import { TRANSLATIONS_EN } from '../public/locales/en/en.js';
import Backend from 'i18next-http-backend';
i18next
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
backend: {
loadPath: 'http://localhost:8080/file_download/{{lng}}/{{ns}}.json'
}, // your backend options.
// More info here: https://github.com/i18next/i18next-http-backend
resources: {
en,
fr
},
fallbackLng: 'fr',
});
i18next.changeLanguage(navigator.language);
export default i18next;
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import backend from 'i18next-http-backend';
import api from "../api";
var lang=navigator.language;
let loadResources= apiDelegate.getTranslations(lang);
const backendOptions = {
loadPath: 'http://localhost:8080/code/'+lang,
request: (options, url, payload, callback) => {
try {
loadResources.then((result) => {
callback(null, {
data: result,
status: 200,
});
});
} catch (e) {
console.error(e);
callback(null, {
status: 500,
});
}
},
};
i18n
.use(LanguageDetector)
.use(backend)
.init({
backend: backendOptions,
fallbackLng: "fr",
debug: false,
load:"languageOnly",
ns: ["translations"],
defaultNS: "translations",
keySeparator: false,
interpolation: {
escapeValue: false,
formatSeparator: ","
},
react: {
wait: true
}
});
i18n.changeLanguage(navigator.language);
export default i18n;
you don't need to write http://localhost:8080 as prefix of your get URL. just an / refers to public folder.
just change your axios URL in API file to :
axios
.get(
'/file_download' +
navigator.lnaguage
) + '.json' // or any other format that your language file is
.then((res) => {
console.log(res.data);
});
});
}
There's a great article explaining exactly how to adapt your code to load the translations via api here: https://dev.to/adrai/how-to-properly-internationalize-a-react-application-using-i18next-3hdb#separate
It introduces the i18next-http-backend module, shows you where to place the translation files:
and how to adapt the code:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
i18n
// i18next-http-backend
// loads translations from your server
// 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({
debug: true,
fallbackLng: 'en',
interpolation: {
escapeValue: false // not needed for react as it escapes by default
}
});
export default i18n;
The full example can be found here.
—-
Alternatively, you can also lazy load the translations like this: https://github.com/i18next/i18next-resources-to-backend#you-can-also-lazy-load-the-in-memory-translations-ie-when-using-webpack
btw: i18next-http-backend is also able to inject a custom request function:
https://github.com/i18next/i18next-http-backend#backend-options
like here: https://github.com/i18next/i18next-http-backend/issues/34#issuecomment-729908814

vue3 i18n lazy loading not loading text

I have installed i18n in vue 3 https://vue-i18n.intlify.dev/introduction.html and I want to load the json files lazy.
In the app.js
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: 'en',
fallbackLocale: 'en'
})
const app = createApp(App)
app.use(i18n)
app.mount('#app');
In the main component I have a select
<select class="form-control" #change="onChangeLocale" v-model="selectedLocale">
<option v-for="locale in availableLocales" :key=`locale-${locale}` :value="locale" v-text="locale.toUpperCase()">
</select>
and a text
{{ $t("hello_world") }}
which is in every files in locales (en.json, ro.json, de.json)
ex for en.json
{
"hello_world": "Hello World"
}
In setup
setup() {
const {t, locale, i18n} = useI18n({useScope: 'global'})
const selectedLocale = ref(locale.value)
const availableLocales = ref(['en', 'ro', 'de'])
const onChangeLocale = async () => {
const messages = await import(
/* webpackChunkName: "locale-[request]" */ `../../locales/${selectedLocale.value}.json`
)
// set locale and locale message
i18n.setLocaleMessage(selectedLocale.value, messages.default)
}
}
When loadin the app i see the key for the text "hello_world" - with the message in console (not found "hello_world" key in "en" locale messages) and when changing the select for another language I get en error - cannot read property of undefined (reading 'setLocaleMessage)'
Any idea what I did wrong ?
If setting the messages in app.js like this:
const messages = {
en: {
hello_world: 'Hello World'
},
de: {
...
}
}
then set the messages in i18n options it works.
But I want to load the json files with the translations when selecting the language
https://vue-i18n.intlify.dev/guide/advanced/lazy.html
Any idea ?
*** UPDATE ***
It seems to work after making some changes:
load default language en.json in app.js
import enLocaleMessages from './locales/en.json'
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: 'en',
fallbackLocale: 'en',
messages: {en: enLocaleMessages} // the new change
})
in the component where the locale changes
const {t, locale, setLocaleMessage} = useI18n({useScope: 'global'})
const onChangeLocale = async () => {
const messages = await import(
/* webpackChunkName: "locale-[request]" */ `../../locales/${selectedLocale.value}.json`
)
setLocaleMessage(selectedLocale.value, messages.default)
locale.value = selectedLocale.value
document.documentElement.lang = selectedLocale.value
axios.defaults.headers.common['Accept-Language'] = locale.value
}
I am not sure if it's the correct way ....but for the moment works.

i18next load json from api using i18next-xhr-backend

I try to load a translation JSON file from API in React Native and parse it but it seems that load does not work because the parse method never invokes.
function initI18Next(onInit) {
return (
i18n
.use(initReactI18next)
.use(XHR)
.init({
...initOptions,
backend : backendOptions
}).then(onInit())
)}
initOptions :
export const initOptions = {
fallbackLng : 'es',
defaultNS : 'translation',
lng : 'es',
debug: true,
keySeparator : false,
initImmediate: false,
preload : ['en', 'es'],
react: {
wait: true,
useSuspense: false
},
interpolation: {
escapeValue: true // not needed for react as it escapes by default
},
resources : i18nResources
}
backend options :
export const backendOptions = {
loadPath: 'http://www.mocky.io/v2/5ecd0fe73200006400236655.json',
parse(data) {
console.log('data', data);
return data;
}
};
i18next-xhr-backend is deprecated, use i18next-http-backend instead...
Then try to set i18next debug option to true and have a look at the developer console logs.
Btw: the load path looks strange to me. It should be more like this: https://github.com/i18next/i18next-http-backend#backend-options

Use i18next with XHR backend in client-side javascript

The documentation at i18next-xhr-backend tells me to use import to load their module. But when I use the import-statement, nothing happens and Firefox gives me a SyntaxError in the developer console:
SyntaxError: import declarations may only appear at top level of a module
So how can I use i18next library with the XHR-backend? The following code example works if the .use(XHR)-line and the corresponding import is commented out (Warning: i18next::backendConnector: No backend was added via i18next.use. Will not load resources.). But it fails, if it is not: ReferenceError: XHR is not defined
//import Fetch from 'i18next-fetch-backend';
let t = null;
i18next
.use(XHR)
.init({
debug: true,
fallbackLng: ['en'],
preload: ['en'],
ns: 'translation',
defaultNS: 'translation',
keySeparator: false, // Allow usage of dots in keys
nsSeparator: false,
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json',
},
}, (err, _t) => {
if (err) {
reject(err);
return;
}
t = _t;
//resolve();
});
jqueryI18next.init(i18next, $, {
tName: 't', // --> appends $.t = i18next.t
i18nName: 'i18n', // --> appends $.i18n = i18next
handleName: 'localize', // --> appends $(selector).localize(opts);
selectorAttr: 'data-i18n', // selector for translating elements
targetAttr: 'i18n-target', // data-() attribute to grab target element to translate (if different than itself)
optionsAttr: 'i18n-options', // data-() attribute that contains options, will load/set if useOptionsAttr = true
useOptionsAttr: false, // see optionsAttr
parseDefaultValueFromContent: true // parses default values from content ele.val or ele.text
});
$(".nav").localize();
I needed to use i18nextXHRBackend instead of just XHR, since that is the name the class gets loaded as if no loader is used. As the README.md says:
If you don't use a module loader it will be added to window.i18nextXHRBackend
I didn't see that before, and I didn't know that this will happen automatically, but it seems that you have to find that out on your own if not using a module loader. Lesson learned, hopefully this will help some other newbies being stuck on how to use modules in javascript. Therefore, my complete localisation.js looks like this:
$(document).ready(function() {
i18next
.use(i18nextXHRBackend)
.use(i18nextBrowserLanguageDetector)
.init({
debug: true,
backend: {
loadPath: 'locales/{{lng}}/{{ns}}.json',
addPath: 'locales/add/{{lng}}/{{ns}}'
}
}, function(err, t) {
jqueryI18next.init(i18next, $);
$('.translatable').localize();
$('.language-button').click(function() {
i18next.changeLanguage(this.firstElementChild.alt).then(function(t) {
$('.translatable').localize();
$('#signupPassword').pwstrength("forceUpdate");
$('#signupPasswordConfirm').pwstrength("forceUpdate");
});
});
});
});

Categories

Resources