Интерполяция компонентов
Основное использование
Иногда нам нужно локализовать сообщение, которое было включено в тег 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> в локализованном сообщении, существует возможность уязвимостей XSS из-за локализации с помощью v-html="$t('term')".
Вы можете избежать этого, используя компонент перевода (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>Разрешение области видимости
По умолчанию разрешение области видимости Scope компонента перевода — parent (родительская).
Это означает, что компонент перевода использует область видимости, включенную в родительском компоненте, который его использует.
Если родительский компонент имеет useI18n с useScope: 'global', он будет использовать глобальную область видимости, иначе если useScope: 'local', он будет использовать локальную область видимости родительского компонента.
Однако иногда вы можете увидеть предупреждающее сообщение в консоли браузера следующего содержания:
[intlify] Не найдена родительская область видимости. Используется глобальная область видимости.Это сообщение отображается в том случае, если вы не запустили useI18n в родительском компоненте, который использует компонент перевода.
В этой ситуации область видимости компонента перевода будет возвращена к глобальной области видимости, как указано в предупреждении.
Обходной путь для подавления этого предупреждения — указать global как свойство scope компонента перевода.
<i18n-t keypath="message.foo" scope="global">
...
</i18n-t>ПРИМЕЧАНИЕ
Это предупреждение не выводится в консоль браузера в сборке для продакшена.
ПРИМЕЧАНИЕ
Эта функция недоступна в petite-vue-i18n