# Интерполяция компонента

# Базовое использование

Поддержка с версии

🆕 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>

Подробнее о примере можно изучить здесь

Потомки функционального компонента 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>