在vue3中使用vue-i18n@next

1,673 阅读1分钟

我正在参加「掘金·启航计划」

版本与模式

如果要使用vue3,则需要使用vue-i18n v9以上的版本

因为vue3支持组合式api(Composition API),因此vue-i18n从v9开始也增加了相应的支持

对于以前类似v8的使用方式,在v9里被叫做Legacy API模式,新的方式叫做Composition API模式。v9默认是Legacy API模式。可以在createI18n时设置legacy: false切换到Composition API模式

Legacy API使用

// 1. Ready translated locale messages
// The structure of the locale message is the hierarchical object structure with each locale as the top property
const messages = {
  en: {
    message: {
      hello: 'hello world'
    }
  },
  ja: {
    message: {
      hello: 'こんにちは、世界'
    }
  }
}

// 2. Create i18n instance with options
const i18n = VueI18n.createI18n({
  locale: 'ja', // 设定语言
  fallbackLocale: 'en', // 设定兜底的语言
  messages, // 不同语言的文案
  // If you need to specify other options, you can set other options
  // ...
})


// 3. Create a vue root instance
const app = Vue.createApp({
  // set something options
  // ...
})

// 4. Install i18n instance to make the whole app i18n-aware
app.use(i18n)

// 5. Mount
app.mount('#app')

// Now the app has started!

于是,在每个组件中都可以使用this.$i18n获取createI18n创建的i18n实例,使用this.$t来获取对应语言的文案

在html中可以如下使用

<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-i18n@9"></script>

<div id="app">
  <p>{{ $t("message.hello") }}</p>
</div>

作用域

v9里增加了作用域的概念,一个叫全局作用域一个叫组件作用域,也就是说我们可以单独设置某个组件的语言,而忽略全局的语言

如果在创建i18n实例的时候指定了组件的选项,那么创建出来的就是组件作用域的i18n实例,它继承自全局的实例,并只在这个组件内有效

此时在组件内this.$i18n获取的i18n实例就是组件自身的i18n实例。如果想要获得全局的实例需要使用i18n.global(如果没有创建组件内部的i18n实例,那this.$i18ni18n.global是相等的)

组件作用域的i18n实例并不意味着完全不受全局实例的影响。

  • 组件内部的i18n实例没有指定语言,因此会兜底到全局的语言上去;
  • 组件内部的i18n实例没有的文案,也会去全局的文案里去寻找;
  • 如果没有设置sync:false,全局的语言改变,所有的组件i18n实例语言也都会变化(也就是说,组件语言变了不影响全局语言,全局语言变了影响组件语言)
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'

// setting locale info used by global scope as an options
const i18n = createI18n({
  locale: 'ja',
  messages: {
    en: {
      message: {
        hello: 'hello world',
        greeting: 'good morning, world!'
      }
    },
    ja: {
      message: {
        hello: 'こんにちは、世界',
        greeting: 'おはよう、世界!'
      }
    }
  }
})

// define component
const Component1 = {
  template: `
    <div id="component">
      <h1>Component1</h1>
      <p>Component1 locale messages: {{ $t("message.hello") }}</p>
      <p>Fallback global locale messages: {{ $t("message.greeting") }}</p>
    </div>
  `,
  i18n: { // 组件内的i18n实例构造参数,`this.$i18n`获取的就是这个实例
    // locale: 'ja', 组件内部的i18n实例没有指定语言,因此会兜底到全局的语言上去
    messages: {
      en: { message: { hello: 'hello component1' } },
      ja: { message: { hello: 'こんにちは、component1' } }
    }
  }
}

const app = createApp({
  components: { Component1 }
})
app.use(i18n)
app.mount('#app')

切换语言

因为i18n分为全局作用域和组件作用域的,所以分开来看

没有创建组件内部的i18n实例,那this.$i18ni18n.global是相等的

因此通过i18n.global.localethis.$i18n.locale都可以改变语言

<template>
  <div class="locale-changer">
    <select v-model="$i18n.locale">
      <option v-for="locale in $i18n.availableLocales" :key="`locale-${locale}`" :value="locale">{{ locale }}</option>
    </select>
  </div>
</template>
// when vue-i18n is being used with legacy: false, note that i18n.global.locale is a ref, so we must set it via .value:
i18n.global.locale.value = 'en'

// otherwise - when using legacy: true, we set it like this:
i18n.global.locale = 'en'

如果没有设置sync:false,全局的语言改变,所有的组件i18n实例语言也都会变化(也就是说,组件语言变了不影响全局语言,全局语言变了影响组件语言)

于是通过i18n.global.locale改变全局语言,此时所有的组件i18n实例语言也都会变化

// when vue-i18n is being used with legacy: false, note that i18n.global.locale is a ref, so we must set it via .value:
i18n.global.locale.value = 'en'

// otherwise - when using legacy: true, we set it like this:
i18n.global.locale = 'en'

通过this.$i18n.locale改变组件的语言,其他组件语言不会变化

<template>
  <div class="locale-changer">
    <select v-model="$i18n.locale">
      <option v-for="locale in $i18n.availableLocales" :key="`locale-${locale}`" :value="locale">{{ locale }}</option>
    </select>
  </div>
</template>

参考