Reputation: 239
I'm currently trying to internationalize my vue 3 vite project with "@intlify/vite-plugin-vue-i18n". The problem I am facing here, is that i currently have to import and setup the t variable for every component to use it.
example component:
<template>
t('translation')
</template>
<script>
import { useI18n } from 'vue-i18n'
export default {
setup(){
const {t} = useI18n();
return {t}
},
};
</script>
My question is, if its possible, what is the best way to make the variable "t" global? I cant find any examples/help on this, since they all import it into every compoenent. All help would be apreciated! :) For reference, here are the relevant files.
export default defineConfig({
plugins: [
vue(),
vueI18n({
include: path.resolve(__dirname, './src/locales/**')
})
]
})
main.ts:
import i18n from './i18n';
const app = createApp(App);
app.use(i18n);
app.mount("#app");
i18n.js:
import { createI18n } from 'vue-i18n'
import messages from '@intlify/vite-plugin-vue-i18n/messages'
export default createI18n({
legacy: false,
locale: 'no',
messages
})
Upvotes: 9
Views: 34318
Reputation: 17168
I have an additional example to show of accessing the global composer instance in vue-i18n v9:
i18n.js
import { createI18n } from 'vue-i18n';
import en from './locales/en';
import fr from './locales/fr';
const i18n = createI18n({
legacy: false,
locale: 'en',
fallbackLocale: 'en',
messages: {
en,
fr,
},
});
export default i18n;
main.js
import i18n from './i18n.js';
...
app.use(i18n);
Then you can import the instance into any file, such as vue-router's beforeEnter hook or vuex, etc.
import i18n from '../i18n.js';
console.log('i18n', i18n.global);
// to change locale:
i18n.global.locale.value = 'en';
You access it via i18n.global
. it is the same instance that is returned via useI18n()
from the 'vue-i18n' package.
EDIT: here is my current router.beforeEach function:
const routes = [
{
path: '/',
redirect: 'lang'
},
{
path: '/:lang',
name: 'lang',
component: HomePage,
},
{
path: '/:lang/content/:contentId',
name: 'guide.content',
component: () => import('@/views/ContentRoot.vue'),
children: [
{
path: '',
name: 'guide.content.root',
component: ContentPage,
},
{
path: 'video',
name: 'guide.content.video',
component: ShowVideo,
},
],
},
{
path: '/:catchAll(.*)',
component: () => import('@/views/404.vue'),
hidden: true,
},
];
router.beforeEach((to, from, next) => {
const locale = to.params.lang; // Retrieve the current locale set in the URL
// Check if the locale the user is trying to access is authorized.
// In a larger application that supports lots of languages, you may want to store
// all the locales in a separate array
if (!['en', 'es'].includes(locale)) {
return next(i18n.global.locale.value);
}
// Changing the language from the URL (either manually or with a link) is possible this way
i18n.global.locale.value = locale;
return next();
});
and here is my localeswitcher component:
<script setup>
import { watch } from 'vue';
import { IonSelect, IonSelectOption } from '@ionic/vue';
import { useRoute, useRouter } from 'vue-router';
import i18n from '@/i18n';
const route = useRoute();
const router = useRouter();
watch(() => i18n.global.locale.value, () => {
router.replace({
name: route.name,
params: {
lang: i18n.global.locale.value,
},
});
});
</script>
<template>
<ion-select v-model="$i18n.locale" class="w-20" aria-label="Locale">
<ion-select-option value="en">English</ion-select-option>
<ion-select-option value="es">Spanish</ion-select-option>
</ion-select>
</template>
It's Ionic in this example, but you can easily port that to a <select>
and <option>
Upvotes: 17
Reputation: 1
The i18n plugin registering using app.use(i18n)
make a global function $t
available for all the children components :
<template>
{{$t('translation')}}
</template>
This function is also available in option api and you could it like :
mounted() {
console.log(this.$t('translation'))
}
But you should add globalInjection: true,
to i18n config as follows :
import { createI18n } from 'vue-i18n'
import messages from '@intlify/vite-plugin-vue-i18n/messages'
export default createI18n({
legacy: false,
locale: 'no',
globalInjection: true,
messages
})
BONUS :
Change the locale by watching the getter inside App.vue
then set locale:
<script>
import { defineComponent, onMounted, watch } from "vue";
import { useI18n } from "vue-i18n";
import { useStore } from "vuex";
export default defineComponent({
name: "app",
data() {
return {};
},
setup() {
const i18n = useI18n();
const store = useStore();
watch(()=>store.getters.currentLang,(newVal) => { //watch the getter
i18n.locale.value = store.getters.currentLang;
},{
immediate:true
});
},
});
</script>
Upvotes: 24