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:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
const i18n = new VueI18n({
// ...
})
new Vue({
i18n,
// ...
})Vue I18n v9 或更高版本:
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:
const i18n = new VueI18n({
// ...
dateTimeFormats: {
// ...
}
})Vue I18n v9 或更高版本:
const i18n = createI18n({
// ...
datetimeFormats: {
// ...
}
})翻译 API 返回值
翻译 API 如 $t 和 t 函数只返回字符串。不再返回对象和数组值。
Vue I18n v8.x:
// 例如:数组结构的本地化消息
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 获取本地化消息,并通过 $rt 或 rt 解析本地化消息。以下为 Composition API 示例:
// 例如:数组结构的本地化消息
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 如 $tc 和 tc 函数只返回字符串。不再返回对象和数组值。
原因: 使返回翻译结果的简单义务,同时支持 TypeScript 类型。
移除 getChoiceIndex
CAUTION
getChoiceIndex 选项的实现代码将在 v10 中被完全移除。
要自定义复数规则,Vue I18n v8.x 扩展了 VueI18n 类的 getChoiceIndex。
Vue I18n v8.x:
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 模式:
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 模式:
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:
import VueI18n from 'vue-i18n'
console.log(VueI18n.version)Vue I18n v9 或更高版本:
import { VERSION } from 'vue-i18n'
console.log(VERSION)原因: 树摇优化,且 VueI18n 类已被移除。
移除 Intl 可用性
由于主流浏览器现在都支持 ECMAScript 国际化 API,已被移除。
Vue I18n v8.x:
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:
import VueI18n from 'vue-i18n'
const i18n = new VueI18n({
// ...
preserveDirectiveContent: true,
// ...
})原因: 保留元素中的 v-t 指令的内容
消息格式语法
移除用于列表插值的数组类对象
在 Vue I18n v8.x 中,列表插值可以使用数组类对象作为参数,例如:
import VueI18n from 'vue-i18n'
const i18n = new VueI18n({
// ...
messages: {
en: {
greeting: '你好,{0}!'
}
},
// ...
})<p>{{ $t('greeting', { '0': 'kazupon' }) }}</p>在 Vue I18n v9 及更高版本中,无法再使用数组类对象进行列表插值,你必须使用数组:
<p>{{ $t('greeting', ['kazupon']) }}</p>原因: 为翻译 API 提供一致的参数接口
特殊字符处理
Vue I18n 可以高度翻译的消息使用消息格式语法,例如:
@.caml:{'没有苹果'} | {0} 苹果 | {n} 苹果消息格式语法可以使用以下特殊字符表达:
{,},@,$,|
从 Vue I18n v9 开始,消息格式语法由消息格式编译器处理,如果你将这些特殊字符用作消息的一部分,消息在编译时会发生错误。如果要使用这些特殊字符,则必须使用字面插值。
// 例如 `@` 用于电子邮件地址
{emailIdentity}{'@'}{emailDomain}原因: 为了让消息格式编译器正确处理消息格式语法中使用的特殊字符,需要对其进行限制。
移除链接消息的括号分组
在 Vue I18n v8.x 中,区分了链接消息中的键引用与使用括号 () 的消息,以区分它们。
Vue I18n v8.x:
const messages = {
en: {
message: {
dio: 'DIO',
linked: '有个理由,你输了,@:(message.dio).'
}
}
}在 Vue I18n v9 及更高版本中,括号不再需要,因为消息格式编译器允许你处理命名、列表和字面插值。
Vue I18n v9 或更高版本:
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:
<p v-t.preserve="'hello'"></p>原因: 保留元素中 v-t 指令的内容
翻译组件
重命名为 i18n-t 而不是 i18n
翻译组件(在 Vue I18n v8.x 中称为 i18n 功能组件)的标签名已更改。
Vue I18n v8.x:
<i18n path="message.greeting" />Vue I18n v9 或更高版本:
<i18n-t keypath="message.greeting" />原因: 标签名与 i18n 自定义块 <i18n> 相同,这会使它与块名称混淆并容易在单文件组件中出错。
tag 属性是可选的
在 Vue I18n v8.x 中,可以通过指定标签名和 Boolean 值 false 来使用 tag 属性渲染子元素而不带根元素。
Vue I18n v8.x:
<i18n :tag="false" path="message.greeting">
<span>hello!</span>
</i18n>从 Vue I18n v9 或更高版本开始,可以通过省略 tag 属性来实现相同的效果。
Vue I18n v9 或更高版本:
<i18n-t keypath="message.greeting">
<span>hello!</span>
</i18n-t>原因: Vue 3 现在支持片段
将 keypath 属性重命名为 path 属性
Vue I18n v8.x:
<i18n path="message.greeting" />Vue I18n v9 或更高版本:
<i18n-t keypath="message.greeting" />移除 place 属性和 places 属性
在 Vue I18n v9 及更高版本中,组件插值中的 place 属性和 places 属性已被移除。
Vue I18n v8.x:
<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 或更高版本:
<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 功能组件)中,可以通过指定标签名和 Boolean 值 false 来使用 tag 属性渲染子元素而不带根元素。
Vue I18n v8.x:
<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 或更高版本:
<i18n-n :value="100" format="currency">
<span v-slot:integer="slotProps" styles="font-weight: bold">{{ slotProps.integer }}</span>
</i18n-n>原因: Vue 3 现在支持片段