mirror of
https://github.com/mokuappio/serverless-invoices.git
synced 2025-10-27 16:01:07 -04:00
Merge remote-tracking branch 'origin/main' into main
# Conflicts: # src/main.js
This commit is contained in:
35
src/components/LanguageSwitcher.vue
Normal file
35
src/components/LanguageSwitcher.vue
Normal 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>
|
||||
@ -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
35
src/config/i18n.config.js
Normal 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;
|
||||
@ -7,6 +7,7 @@ import router from '@/router';
|
||||
import store from '@/store/store';
|
||||
import VueNotifications from 'vue-notification';
|
||||
import './registerServiceWorker';
|
||||
import i18n from './config/i18n.config';
|
||||
|
||||
Vue.use(BVModalPlugin);
|
||||
Vue.use(VueNotifications);
|
||||
@ -16,6 +17,7 @@ Vue.config.productionTip = false;
|
||||
const app = new Vue({
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app');
|
||||
|
||||
|
||||
@ -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
27
src/store/language.js
Normal 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));
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -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: {},
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
<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>
|
||||
<button class="btn btn-sm btn-outline-dark" @click="createNewInvoice">{{ $t('new_invoice') }}</button>
|
||||
<b-dropdown variant="link" size="sm" no-caret right>
|
||||
<template slot="button-content">
|
||||
<i class="material-icons">more_vert</i>
|
||||
@ -30,6 +30,7 @@ import InvoicesList from '@/components/invoices/InvoicesList';
|
||||
|
||||
export default {
|
||||
name: 'invoices',
|
||||
i18nOptions: { namespaces: 'invoices' },
|
||||
components: {
|
||||
InvoicesList,
|
||||
BDropdown,
|
||||
|
||||
Reference in New Issue
Block a user