Closed thelinuxlich closed 8 years ago
@nickkuijpers yep it seems to work for me. Thanks for sharing @ssc-hrep3's elegant solution @TheBroox. I used your snippet :)
I think the Elegant Solution is
Within the same component, you can path the language value to a method that switches in the global range through this. $ I18n.locale = value
</template>
<button @click="setLanguage('en')">en</button>
<button @click="setLanguage('de')">de</button>
<button @click="setLanguage('fr')">fr</button>
</template>
<script>
export default {
....
methods: {
setLanguage (val) {
this.$i18n.locale = val
}
}
}
</script>
it will update language without refresh page or reload or redirect.
const app = new Vue({
el: '#app',
mounted() {
Vue.config.lang = document.querySelector("html").lang
}
});
In my case, Laravel takes care of filling up the 'lang' attribute in html so I see no reason to make this any more complicated.
If you are looking for a completely js solution that can be set on page load via query string param as well as offering buttons to the user.
<template>
<button v-for="lang in notCurrentLangs" :key="lang.file" @click="changeLang(lang.key)">
{{lang.name}}
</ui-button>
</template>
<script>
export default {
name: 'Localization',
data(){
return {
langs: [
{key: 'en', name: 'English'},
{key: 'sp', name: 'Spanish'},
{key: 'fr', name: 'French'},
{key: 'ho', name: 'Hodor', hidden: true}
]
}
},
computed: {
notCurrentLangs(){
var currentLang = this.$locale.current()
return this.langs.filter(function(lang){
return lang.key !== currentLang && !lang.hidden
})
}
},
methods : {
changeLang: function(newLang){
this.$locale.change(newLang)
},
hasLang: function(checkKey) {
var hasLang = false
this.langs.forEach(function(lang){
if(lang.key === checkKey){
hasLang = true
}
})
return hasLang
}
},
created(){
if(this.$route.query.lang && this.hasLang(this.$route.query.lang)){
this.changeLang(this.$route.query.lang)
}
}
}
</script>
@EmadAdly I tried your code as it's very similar to the one in the docs.
I can change the locale with this.$root.$i18n.locale = val
, but all components update only after the next page change. until then nothing happens.
Any idea how I can force an "update"?
PS: Everything inside this components changes, but other components stay the same. Until I change the page.
Well, seems like I used the translations in a wring way. I set some data props, but those do not get updated. So I guess the best way to use the translations is to always do it in the template.
@janein sorry for that , val must be stored in local storage So add this line inside the setLanguage method
setLanguage (val) {
this.$i18n.locale = val
window.localStorage.setItem('Language', val)
}
and in main.js read locale from local storage like the below
const i18n = new VueI18n({
locale: window.localStorage.getItem('userLanguage'), // get locale
messages // set locale messages
})
If you want to do it inside a component:
selectLanguage(lang) {
this.$root.$i18n.locale = lang;
window.localStorage.language = lang;
},
If you want to use in vuex, so you can easily access/watch in other components:
// i18n.js
import Vue from 'vue';
import VueI18n from 'vue-i18n';
Vue.use(VueI18n);
export default new VueI18n({
locale: window.localStorage.language || navigator.language || 'en',
});
// store.js
import i18n from '../i18n';
mutations: {
[SET_LANGUAGE](state, payload) {
state.language = payload.data;
i18n.locale = payload.data;
window.localStorage.language = payload.data;
},
},
actions: {
setLanguage: ({ commit }, data) => {
commit(SET_LANGUAGE, { data });
},
},
@EmadAdly @longprao Thanks, your approach looks nice. I got another solution in the meantime. As I work with vuex I wanted to have a centralized solution to get/set the language. I handle all my communication with the localStorage in a separate file, whose methods get called from my vuex-store's actions. To get my language a again on restart I do something like this:
/* main.ts */
import store from './store';
const app = new Vue({
// ...
store
});
store.dispatch('settings/loadSettings');
/* store/settings/actions.ts */
export const loadSettings = (state) => {
return SettingsApi.fetchSettings().then((res) => {
state.commit('loadSettings', res);
});
};
/* api/settings-api.ts */
namespace SettingsApi {
export const fetchSettings = () => {
return localforage.startsWith(STORAGE_PREFIX).then(async (settings): Promise<SettingsState> => {
settings = stripSettingsPrefix(settings);
// merge with default settings
const allSettings = (Object as any).assign({}, defaultSettings, settings);
await saveAllSettings(allSettings);
return allSettings;
});
};
export const saveAllSettings = async (settings) => {
for (const setting of Object.keys(settings)) {
const value = settings[setting];
await saveSetting(setting, value);
}
return settings;
};
export const saveSetting = (key, value) => {
if (key === 'language') {
(window as any).app.$root.$i18n.locale = value;
}
return localforage.setItem(STORAGE_PREFIX + key, value)
.then((val) => val)
.catch((err) => {
console.warn(`
oooops ${key} with the value "${value}" could not be saved to the local storage! :(
`, err);
});
};
}
This works pretty neat as it handles all settings and not just the language. And it is fast too, so you don't get a delay where you can see the language switch fron the default language to the saved one. Maybe this helps someone who tries so achieve something similar :)
What if I want to reload the page to receive new content based on the user language and also I want to change the stylesheet file based on it?
@ealves-pt @longprao
Your ideas were helpful.
i solve the problem and i didn't use VueX
// lang.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
let i18n = new VueI18n({
messages: {}
})
let setLocale = function (locale) {
if (locale === undefined) {
i18n.locale = window.localStorage.language || navigator.language || 'en'
}
else {
i18n.locale = locale
}
try {
if (!i18n.messages[i18n.locale]) {
let addMessage = require('../message-' + i18n.locale + '.json')
i18n.mergeLocaleMessage(i18n.locale, addMessage)
}
window.localStorage.language = i18n.locale
}
catch (error) {
}
}
export default {i18n, setLocale}
// main.js
import 'babel-polyfill'
import Vue from 'vue'
import Quasar from 'quasar'
import lang from 'util/lang'
Vue.use(Quasar) // Install Quasar Framework
Quasar.start(() => {
Vue.mixin({
data: () => {
return {
lang: lang
}
}
})
new Vue({
el: '#q-app',
store,
router,
i18n: lang.i18n,
render: h => h(require('./App')),
created: function () {
this.lang.setLocale()
}
})
})
I use another solution for setting language (in main.js): `function checkLang () { var navigatorLang = navigator.language || navigator.userLanguage var langList = ['ru', 'en'] var fallbackLang = 'en' var settingLang = langList.includes(navigatorLang) ? navigatorLang : fallbackLang var lang = window.localStorage.getItem('userLang') return lang.length > 0 ? lang : settingLang }
const i18n = new VueI18n({ locale: checkLang(), fallbackLocale: 'en', dateTimeFormats: 'long' })`
In my vue component file I have a method that can change. Just tested this and it was reactive to change it from en to fr and the UI updated straight away.
change: function () {
this.$i18n.locale = 'fr';
}
I am doing this
router.beforeEach((to, from, next) => {
// possible entry points where language should be set
let entryPoints = ["login", "token"];
if (entryPoints.includes(to.name)) {
console.log("Setting locale from supported entry points")
let languageQuery = to.query.locale || "en";
i18n.locale = languageQuery;
// This will allow us to use it later
window.localStorage.setItem('locale', languageQuery);
Cookies.set('locale', languageQuery);
} else {
console.log("Setting locale from localStorage or Cookies");
i18n.locale = window.localStorage.getItem('locale') || Cookies.get('locale');
}
})
this.$i18n.locale = 'your locale'
How to do this in vue3 composition api
and vue-i18n@9
, there is no this.$i18n
@roelvan it worked for me but after upgrading to i18n 6.0+ I have switched to @ssc-hrep3's solution. It still extends the prototype but the altered values are slightly different.
My i18n file:
And then how I incorporate it into a template: