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の戻り値
$tやt関数などの翻訳APIは文字列のみを返すように変更されました。オブジェクトと配列の値は返されなくなりました。
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の戻り値と同様に、$tcやtc関数などの複数形APIは、文字列のみを返すようになります。オブジェクトと配列の値は返されなくなりました。
理由: 翻訳結果を返すためのシンプルな義務を果たし、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以降では、以下のオプションでカスタマイズできます:
レガシーアイディアモード:
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以降では、デフォルト値を次のように変更します:
- レガシーアイディアモード:
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にはcustome message formatという実験的な機能があります。
理由: 新しいコンパイラとランタイム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に一貫した引数I/Fを提供するため
特殊文字の処理
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="'こんにちは'"></p>理由: v-tディレクティブを持つ要素にコンテンツを保持する
翻訳コンポーネント
i18nからi18n-tへの名前変更
翻訳コンポーネント(Vue I18n v8.xではi18n機能コンポーネントと呼ばれます)のタグ名が変更されました。
Vue I18n v8.x:
<i18n path="message.greeting" />Vue I18n v9以降:
<i18n-t keypath="message.greeting" />理由: タグ名がi18nカスタムブロック<i18n>と同じため、ブロック名との混同を避け、SFCでミスを起こしやすい。
tagプロパティは省略可能
Vue I18n v8.xでは、タグ名とBoolean値falseを指定することで、ルート要素なしで子要素をレンダリングするためにtagプロパティを使用できました。
Vue I18n v8.x:
<i18n :tag="false" path="message.greeting">
<span>こんにちは!</span>
</i18n>Vue I18n v9以降では、tagプロパティを省略することで同じことができます。
Vue I18n v9以降:
<i18n-t keypath="message.greeting">
<span>こんにちは!</span>
</i18n-t>理由: Vue 3がFragmentsをサポートしたため
pathプロパティからkeypathプロパティへの名前変更
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>理由: スロットで同じことができるため
NumberFormatコンポーネント
tagプロパティは省略可能
翻訳コンポーネントセクションと同様に、NumberFormatコンポーネント(Vue I18n v8.xではi18n-n機能コンポーネントと呼ばれます)のtagプロパティは、タグ名とBoolean値falseを指定することで、ルート要素なしで子要素をレンダリングするために使用できました。
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がFragmentsをサポートしたため