Getting ChunkLoadError: Loading chunk when lazy laoding Translation in vuejs - javascript

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.

Related

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.

React i18next return a fallback language

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;

How to extend core modules of Vue Storefront

I want to override an action from cart module store. I am trying to extend this CartModule by following this link
Extending and Overriding Modules Doc
I have created a file /src/modules/cart/index.ts with following code
import { VueStorefrontModuleConfig, extendModule, VueStorefrontModule } from '#vue-storefront/core/lib/module'
import { CartModule } from '#vue-storefront/core/modules/cart'
import { cartModule } from './store'
const cartExtend: VueStorefrontModuleConfig = {
key: 'cart',
store: {modules: [{key: 'cart', module: cartModule}]},
afterRegistration: function () {
console.log('Cart module extended')
}
}
extendModule(cartExtend)
export const registerModules: VueStorefrontModule[] = [CartModule]
I am getting error that CarModule type does not match with VueStorefrontModule
Also I don't know what to do next in order to make it effective. Docs are not clear about it. Please help. Thanks
If you want to overwrite action of module you don't want to extend module but store.
Here is example:
Vuestorefront has CartModule (in core) and you need to change code of action refreshTotals.
Code your in file /src/modules/cart/index.ts:
import {StorefrontModule} from '#vue-storefront/core/lib/modules';
import {extendStore} from '#vue-storefront/core/helpers';
const cartModule = {
action: {
async refreshTotals({dispatch}, payload) {
//
// your new (and better!) code ;-)
//
}
},
}
export const MyAwesomeCart: StorefrontModule = function () {
extendStore('cart', cartModule);
}
In last step register this your new module under /src/modules/client.ts:
..
...
import {CartModule} from '#vue-storefront/core/modules/cart';
import {MyAwesomeCart} from "modules/cart/index";
export function registerClientModules() {
registerModule(CartModule); // original module
registerModule(MyAwesomeCart); // your new overwiritng module
...
..

Angular2 / Electron application using electron API within the angular2 ts files

I have setup an angular2 / Electron app similar to the explanation in this video : https://www.youtube.com/watch?v=pLPCuFFeKOU. The project I am basing my code on can be found here : https://github.com/rajayogan/angular2-desktop
I am getting the error:
app.ts:16Uncaught TypeError: Cannot read property 'on' of undefined
When I try to run this code:
import { bootstrap } from '#angular/platform-browser-dynamic';
import { Component } from '#angular/core';
import { MenuComponent} from './menu';
import { ConfigEditorComponent } from './config-editor';
import { remote, ipcRenderer} from 'electron';
let {dialog} = remote;
//Functions used for select server xml callbacks.
const ipc = require('electron').ipcMain
const xml2js = require('xml2js')
const fs = require('fs')
var parser = new xml2js.Parser();
ipc.on('open-file-dialog', function (event) {
dialog.showOpenDialog({
title:"Select zOS Connect server.xml",
properties: ['openFile', 'openDirectory'],
filters: [
{name: 'XML', extensions: ['xml']},
{name: 'All Files', extensions: ['*']}
]
}, function (files) {
if (files){
fs.readFile(files[0], function(err, data) {
parser.parseString(data, function (err, result) {
console.dir(result);
process_server_xml(event,result);
})
})
}
})
})
function process_server_xml(event,json){
console.log("oh hello!")
event.sender.send('selected-directory', json)
console.log("oh im done!")
}
#Component({
selector: 'connect-toolkit',
templateUrl: 'app.component.html',
directives: [ MenuComponent, ConfigEditorComponent ]
})
export class AppComponent {
constructor() {
var menu = remote.Menu.buildFromTemplate([{
label: 'Raja',
submenu: [
{
label: 'open',
click: function(){
dialog.showOpenDialog((cb) => {
})
}
},
{
label: 'opencustom',
click: function(){
ipcRenderer.send('open-custom');
let notification = new Notification('Customdialog', {
body: 'This is a custom window created by us'
})
}
}
]
}])
remote.Menu.setApplicationMenu(menu);
}
}
bootstrap(AppComponent);
I think the problem may be:
const ipc = require('electron').ipcMain
const xml2js = require('xml2js')
const fs = require('fs')
var parser = new xml2js.Parser();
Is it possible require doesn't work here, and somehow I need to use import statements instead from my ts files? If this is the case how do I use the import in order to get the ipcMain object and my xml2js etc?
Why would that be the case? How can I make require work within the ts files if this is the problem.
Note that if I remove the require lines, and all the ipc.on code everything runs as expected and works fine (other than the fact that the ipc event is never received ;)
Calling ipcMain doesn't work because you're not on main (i.e., the electron side code, which is on electron index.js file), your are on renderer (web page). Therefore you must use ipcRenderer instead, which is already imported using es6 import syntax on top of your app.ts file. And if you want to make something using electron ipcMain, it have to be done from the electron code side.
import {remote, ipcRenderer} from 'electron';
Electron ipc notes:
ipcMain Communicate asynchronously from the main process to renderer processes.
ipcRenderer Communicate asynchronously from a renderer process to the main process.

Categories

Resources