Skip to content

Cannot make the result of i18n.global.t() reactive in object returned by setup() #536

@kuanyui

Description

@kuanyui

Reporting a bug?

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().

The official documentation of vue-i18n says If t(key) is used in a reactive context, it will re-evaluate once the locale changes., however, I just cannot find a way to make the value reactive via steup().

Module versions (please complete the following information):

  • vue: 3.x
  • vue-i18n: 9.x

Reproduction Link
https://codesandbox.io/s/vue-i18n-reactive-in-setup-t9j3e

<!DOCTYPE html>
<html lang="en">
  <head>
    <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>
  <body>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vue-i18n@next"></script>

    <div id="app">
      <form>
        <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,
            obj
          };
        }
      });

      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:

  1. Initialize an i18n instance (composition API, no legacy), with default locale: 'en'
  2. Initialize Vue app instance and use() the i18n instance.
  3. Change language with i18n.global.locale.value to ja
  4. 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()
  5. Access {{ tmpObj.test }} in the template of <Child>. Now it's translation is still in en.
  6. 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

Screenshot_20210617_100237
Screenshot_20210617_100243
Screenshot_20210617_100250

Additional context
No.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions