Vue-i18n - Cannot read property 'config' of undefined - vue.js

First of all I show you what works (in App.js)
import router from './routes.js';
import VueI18n from 'vue-i18n';
const messages = {
en: {
message: {
hello: 'hello world'
}
}
}
// Create VueI18n instance with options
const i18n = new VueI18n({
locale: 'en', // set locale
messages, // set locale messages
})
const app = new Vue({
el: '#app',
router,
i18n
});
But if I want to separate the code in lang.js
import VueI18n from 'vue-i18n';
const messages = {
en: {
message: {
hello: 'hello world'
}
}
}
export default new VueI18n({
locale: 'en', // set locale
messages, // set locale messages
});
So that I can write in App.js
import router from './routes.js';
import i18n from './lang.js';
const app = new Vue({
el: '#app',
router,
i18n
});
But somehow this doesn't work even though routes.js is built exact the same.
My bootstrap.js looks like that, if it is important to know.
import Vue from 'vue';
window.Vue = Vue;
import VueRouter from 'vue-router';
import VueI18n from 'vue-i18n';
Vue.use(VueRouter);
Vue.use(VueI18n);
I'm sorry for the long code, but somehow the mistake lies in import i18n from './lang.js';
I get the message: Uncaught TypeError: Cannot read property 'config' of undefined

In your main file where you create the app instance add the i18n as option instead of Vue.use(Vuei18n) like this:
new Vue({
el: '#app',
i18n, // < --- HERE
store,
router,
template: '<App/>',
components: { App }
})
Put it just after el;
And this should be your lang:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import en from './en'
import fr from './fr'
import ro from './ro'
Vue.use(VueI18n)
export default new VueI18n({
locale: 'en',
fallbackLocale: 'en',
messages: {
en, fr, ro
}
})

Just to add a detail, you MUST construct the new VueI18n after using Vue.use(VueI18n)
Vue.use(VueI18n);
// must be called after vue.use
const i18n = new VueI18n({
locale: "en",
fallbackLocale: "en",
messages: {
en
}
});
new Vue({
el: "#app",
i18n,
render: (h) => h(App),
});

The idea of code separation can be implemented this way
/* i18n.ts */
import VueI18n from "vue-i18n";
import en from "./locales/en.json";
// Export as an arrow function
export default () =>
new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || "en",
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en",
messages: { en }
});
/* plugins.ts */
import Vue from "vue";
// Plugins
import VueI18n from "vue-i18n";
import i18n from "./i18n";
Vue.use(VueI18n);
export default {
i18n: i18n()
};
And finally, the main.ts
/* main.ts */
import Vue from "vue";
import plugins from "./core/plugins";
import App from "./App.vue";
new Vue({
...plugins,
render: (h) => h(App)
}).$mount("#app");
The trick is using arrow functions when exporting i18n settings. It's worth mentioning that this problem does not occur with some other Vue plugins.

Related

Load i18n for all components Vue3

When using vue-i18n, I need to add this to every single component:
setup() {
const { t, locale } = useI18n();
return { t, locale };
}
Is there any way to preload the t function to all my components?
You can load and switch languages as below.
in i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
function loadLocaleMessages () {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key)
}
})
return messages
}
const locale = localStorage.getItem('language') || 'tr'
export default new VueI18n({
locale: locale,
fallbackLocale: locale,
messages: loadLocaleMessages()
})
in main.js
import i18n from './i18n'
new Vue({
el: "#app",
router,
store,
i18n,
render: h => h(App),
})
createI18n() creates a Vue plugin that makes vue-i18n available globally for all components:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { createI18n } from 'vue-i18n'
const i18n = createI18n(/*...*/)
createApp(App).use(i18n).mount('#app')
t is then available in the template as $t, and locale is $i18n.locale.
demo

vue-i18n not use vuetify components strings

i try to use vue-i18n to translate my application. I use also vuetify and the vue cli.
At the moment i have the languages englisch and german.
Here is my project structure and code.
main.js
import Vue from "vue";
import i18n from "./plugins/i18n";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
new Vue({
vuetify,
i18n,
render: (h) => h(App),
}).$mount("#app");
plugins/i18n.js
import Vue from "vue";
import VueI18n from "vue-i18n";
import de from "#/locale/de";
import en from "#/locale/en";
Vue.use(VueI18n);
const messages = {
de: de,
en: en,
};
const i18n = new VueI18n({
locale: "de",
fallbackLocale: "en",
messages,
});
export default i18n;
locale/en.js
export default {
hello: "hello",
};
locale/de.js
export default {
hello: "Hallo",
$vuetify: {
dataIterator: {
rowsPerPageText: "Einträge pro Seite:",
pageText: "{0}-{1} von {2}",
},
}
};
plugins/vuetify.js
import Vue from "vue";
import Vuetify from "vuetify/lib/framework";
import i18n from "./i18n";
Vue.use(Vuetify);
export default new Vuetify({
lang: {
t: (key, ...params) => i18n.t(key, params),
},
});
All works fine with the hello translation, but the vuetify components not working as expected.
I would like to add a translation to german for few vuetify components in the future.
But at the moment a would like to use the original names from vuetify. And that is not working.
For example, the v-select component looks like:
And other components also not working.
What i do wrong?
You are missing default vuetify component locales. you should provide it by rewriting them in your locales or import it at the beginning of each locale file.
locale/en.js
import { en } from 'vuetify/lib/locale'
export default {
$vuetify: { ...en },
hello: "hello",
};
locale/de.js
import { de } from 'vuetify/lib/locale'
export default {
hello: "Hallo",
$vuetify: {
...de,
dataIterator: {
rowsPerPageText: "Einträge pro Seite:",
pageText: "{0}-{1} von {2}",
},
}
};

Translate whole component via i18n in vuejs

I want to translate my whole component with i18n and I don't know how to use $t() in this use case. I have data like this
[
{"prizeCount":"300","prizeSum":"2442000","gameStartAt":"2018-01-08 13:00:00.000000"},
{"prizeCount":"288","prizeSum":"2530000","gameStartAt":"2018-01-09 12:00:00.000000"}
]
I pass this data to :items="mydata" for table and I want to translate title of my fields for example I want to translate prizeCount to another language.
I am using vue-bootstrap.
What is the best solution for this?
main.js:
import Vue from 'vue'
import App from './App'
import router from './router'
import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import i18n from './i18n'
Vue.config.productionTip = false
Vue.use(BootstrapVue)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {
App
},
i18n,
template: '<App/>'
})
You can add it like this:
new Vue({
el: '#app',
router,
components: {
App
},
i18n,
t: i18n.t,
template: '<App/>'
})
Than in your component you can use $t or this.$t in your methods.
For get keys from your object you can do like this:
data: [
{"prizeCount":"300","prizeSum":"2442000","gameStartAt":"2018-01-08 13:00:00"},
{"prizeCount":"288","prizeSum":"2530000","gameStartAt":"2018-01-09 12:00:00"}
]
data.forEach( obj => {
let keys = Object.keys(obj)
// ['prizeCount', 'prizeSum', 'gameStartAt']
newData = []
newObj = {}
keys.forEach( key => {
let val = obj[key]
let trans = this.$t(key)
newObj[trans] = val
})
newData.push(newObj)
})

Get current locale in a child component

I don't manage to get the locale parameter from vue-i18n in my child component.
I've installed vue-i18n in cli ui. The translation with $t("message") is working but I have error when i try to access to i18n.locale
my enter point (main.js)
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import i18n from './i18n'
new Vue({
router,
i18n,
render: h => h(App)
}).$mount('#app')
my child component
<template>
<div>{{ $t("message") }}</div>
</template>
<script>
import {HTTP} from '#/http-common'
export default
{
name : 'c1',
methods:{
selectMap()
{
console.log(i18n.locale);//=> doesn't work
}
}
</script>
i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
function loadLocaleMessages () {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key)
}
})
return messages
}
export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
messages: loadLocaleMessages()
})
Try this.$i18n.locale, or just $i18n.locale if inside the <template>.
For Composition API this is my solution:
<script setup>
import { useI18n } from "vue-i18n";
const i18nLocale = useI18n();
console.log(i18nLocale.locale.value); // "en"
</script>

Vuejs - How to call the mounted function of main.js from another Js file

This is the code I have given in commonValidation.js.
commonValidation.js:
this.$validator.localize('en', {
messages: {
required: (field) => '* ' + field + ' is required'
},
attributes: {
email: 'Email'
}
})
I want to call the above file in main.js inside the mounted function
like below. But it's not working. If I given those validation(from commonValidation.js) inside the mounted()(in main.js) method it's working.
main.js:
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'
import App from './App'
import router from './router'
import VeeValidate from 'vee-validate';
import commonValidation from './commonValidation'
Vue.use(VeeValidate);
Vue.use(BootstrapVue);
new Vue({
el: '#app',
router,
template: '<App/>',
components: {
App
},
mounted()
{
commonValidation
}
})
Please help me to call the commonValidation.Js inside the mounted() in main.js . Thanks in advance.
This is my complete commonValidation.js
export default {
mounted() {
this.$validator.localize('en', {
messages: {
required: (field) => '* ' + field + ' is required'
},
attributes: {
email: 'Email'
}
})
}
}
You are exporting an object in commonValidation.js file.
An object cannot be invoked like a function.
I think your intent is to use a mixin. A mixin is nothing but an object that contains reusable component options as its properties.
So just register the mixin on the root component in your main.js file:
//main.js
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'
import App from './App'
import router from './router'
import VeeValidate from 'vee-validate';
import commonValidation from './commonValidation'
Vue.use(VeeValidate);
Vue.use(BootstrapVue);
new Vue({
el: '#app',
router,
template: '<App/>',
components: {
App
},
mixins : [commonValidation]
}