Компонент i18n-t используется для интерполяции и
локализации HTML-структур, Vue-компонентов и сложных текстовых шаблонов
внутри переводов. Основная задача — безопасно внедрять разметку и
динамические элементы в локализованные строки без ручной сборки
текста.
В отличие от обычного вызова t(), компонент
позволяет:
v-html.Наиболее часто i18n-t применяется для:
<i18n-t keypath="welcome">
</i18n-t>
{
"welcome": "Добро пожаловать"
}
Компонент рендерит перевод по ключу welcome.
{
"message": "Нажмите <strong>сюда</strong> для продолжения"
}
<i18n-t keypath="message" tag="p" />
Результат:
<p>
Нажмите <strong>сюда</strong> для продолжения
</p>
tagАтрибут tag задаёт корневой HTML-элемент.
<i18n-t keypath="message" tag="div" />
<div>
Нажмите <strong>сюда</strong> для продолжения
</div>
Одно из главных преимуществ i18n-t — возможность
внедрять компоненты прямо в перевод.
{
"terms": "Примите условия {0}"
}
<i18n-t keypath="terms" tag="p">
<a href="/terms">пользовательского соглашения</a>
</i18n-t>
Результат:
<p>
Примите условия
<a href="/terms">пользовательского соглашения</a>
</p>
Компонент использует индексированные плейсхолдеры:
{
"example": "Это {0} пример"
}
<i18n-t keypath="example">
<strong>важный</strong>
</i18n-t>
Результат:
Это <strong>важный</strong> пример
{
"notification": "{0} отправил сообщение {1}"
}
<i18n-t keypath="notification">
<strong>Администратор</strong>
<a href="/messages">открыть</a>
</i18n-t>
Помимо индексированных параметров поддерживаются именованные слоты.
{
"policy": "Прочитайте {link}"
}
<i18n-t keypath="policy">
<template #link>
<a href="/policy">политику конфиденциальности</a>
</template>
</i18n-t>
Прочитайте
<a href="/policy">политику конфиденциальности</a>
i18n-t поддерживает передачу параметров через атрибут
values.
{
"balance": "Баланс пользователя {name}: {amount}"
}
<i18n-t
keypath="balance"
:values="{
name: 'Алексей',
amount: '$250'
}"
/>
Результат:
Баланс пользователя Алексей: $250
{
"email": "{0}, ваш email: {email}"
}
<i18n-t
keypath="email"
:values="{ email: 'admin@example.com' }"
>
<strong>Администратор</strong>
</i18n-t>
import { useI18n } from 'vue-i18n'
export default {
setup() {
const { locale } = useI18n()
return {
locale
}
}
}
<i18n-t keypath="message" tag="p" />
npm install vue-i18n
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n']
})
<i18n-t keypath="welcome" />
v-htmlПри использовании:
<div v-html="$t('message')"></div>
появляются риски:
i18n-tКомпонент:
{
"profile": "Перейдите в {0}"
}
<i18n-t keypath="profile">
<RouterLink to="/profile">
профиль
</RouterLink>
</i18n-t>
{
"action": "Для продолжения нажмите {0}"
}
<i18n-t keypath="action">
<BaseButton>
Продолжить
</BaseButton>
</i18n-t>
{
"complex": "{0} выполнил действие {1}"
}
<i18n-t keypath="complex">
<UserAvatar />
<ActionButton />
</i18n-t>
{
"register": "Создать {0}"
}
{
"register": "Create {0}"
}
<i18n-t keypath="register">
<a href="/signup">аккаунт</a>
</i18n-t>
После смены локали структура останется неизменной, изменится только текст перевода.
Разные языки имеют различный порядок слов. i18n-t
позволяет не зависеть от фиксированной структуры шаблона.
{
"article": "Статья опубликована пользователем {0}"
}
{
"article": "{0} が記事を公開しました"
}
<i18n-t keypath="article">
<strong>Admin</strong>
</i18n-t>
{
"messages": "Нет сообщений | {count} сообщение | {count} сообщения | {count} сообщений"
}
<i18n-t
keypath="messages"
:plural="count"
:values="{ count }"
/>
localeКомпонент позволяет явно указывать локаль.
<i18n-t
keypath="welcome"
locale="en"
/>
Если перевод отсутствует:
<i18n-t keypath="unknown.key">
<template #default>
Текст по умолчанию
</template>
</i18n-t>
<i18n-t :keypath="currentKey" />
const currentKey = computed(() => {
return isAdmin.value
? 'admin.message'
: 'user.message'
})
<li v-for="item in items" :key="item.id">
<i18n-t
:keypath="item.translation"
:values="item.values"
/>
</li>
{
"date": "Дата: {date}"
}
<i18n-t
keypath="date"
:values="{
date: new Intl.DateTimeFormat('ru').format(new Date())
}"
/>
n() и d()<script setup>
const { n, d } = useI18n()
const price = n(1200, 'currency')
const date = d(new Date(), 'short')
</script>
<template>
<i18n-t
keypath="info"
:values="{ price, date }"
/>
</template>
<i18n-t
v-if="isAuthorized"
keypath="authorized"
/>
<i18n-t
v-else
keypath="guest"
/>
interface UserValues {
name: string
age: number
}
<script setup lang="ts">
const values: UserValues = {
name: 'Alex',
age: 25
}
</script>
<template>
<i18n-t
keypath="profile"
:values="values"
/>
</template>
Компонент i18n-t:
Однако большое количество компонентов внутри циклов может увеличивать стоимость рендера.
<div v-for="item in hugeArray">
<i18n-t :keypath="item.key">
<ComplexComponent />
</i18n-t>
</div>
В подобных случаях рекомендуется:
i18n-t корректно работает при серверном рендеринге.
Особенно важно:
locale.value = navigator.language
На сервере и клиенте значение может отличаться.
i18n-t от
$t| Возможность | $t() |
i18n-t |
|---|---|---|
| Простые строки | Да | Да |
| HTML-разметка | Ограниченно | Да |
| Vue-компоненты | Нет | Да |
| Слоты | Нет | Да |
| Безопасный рендер | Частично | Да |
| Сложная структура | Нет | Да |
i18n-tКомпонент особенно полезен в следующих случаях:
Для простых строк предпочтительнее использовать обычный
t() или $t().
Нежелательно:
{
"text": "Нажмите <a href='/home'>сюда</a>"
}
Лучше:
{
"text": "Нажмите {0}"
}
<i18n-t keypath="text">
<RouterLink to="/home">
сюда
</RouterLink>
</i18n-t>
Плохо:
<i18n-t :keypath="isAdmin ? 'a' : 'b'" />
Лучше:
const translationKey = computed(() => {
return isAdmin.value
? 'a'
: 'b'
})
Нежелательно:
{
"message": "Пользователь {0} создал {1}"
}
если в других языках структура может отличаться.
Для таких случаев лучше применять именованные слоты.
{
"register": "Создавая аккаунт, вы принимаете {terms} и {policy}"
}
<i18n-t keypath="register" tag="p">
<template #terms>
<RouterLink to="/terms">
условия использования
</RouterLink>
</template>
<template #policy>
<RouterLink to="/policy">
политику конфиденциальности
</RouterLink>
</template>
</i18n-t>
<p>
Создавая аккаунт, вы принимаете
<a href="/terms">
условия использования
</a>
и
<a href="/policy">
политику конфиденциальности
</a>
</p>