This commit is contained in:
Karel Vendla
2021-04-19 13:23:59 +03:00
parent 2e57464679
commit eb85ab4e1b
12 changed files with 179 additions and 7 deletions

View File

@ -0,0 +1,35 @@
<template>
<b-dropdown v-if="selectedLang" variant="link" size="sm" no-caret right>
<template slot="button-content">
{{ selectedLang.code }}
<i class="material-icons">keyboard_arrow_down</i>
</template>
<template v-for="lang in languages" >
<b-dropdown-item-button @click="langChanged(lang)" :key="lang.code">{{ lang.name }}</b-dropdown-item-button>
</template>
</b-dropdown>
</template>
<script>
import { mapState } from 'vuex';
import { BDropdown, BDropdownItemButton } from 'bootstrap-vue';
export default {
name: 'language-switcher',
i18nOptions: { namespaces: 'language-switcher' },
components: {
BDropdown,
BDropdownItemButton,
},
computed: {
...mapState({
selectedLang: state => state.language.lang,
languages: state => state.language.all,
}),
},
methods: {
langChanged(lang) {
this.$store.dispatch('language/changeLanguage', lang);
},
},
};
</script>

View File

@ -6,6 +6,7 @@
{{ theme === 'dark' ? 'wb_sunny' : 'brightness_2' }}
</i>
</button>
<LanguageSwitcher/>
<div>
<small v-b-tooltip.hover
title="All your data is saved in your browser and not on any server.
@ -39,8 +40,10 @@
<script>
import { mapState } from 'vuex';
import { VBTooltip } from 'bootstrap-vue';
import LanguageSwitcher from './LanguageSwitcher';
export default {
components: { LanguageSwitcher },
directives: {
'b-tooltip': VBTooltip,
},

35
src/config/i18n.config.js Normal file
View File

@ -0,0 +1,35 @@
import Vue from 'vue';
import i18next from 'i18next';
import VueI18Next from '@panter/vue-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import app from '@/main';
import enJson from '../../public/locales/en';
import estJson from '../../public/locales/est';
Vue.use(VueI18Next);
i18next.use(LanguageDetector);
const initialized = i18next.init({
fallbackLng: 'en',
whitelist: ['en', 'est'],
resources: {
en: enJson,
est: estJson,
},
detection: {
order: ['querystring', 'path', 'localStorage', 'navigator'],
lookupQuerystring: 'lang',
caches: ['localStorage'],
checkWhitelist: true,
},
});
initialized.then(() => app.$store.dispatch('language/initLanguage', i18next.language));
const i18n = new VueI18Next(i18next, {
loadComponentNamespace: true,
});
i18n.initialized = initialized;
export default i18n;

View File

@ -6,6 +6,7 @@ import App from '@/App.vue';
import router from '@/router';
import store from '@/store/store';
import VueNotifications from 'vue-notification';
import i18n from './config/i18n.config';
Vue.use(BVModalPlugin);
Vue.use(VueNotifications);
@ -15,6 +16,7 @@ Vue.config.productionTip = false;
const app = new Vue({
router,
store,
i18n,
render: h => h(App),
}).$mount('#app');

View File

@ -1,6 +1,7 @@
import Vue from 'vue';
import Router from 'vue-router';
import store from '@/store/store';
import i18n from '@/config/i18n.config';
Vue.use(Router);
@ -40,4 +41,15 @@ const router = new Router({
routes,
});
router.beforeEach((to, from, next) => {
if (!to.query.hasOwnProperty('lang')) {
i18n.initialized.then(() => {
to.query.lang = i18n.i18next.language;
next(to);
});
} else {
next();
}
});
export default router;

27
src/store/language.js Normal file
View File

@ -0,0 +1,27 @@
import app from '../main';
export default {
namespaced: true,
state: {
lang: null,
all: [
{ name: 'English', code: 'en' },
{ name: 'Estonian', code: 'est' },
],
},
mutations: {
lang(state, lang) {
state.lang = lang;
},
},
actions: {
changeLanguage({ commit }, lang) {
app.$i18n.i18next.changeLanguage(lang.code);
app.$router.push({ query: { ...app.$route.query, lang: lang.code } });
commit('lang', lang);
},
initLanguage({ commit, state }, code) {
commit('lang', state.all.find(lang => lang.code === code));
},
},
};

View File

@ -19,6 +19,7 @@ import teamFields from '@/store/team-fields';
import themes from '@/store/themes';
import taxes from '@/store/taxes';
import data from '@/store/data';
import language from '@/store/language';
import ClientField from '@/store/models/client-field';
import TeamField from '@/store/models/team-field';
import InvoiceClientField from '@/store/models/invoice-client-field';
@ -58,6 +59,7 @@ export default new Vuex.Store({
themes,
taxes,
data,
language,
},
state: {},
mutations: {},

View File

@ -2,7 +2,7 @@
<div>
<div class="row">
<div class="col-12 mb-4 pr-0 d-flex justify-content-between">
<h4 class="mb-0">Invoices</h4>
<h4 class="mb-0">{{ $t('title') }}</h4>
<div>
<button class="btn btn-sm btn-outline-dark" @click="createNewInvoice">New invoice</button>
<b-dropdown variant="link" size="sm" no-caret right>
@ -30,6 +30,7 @@ import InvoicesList from '@/components/invoices/InvoicesList';
export default {
name: 'invoices',
i18nOptions: { namespaces: 'invoices' },
components: {
InvoicesList,
BDropdown,