Skip to content

Vue I18n v9 中的重大变更

Vue I18n v9(针对 Vue 3)提供的大多数 API 都力求保持兼容性,以减轻从 v8(针对 Vue 2)迁移时的痛苦。但是,在迁移应用程序时,你仍可能遇到一些重大变更。本指南将介绍如何调整你的应用程序以使其在 Vue I18n v9 中正常工作。

API

new VueI18n 变为 createI18n

Vue I18n 现在不再是一个类而是一组函数。不再使用 new VueI18n(),而是必须调用 createI18n

Vue I18n v8.x:

js
import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

const i18n = new VueI18n({
  // ...
})

new Vue({
  i18n,
  // ...
})

Vue I18n v9 或更高版本:

js
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  // ...
})

const app = createApp({
  // ...
})
app.use(i18n)

原因: Vue 3 的全局 API 变更,以及与组件实例相关的 Vue 3 API 架构变更。

重命名为 datetimeFormats 而不是 dateTimeFormats

Vue I18n v8.x:

js
const i18n = new VueI18n({
  // ...
  dateTimeFormats: {
    // ...
  }
})

Vue I18n v9 或更高版本:

js
const i18n = createI18n({
  // ...
  datetimeFormats: {
    // ...
  }
})

翻译 API 返回值

翻译 API 如 $tt 函数只返回字符串。不再返回对象和数组值。

Vue I18n v8.x:

js
// 例如:数组结构的本地化消息
const i18n = new VueI18n({
  messages: {
    en: {
      errors: [
        '无效参数',
        // ...
        '意外错误'
      ]
    }
  }
})

// 例如:错误组件
const ErrorMessage = {
  props: {
    code: {
      type: Number,
      required: true
    }
  },
  template: `<p class="error">{{ getErrorMessage(code) }}</p>`,
  methods: {
    getErrorMessage(code) {
      return this.$t('errors')[code]
    }
  }
}

在 Vue I18n v9 和更高版本中,它改为通过 $tm / tm 获取本地化消息,并通过 $rtrt 解析本地化消息。以下为 Composition API 示例:

js
// 例如:数组结构的本地化消息
const i18n = createI18n({
  messages: {
    en: {
      errors: [
        '无效参数',
        // ...
        '意外错误'
      ]
    }
  }
})

// 例如:错误组件
const ErrorMessage = {
  props: {
    code: {
      type: Number,
      required: true
    }
  },
  template: `<p class="error">{{ errors(code) }}</p>`,
  setup() {
    const { tm, rt } = useI18n()
    const errors = (code) => rt(tm('errors')[code])
    return { errors }
  }
}

原因: 使返回翻译结果的简单义务,同时支持 TypeScript 类型。

复数 API 返回值

翻译 API 返回值类似,复数 API 如 $tctc 函数只返回字符串。不再返回对象和数组值。

原因: 使返回翻译结果的简单义务,同时支持 TypeScript 类型。

移除 getChoiceIndex

CAUTION

getChoiceIndex 选项的实现代码将在 v10 中被完全移除。

要自定义复数规则,Vue I18n v8.x 扩展了 VueI18n 类的 getChoiceIndex

Vue I18n v8.x:

js
VueI18n.prototype.getChoiceIndex = function (choice, choicesLength) {
  // this === VueI18n 实例,因此 locale 属性存在
  if (this.locale !== 'ru') {
    // 继续默认实现
  }

  if (choice === 0) {
    return 0;
  }

  const teen = choice > 10 && choice < 20;
  const endsWithOne = choice % 10 === 1;

  if (!teen && endsWithOne) {
    return 1;
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2;
  }
  return (choicesLength < 4) ? 2 : 3;
}

在 Vue I18n v9 及更高版本中,你可以使用以下选项来自定义:

传统 API 模式:

js
import { createI18n } from 'vue-i18n'

function customRule(choice, choicesLength, orgRule) {
  if (choice === 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 === 1
  if (!teen && endsWithOne) {
    return 1
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return choicesLength < 4 ? 2 : 3
}

const i18n = createI18n({
  // ...
  pluralizationRules: {
    ru: customRule,
    // ...
  },
  // ...
})

Composition API 模式:

js
import { useI18n } from 'vue-i18n'

function customRule(choice, choicesLength, orgRule) {
  if (choice === 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 === 1
  if (!teen && endsWithOne) {
    return 1
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return choicesLength < 4 ? 2 : 3
}

const MyComp = {
  setup() {
    const { t } = useI18n({
      // ...
      pluralRules: {
        ru: customRule,
        // ...
      },
      // ...
    })

    // ...
  }
}

原因: VueI18n 类已被移除。

更改 warnHtmlInMessage 选项默认值

在 Vue I18n v8.x 中,warnHtmlInMessage 的值为 "off"。因此,默认情况下,即使消息包含 HTML,也不会向控制台输出警告。

在 Vue I18n v9 及更高版本中,更改默认值如下:

  • 传统 API 模式: warnHtmlInMessage 属性: "warn"
  • Composition API 模式: warnHtmlMessage 布尔属性,默认为 true

在开发模式下,除非你更改此值,否则默认情况下你会收到控制台警告

在生产模式下,为了最大化性能,不会检测消息是否包含 HTML。

原因: 为了本地化消息提供更强的安全性

版本信息

版本信息现在可以通过导入语法访问,而不是通过 VueI18n 类静态属性。

Vue I18n v8.x:

js
import VueI18n from 'vue-i18n'

console.log(VueI18n.version)

Vue I18n v9 或更高版本:

js
import { VERSION } from 'vue-i18n'

console.log(VERSION)

原因: 树摇优化,且 VueI18n 类已被移除。

移除 Intl 可用性

由于主流浏览器现在都支持 ECMAScript 国际化 API,已被移除。

Vue I18n v8.x:

js
import VueI18n from 'vue-i18n'

console.log(VueI18n.availability)

原因: IE9 生命周期结束,且 VueI18n 类已被移除。

移除自定义格式器

CAUTION

formatter 选项的实现代码将在 v10 中被完全移除。 作为替代,vue-i18n 提供了自定义消息格式作为实验性功能。

原因: 在新的编译器和运行时 API 中难以提供自定义格式。我们计划在下一个主版本中支持这些 API。如果你想要使用 ICU 消息格式,可以使用 @formatjs/vue-intl

移除 preserveDirectiveContent 选项

CAUTION

preserveDirectiveContent 选项的实现代码将在 v10 中被完全移除。

Vue 3 的 v-t 指令现在保留默认内容。因此,此选项及其属性已从 VueI18n 实例中移除。

Vue I18n v8.x:

js
import VueI18n from 'vue-i18n'

const i18n = new VueI18n({
  // ...
  preserveDirectiveContent: true,
  // ...
})

原因: 保留元素中的 v-t 指令的内容

消息格式语法

移除用于列表插值的数组类对象

在 Vue I18n v8.x 中,列表插值可以使用数组类对象作为参数,例如:

js
import VueI18n from 'vue-i18n'

const i18n = new VueI18n({
  // ...
  messages: {
    en: {
      greeting: '你好,{0}!'
    }
  },
  // ...
})
html
<p>{{ $t('greeting', { '0': 'kazupon' }) }}</p>

在 Vue I18n v9 及更高版本中,无法再使用数组类对象进行列表插值,你必须使用数组:

html
<p>{{ $t('greeting', ['kazupon']) }}</p>

原因: 为翻译 API 提供一致的参数接口

特殊字符处理

Vue I18n 可以高度翻译的消息使用消息格式语法,例如:

txt
@.caml:{'没有苹果'} | {0} 苹果 | {n} 苹果

消息格式语法可以使用以下特殊字符表达:

  • {, }, @, $, |

从 Vue I18n v9 开始,消息格式语法由消息格式编译器处理,如果你将这些特殊字符用作消息的一部分,消息在编译时会发生错误。如果要使用这些特殊字符,则必须使用字面插值

txt
// 例如 `@` 用于电子邮件地址
{emailIdentity}{'@'}{emailDomain}

原因: 为了让消息格式编译器正确处理消息格式语法中使用的特殊字符,需要对其进行限制。

移除链接消息的括号分组

在 Vue I18n v8.x 中,区分了链接消息中的键引用与使用括号 () 的消息,以区分它们。

Vue I18n v8.x:

js
const messages = {
  en: {
    message: {
      dio: 'DIO',
      linked: '有个理由,你输了,@:(message.dio).'
    }
  }
}

在 Vue I18n v9 及更高版本中,括号不再需要,因为消息格式编译器允许你处理命名、列表和字面插值

Vue I18n v9 或更高版本:

js
const messages = {
  en: {
    message: {
      dio: 'DIO',
      linked: "有个理由,你输了,@:{'message.dio'}."
    }
  }
}

v-t 指令

移除 preserve 修饰符

CAUTION

preserve 修饰符的实现代码将在 v10 中被完全移除。

类似于移除 preserveDirectiveContent 选项,Vue 3 的 v-t 指令现在保留默认内容。因此,preserve 修饰符已被从 v-t 指令中移除。

Vue I18n v8.x:

html
<p v-t.preserve="'hello'"></p>

原因: 保留元素中 v-t 指令的内容

翻译组件

重命名为 i18n-t 而不是 i18n

翻译组件(在 Vue I18n v8.x 中称为 i18n 功能组件)的标签名已更改。

Vue I18n v8.x:

html
<i18n path="message.greeting" />

Vue I18n v9 或更高版本:

html
<i18n-t keypath="message.greeting" />

原因: 标签名与 i18n 自定义块 <i18n> 相同,这会使它与块名称混淆并容易在单文件组件中出错。

tag 属性是可选的

在 Vue I18n v8.x 中,可以通过指定标签名和 Booleanfalse 来使用 tag 属性渲染子元素而不带根元素。

Vue I18n v8.x:

html
<i18n :tag="false" path="message.greeting">
  <span>hello!</span>
</i18n>

从 Vue I18n v9 或更高版本开始,可以通过省略 tag 属性来实现相同的效果。

Vue I18n v9 或更高版本:

html
<i18n-t keypath="message.greeting">
  <span>hello!</span>
</i18n-t>

原因: Vue 3 现在支持片段

keypath 属性重命名为 path 属性

Vue I18n v8.x:

html
<i18n path="message.greeting" />

Vue I18n v9 或更高版本:

html
<i18n-t keypath="message.greeting" />

移除 place 属性和 places 属性

在 Vue I18n v9 及更高版本中,组件插值中的 place 属性和 places 属性已被移除。

Vue I18n v8.x:

html
<i18n path="info" tag="p" :places="{ limit: refundLimit }">
  <span place="limit">{{ refundLimit }}</span>
  <a place="action" :href="refundUrl">{{ $t('refund') }}</a>
</i18n>

Vue I18n v9 或更高版本:

html
<i18n-t keypath="info" tag="p">
  <template #limit>
    <span>{{ refundLimit }}</span>
  <template>
  <template #action>
    <a :href="refundUrl">{{ $t('refund') }}</a>
  <template>
</i18n-t>

原因: 可以通过插槽实现相同功能

数字格式化组件

tag 属性是可选的

翻译组件部分相似,在数字格式化组件(在 Vue I18n v8.x 中称为 i18n-n 功能组件)中,可以通过指定标签名和 Booleanfalse 来使用 tag 属性渲染子元素而不带根元素。

Vue I18n v8.x:

html
<i18n-n :tag="false" :value="100" format="currency">
  <span v-slot:integer="slotProps" styles="font-weight: bold">{{ slotProps.integer }}</span>
</i18n-n>

从 Vue I18n v9 或更高版本开始,可以通过省略 tag 属性来实现相同的效果。

Vue I18n v9 或更高版本:

html
<i18n-n :value="100" format="currency">
  <span v-slot:integer="slotProps" styles="font-weight: bold">{{ slotProps.integer }}</span>
</i18n-n>

原因: Vue 3 现在支持片段