Reputation: 59
I'm using vue-i18n to translate messages in my vue app. I have some global translations that are added in new VueI18n(...)
as well as some component based translations in a component named c-parent
. The component contains child components named c-child
. Now, I would like to use the component based translations of c-parent
also in c-child
.
I made a small example in this fiddle: https://jsfiddle.net/d80o7mpL/
The problem is in the last line of the output: The message in c-child
is not translated using the component based translations of c-parent
.
Since global translations are "inherited" by all components, I would expect the same for component based translations (in their respective component subtree). Is there a way to achieve this in vue-i18n?
Upvotes: 0
Views: 2636
Reputation: 131
What I'm doing is using i18n.mergeLocaleMessage in router.ts
to merge a particular .i18n.json
translation file (by setting a meta.i18n
property) for each route:
const router = new Router({
[...]
{
path: '/settings',
name: 'settings',
component: () => import('./views/Settings.vue'),
meta: {
i18n: require('./views/Settings.i18n.json'),
},
},
[...]
});
router.beforeEach((to, from, next) => {
// load view-scoped translations?
if (!!to.meta.i18n) {
Object.keys(to.meta.i18n).forEach((lang) => i18n.mergeLocaleMessage(lang, to.meta.i18n[lang]));
}
next();
});
With Settings.i18n.json
being like:
{
"en":
{
"Key": "Key"
},
"es":
{
"Key": "Clave"
}
}
That way, all child components will use the same translation file.
In case you can't use vue-router, maybe you can do it in the parent component's mounted() hook (haven't tried that)
Upvotes: 2
Reputation: 63
I had the same situation with i18n.
Let's say we have a "card" object prop which it includes the needed language ( was my case) that we'll use in a CardModal.vue component which will be the parent. So what i did was get the needed locale json file ( based on the prop language) and adding those messages within the card prop.
So in the parent component we'll have:
<template>
<div id="card-modal">
<h1> {{ card.locales.title }} </h1>
<ChildComponent card="card" />
</div>
</template>
<script>
export default {
name: 'CardModal',
props: {
card: {
type: Object,
required: true,
}
}
data() {
return {
locale: this.card.language, //'en' or 'es'
i18n: {
en: require('@/locales/en'),
es: require('@/locales/es'),
},
}
},
created() {
this.card.locales = this.i18n[this.locale].card_modal
}
}
</script>
Notice that we are not relying in the plugin function anymore ( $t() ) and we are only changing the locale in the current component. I did it in this way cause i didn't want to use the "i18n" tag in each child component and wanted to keep all the locales messages in one single json file per language. I was already using the card prop in all child components so that's why i added the locales to that object.
If you need a way to change the locale using a select tag in the component, we can use a watcher for the locale data property like the docs shows
Upvotes: 0
Reputation: 3520
Well, you need to pass the text to child component using props.
Global translations are "inherited" by all components. But you're using local translation in child.
const globalMessages = {
en: { global: { title: 'Vue i18n: usage of component based translations' } }
}
const componentLocalMessages = {
en: { local: {
title: "I\'m a translated title",
text: "I\'m a translated text"
}}
}
Vue.component('c-parent', {
i18n: {
messages: componentLocalMessages
},
template: `
<div>
<div>c-parent component based translation: {{ $t('local.title') }}</div>
<c-child :text="$t('local.title')"></c-child>
</div>
`
})
Vue.component('c-child', {
props: ['text'],
template: `
<div>c-child translation: {{ text }}</div>
`
})
Vue.component('app', {
template: '<c-parent />'
})
const i18n = new VueI18n({
locale: 'en',
messages: globalMessages
})
new Vue({
i18n,
el: "#app",
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
}
h5 {
margin: 1em 0 .5em 0;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue-i18n"></script>
<div id="app">
<h2>{{ $t('global.title') }}</h2>
We define two Vue components: <code><c-child/></code> contained in <code><c-parent/></code>.
<code><c-parent/></code> defines some component based translations. We would like to use the
parent's translations in the child but it does not work.
<h5>Example:</h5>
<app />
</div>
Upvotes: 1