コンポーネント補間
基本的な使用方法
場合によっては、HTMLタグやコンポーネントに含まれたローカライズメッセージが必要になることがあります。例えば:
<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>上記のメッセージで $t を使うと、おそらく以下のローカルメッセージを組み立てようとするでしょう:
const messages = {
en: {
term1: 'I Accept xxx\'s',
term2: 'Terms of Service Agreement'
}
}そして、ローカライズされたテンプレートは次のようになります:
<p>{{ $t('term1') }}<a href="/term">{{ $t('term2') }}</a></p>出力結果:
<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>これは非常に面倒くさいです。もしローカルメッセージの中で <a> タグを設定すると、v-html="$t('term')" でローカライズする際にXSS脆弱性が発生する可能性があります。
Translationコンポーネント (i18n-t) を使用することでこれを回避できます。下記のようにします。
テンプレート:
<div id="app">
<!-- ... -->
<i18n-t keypath="term" tag="label" for="tos">
<a :href="url" target="_blank">{{ $t('tos') }}</a>
</i18n-t>
<!-- ... -->
</div>JavaScript:
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
const i18n = createI18n({
locale: 'en',
messages: {
en: {
tos: 'Term of Service',
term: 'I accept xxx {0}.'
},
ja: {
tos: '利用規約',
term: '私は xxx の{0}に同意します。'
}
}
})
const app = createApp({
data: () => ({ url: '/term' })
})
app.use(i18n)
app.mount('#app')出力結果:
<div id="app">
<!-- ... -->
<label for="tos">
I accept xxx <a href="/term" target="_blank">Term of Service</a>.
</label>
<!-- ... -->
</div>上記の例については、例を参照してください。
翻訳コンポーネントの子要素は keypath プロパティのローカルメッセージで補間されます。上記の例では、
<a :href="url" target="_blank">{{ $t('tos') }}</a>
が term ローカルメッセージで補間されます。
上記の例では、コンポーネント補間は リスト補間 に従います。翻訳コンポーネントの子要素は出現順序で補間されます。
tag プロパティを指定することでルートノード要素タイプを選択できます。省略した場合、デフォルトではFragmentsになります。
スロット構文の使用方法
名前付きスロット構文を使用することがより便利です。下記のようにします:
テンプレート:
<div id="app">
<!-- ... -->
<i18n-t keypath="info" tag="p">
<template v-slot:limit>
<span>{{ changeLimit }}</span>
</template>
<template v-slot:action>
<a :href="changeUrl">{{ $t('change') }}</a>
</template>
</i18n-t>
<!-- ... -->
</div>JavaScript:
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
const i18n = createI18n({
locale: 'en',
messages: {
en: {
info: 'You can {action} until {limit} minutes from departure.',
change: 'change your flight',
refund: 'refund the ticket'
}
}
})
const app = createApp({
data: () => ({
changeUrl: '/change',
refundUrl: '/refund',
changeLimit: 15,
refundLimit: 30
})
})
app.use(i18n)
app.mount('#app')出力結果:
<div id="app">
<!-- ... -->
<p>
You can <a href="/change">change your flight</a> until <span>15</span> minutes from departure.
</p>
<!-- ... -->
</div>テンプレートで以下のスロットの省略構文も使用できます:
<div id="app">
<!-- ... -->
<i18n-t keypath="info" tag="p">
<template #limit>
<span>{{ changeLimit }}</span>
</template>
<template #action>
<a :href="changeUrl">{{ $t('change') }}</a>
</template>
</i18n-t>
<!-- ... -->
</div>制限事項
⚠️ 翻訳コンポーネントでは、スロットプロパティはサポートされていません。
複数形の使用方法
plural プロパティを使用して、コンポーネント補間で複数形を使用できます。下記の例のようにします。
テンプレート:
<div id="app">
<!-- ... -->
<i18n-t keypath="message.plural" locale="en" :plural="count">
<template #n>
<b>{{ count }}</b>
</template>
</i18n-t>
<!-- ... -->
</div>JavaScript:
const { createApp, ref } = Vue
const { createI18n } = VueI18n
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: {
en: {
message: {
plural: 'no bananas | {n} banana | {n} bananas'
}
}
}
})
const app = createApp({
setup() {
const count = ref(2)
return { count }
}
})
app.use(i18n)
app.mount('#app')出力結果:
<div id="app" data-v-app="">
<!-- ... -->
<b>2</b> bananas
<!-- ... -->
</div>スコープ解決
翻訳コンポーネントのスコープ解決はデフォルトで parent です。
これは、翻訳コンポーネントがそれを使う親コンポーネントで有効になっているスコープを使用することを意味します。
親コンポーネントに useI18n が useScope: 'global' で設定されている場合、グローバルスコープを使用し、そうでなければ親コンポーネントのローカルスコープを使用します。
ただし、ブラウザコンソールに次のような警告メッセージが表示されることがあります:
[intlify] Not found parent scope. use the global scope.このメッセージは、翻訳コンポーネントを使う親コンポーネントで useI18n を実行していない場合に表示されます。
そのような状況では、翻訳コンポーネントのスコープは警告メッセージにあるようにグローバルスコープにフォールバックします。
この警告を抑制するための回避策として、翻訳コンポーネントの scope プロパティに global を指定します。
<i18n-t keypath="message.foo" scope="global">
...
</i18n-t>注意事項
この警告は本番ビルドではブラウザコンソールに出力されません。
注意事項
これは petite-vue-i18n では利用できません。