0👍
This is how I do it – using a single JSON file with all localizations (each localization has a key title
which represents the name of the locale in its corresponding language):
<template>
<pop-over>
<flat-button class="country_selector pl-1 pr-1 pt-0 pb-0 ma-0 font-0 bold">
<div class="current_flag" :style="{'background-image': 'url(' + $root.baseURL + 'flags/' + curLocale + '.png' + ')'}"/>
<div class="flexbox flex-column align-center ml-1">
<icon>
<caret-up/>
</icon>
<span class="upper" style="margin-top: -5px;">{{ $root.locale }}</span>
</div>
</flat-button>
<my-card slot="popover" title-class="popover_header">
<!--
<div slot="title">{{ $t('header.language_selector') }}</div>
-->
<div v-for="lang in $root.languages" :key="lang" v-close-popover class="popup_menu_item flexbox align-center pl-2 pr-2 pt-1 pb-1" @click="changeLocale(lang)">
<icon :size="14" :color="($i18n.messages[$i18n.locale] ? lang === $i18n.locale : lang === 'en') ? '' : 'transparent'">
<icon-checkmark/>
</icon>
<div class="country_flag" :style="{'background-image': 'url(' + $root.baseURL + 'flags/' + lang + '.png' + ')'}"/>
<div class="flex-auto font-1 bold">{{ $i18n.messages[lang].title }}</div>
</div>
</my-card>
</pop-over>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
import iconCheckmark from '@/assets/img/icon/check.svg'
import caretUp from '@/assets/img/icon/caret-up.svg'
export default
{
name: 'LanguageSelector',
components:
{
iconCheckmark,
caretUp,
},
computed:
{
...mapGetters(['curLocale']),
},
methods:
{
...mapMutations(['setLocale']),
changeLocale (langCode)
{
this.setLocale(langCode);
if (!this.$root.isLogged) return;
const data = new FormData();
data.append('language', langCode);
this.$ajax(
{
method: 'POST',
url: '/api/user/setusersettings/',
login: this.$root.login,
data,
}
);
},
}
}
</script>
<style lang="scss">
@import '@/assets/scss/theme/footer.scss';
.current_flag
{
border-radius: 50%;
width: 24px;
height: 24px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.country_flag
{
border-radius: 50%;
width: 22px;
height: 22px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
margin-left: 4px;
margin-right: 4px;
}
.country_selector
{
color: $footer_color;
}
</style>
And the store mutation is
setLocale (state, lang)
{
state.locale = lang;
document.querySelector('html').setAttribute('lang', lang);
if (window.i18n) window.i18n.locale = lang;
},
And Vue-i18n is instantiated like this
import VueI18n from 'vue-i18n'
import locales from "./locales.json";
Vue.use(VueI18n);
window.i18n = new VueI18n(
{
fallbackLocale: 'en',
locale: 'en',
messages: locales,
silentTranslationWarn: true
});
The relevant computed properties in the root Vue instance are
computed:
{
baseURL ()
{
return process.env.BASE_URL;
},
locale ()
{
return this.$i18n.messages[this.$i18n.locale] ? this.$i18n.locale : 'en';
},
languages ()
{
return Object.keys(this.$i18n.messages);
},
}
0👍
I know this is a bit old and you’ve probably already found a solution, but I got here ’cause I had the same problem and found a different approach to solving it, so I’m posting this in case anyone else has the same issue.
I made a folder called locales
in my src
folder which looks something like:
|--- src
|--- locales
|--- en-GB.json
|--- fr-FR.json
|--- de-DE.json
My i18n.js
file looks like this:
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({
// These two lines are in case you want to setup environmental variables
//locale: process.env.VUE_APP_I18N_LOCALE || 'en-GB',
//fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en-GB',
locale: 'en-GB',
fallbackLocale: 'en-GB',
messages: loadLocaleMessages()
})
Then I put it in my main.js
import Vue from 'vue'
import App from './App.vue'
import i18n from './i18n'
Vue.config.productionTip = false
new Vue({
i18n,
render: h => h(App)
}).$mount('#app')
Here comes my trick (don’t know if it’s considered a hack or anything, but it makes things simpler for me):
<select v-model="$i18n.locale">
<option v-for="(lang, i) in $i18n.locale" :key="`Lang${i}`" :value="lang"
v-on:click="$i18n.locale=lang">
<img :src="require(`../assets/images/${lang}.png`)"></img>
</option>
</select>
In order for the above code to work, make sure the names of the images are the same as the locale
files, i.e. if your language file is called fr.js
, the image should be called fr.png
, and in my case, the image is called en-GB.png
.
The v-on:click
, will change your currently selected language. I’ve used require()
, because in my case, it won’t show the images without it (because of webpack
if I’m not mistaken) – but you might not needed it. Test and see.
Hopefully this helps someone. Cheers!
- [Vuejs]-Full-Calendar Vue refetch-events error? nothing appears to happen
- [Vuejs]-Vuejs passing arguments with a routes href link