# Интерполяция компонента
# Базовое использование
Поддержка с версии
🆕 7.0+
Иногда требуется перевести сообщения в которых есть 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
. Например:
<div id="app">
<!-- ... -->
<i18n path="term" tag="label" for="tos">
<a :href="url" target="_blank">{{ $t('tos') }}</a>
</i18n>
<!-- ... -->
</div>
const messages = {
en: {
tos: 'Term of Service',
term: 'I accept xxx {0}.'
},
ru: {
tos: 'Условия обслуживания',
term: 'Я соглашаюсь с xxx {0}.'
}
}
const i18n = new VueI18n({
locale: 'en',
messages
})
new Vue({
i18n,
data: {
url: '/term'
}
}).$mount('#app')
Результат:
<div id="app">
<!-- ... -->
<label for="tos">
I accept xxx <a href="/term" target="_blank">Term of Service</a>.
</label>
<!-- ... -->
</div>
Подробнее о примере можно изучить здесь (opens new window)
Потомки функционального компонента i18n
интерполируют сообщения локализации по входному параметру path
.
В примере выше:
<a :href="url" target="_blank">{{ $t('tos') }}</a>
интерполируется с сообщением локализации term
.
В примере выше интерполяция компонента использует формат в виде списка. Потомки функционального компонента i18n
интерполируются по порядку их появления.
Определить тип корневого элемента можно указать с помощью входного параметра tag
. Если входной параметр не указан, то по умолчанию будет 'span'
. Также можно указать значение false
, чтобы вставлять дочерние элементы без создания и оборачивания в корневой.
# Использование синтаксиса слотов
Поддержка с версии
🆕 8.14+
Гораздо удобнее использовать синтаксис именованных слотов. Например:
<div id="app">
<!-- ... -->
<i18n path="info" tag="p">
<template v-slot:limit>
<span>{{ changeLimit }}</span>
</template>
<template v-slot:action>
<a :href="changeUrl">{{ $t('change') }}</a>
</template>
</i18n>
<!-- ... -->
</div>
const messages = {
en: {
info: 'You can {action} until {limit} minutes from departure.',
change: 'change your flight',
refund: 'refund the ticket'
}
}
const i18n = new VueI18n({
locale: 'en',
messages
})
new Vue({
i18n,
data: {
changeUrl: '/change',
refundUrl: '/refund',
changeLimit: 15,
refundLimit: 30
}
}).$mount('#app')
Результат:
<div id="app">
<!-- ... -->
<p>
You can <a href="/change">change your flight</a> until
<span>15</span> minutes from departure.
</p>
<!-- ... -->
</div>
С версии Vue 2.6 можно использовать сокращённый синтаксис слотов в шаблонах:
<div id="app">
<!-- ... -->
<i18n path="info" tag="p">
<template #limit>
<span>{{ changeLimit }}</span>
</template>
<template #action>
<a :href="changeUrl">{{ $t('change') }}</a>
</template>
</i18n>
<!-- ... -->
</div>
Ограничение
⚠️ В компоненте i18n
входные параметры слота не поддерживаются.
# Использование синтаксиса places
Внимание!
В следующей мажорной версии входные параметры place
и places
будут объявлены устаревшими. Рекомендуем использовать синтаксис слотов.
Поддержка с версии
🆕 7.2+
Обратите внимание
⚠️ В компоненте i18n
содержимое, состоящее только из пробелов, будет опущено.
Именованное форматирование поддерживается с помощью атрибута place
. Например:
<div id="app">
<!-- ... -->
<i18n path="info" tag="p">
<span place="limit">{{ changeLimit }}</span>
<a place="action" :href="changeUrl">{{ $t('change') }}</a>
</i18n>
<!-- ... -->
</div>
const messages = {
en: {
info: 'You can {action} until {limit} minutes from departure.',
change: 'change your flight',
refund: 'refund the ticket'
}
}
const i18n = new VueI18n({
locale: 'en',
messages
})
new Vue({
i18n,
data: {
changeUrl: '/change',
refundUrl: '/refund',
changeLimit: 15,
refundLimit: 30
}
}).$mount('#app')
Результат:
<div id="app">
<!-- ... -->
<p>
You can <a href="/change">change your flight</a> until
<span>15</span> minutes from departure.
</p>
<!-- ... -->
</div>
Обратите внимание
⚠️ Для использования именованного форматирования все потомки компонента i18n
должны иметь установленный атрибут place
. В противном случае будет использовано форматирование списком.
Если всё же необходимо интерполировать текстовое содержимое с помощью именованного форматирования, можно определить свойство places
на компоненте i18n
. Например:
<div id="app">
<!-- ... -->
<i18n path="info" tag="p" :places="{ limit: refundLimit }">
<a place="action" :href="refundUrl">{{ $t('refund') }}</a>
</i18n>
<!-- ... -->
</div>
Результат:
<div id="app">
<!-- ... -->
<p>
You can <a href="/refund">refund your ticket</a> until 30 minutes from
departure.
</p>
<!-- ... -->
</div>