In fact I guess this is not a bug, though I didn't find a workable way to solve this currently, after searching lots of docs, issues and pages. However I guess maybe the official reference of vue-i18n could describe the solution about this issue.
In some scenario, I want to create some reactive object containing translated i18n strings (via some reusable util functions) in
setup()
.
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Vue I18n v9 Starter Template</title>
</head>
<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/vue-i18n@next"></script>
<div id="app">
<label>{{ $t('message.language') }}</label>
<select v-model="curLang">
<option value="en">en</option>
<option value="ja">ja</option>
</select>
</form>
<button v-on:click="showChild = !showChild">Toggle Child v-if</button>
<p>{{ $t("message.directMsg") }}</p>
<Child v-if="showChild"></Child>
</div>
<script>
const { createApp, defineComponent, reactive, ref } = Vue;
const { createI18n } = VueI18n;
const i18n = createI18n({ // step 1
legacy: false,
globalInjection: true,
locale: "en",
messages: {
en: {
message: {
language: "Language",
directMsg: "Direct i18n.t()",
msgInObj: "i18n.t() in Object"
ja: {
message: {
language: "言語",
directMsg: "直接の i18n.t()",
msgInObj: "オブジェクト内の i18n.t()"
const Child = defineComponent({
template: `<p><b>Child Component, in setup():</b>
<div>{{ directVal }}</div> // step 5
<div>{{ obj.indirectVal }}</div>
</p>`,
setup() {
let directVal = i18n.global.t("message.directMsg");
let obj = reactive({ // step 4
indirectVal: i18n.global.t("message.msgInObj")
return {
directVal,
const app = createApp({ // step 2
components: {
Child
data() {
return {
showChild: true
computed: {
curLang: {
get() {
return i18n.global.locale.value;
set(nv) {
i18n.global.locale.value = nv;
app.use(i18n);
app.mount("#app");
i18n.global.locale.value = "ja"; // step 3
</script>
</body>
</html>
To Reproduce
Steps to reproduce the behavior:
Initialize an i18n instance (composition API, no legacy
), with default locale: 'en'
Initialize Vue app instance and use()
the i18n instance.
Change language with i18n.global.locale.value
to ja
Create a reactive object tmpObj
in <Child>
component's setup()
function, and add a property test
into the object with the return value of i18n.global.t()
Access {{ tmpObj.test }}
in the template of <Child>
. Now it's translation is still in en
.
Reload (please click the button Toggle Child v-if
) the <Child>
, Now it's translation will become ja
. (because <Child>
's setup()
is run again after i18n.global.locale.value
changed.)
Expected behavior
The <Child>
should show ja
string as soon as i18n.global.locale.value
changed.
Screenshots
Additional context
Cannot make the result of i18n.global.t()
reactive
Cannot make the result of i18n.global.t()
reactive in object returned by setup()
Jun 17, 2021
@kuanyui try this, use computed
, I just tested, it wrok: