Skip to content

Важные изменения в v9

Большинство API, предлагаемых в Vue I18n v9 (для Vue 3), стремятся сохранить совместимость, чтобы облегчить процесс миграции с v8 (для Vue 2). Однако при переходе вашего приложения всё же могут возникнуть некоторые важные изменения. Этот руководство показывает, как адаптировать ваше приложение для работы с Vue I18n v9.

API

new VueI18n становится createI18n

Vue I18n больше не является классом, а представляет собой набор функций. Вместо написания new VueI18n(), теперь вы должны вызвать createI18n:

Vue I18n v8.x:

js
import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

const i18n = new VueI18n({
  // ...
})

new Vue({
  i18n,
  // ...
})

Vue I18n v9 или новее:

js
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  // ...
})

const app = createApp({
  // ...
})
app.use(i18n)

Причина: Vue 3 Изменения глобального API и изменения архитектуры API Vue 3, связанные с экземплярами компонентов.

Переименование datetimeFormats из dateTimeFormats

Vue I18n v8.x:

js
const i18n = new VueI18n({
  // ...
  dateTimeFormats: {
    // ...
  }
})

Vue I18n v9 или новее:

js
const i18n = createI18n({
  // ...
  datetimeFormats: {
    // ...
  }
})

Значение, возвращаемое API перевода

API перевода, такое как $t и функция t, возвращают только строку. Объекты и массивы больше не возвращаются.

Vue I18n v8.x:

js
// Например, массив структурированных локализационных сообщений
const i18n = new VueI18n({
  messages: {
    en: {
      errors: [
        'invalid argument',
        // ...
        'unexpected errors'
      ]
    }
  }
})

// Например, компонент ошибки
const ErrorMessage = {
  props: {
    code: {
      type: Number,
      required: true
    }
  },
  template: `<p class="error">{{ getErrorMessage(code) }}</p>`,
  methods: {
    getErrorMessage(code) {
      return this.$t('errors')[code]
    }
  }
}

В Vue I18n v9 и новее это изменилось: получение локализационных сообщений осуществляется через $tm / tm, а их разрешение — через $rt или rt. Пример с использованием Composition API:

js
// Например, массив структурированных локализационных сообщений
const i18n = createI18n({
  messages: {
    en: {
      errors: [
        'invalid argument',
        // ...
        'unexpected errors'
      ]
    }
  }
})

// Например, компонент ошибки
const ErrorMessage = {
  props: {
    code: {
      type: Number,
      required: true
    }
  },
  template: `<p class="error">{{ errors(code) }}</p>`,
  setup() {
    const { tm, rt } = useI18n()
    const errors = (code) => rt(tm('errors')[code])
    return { errors }
  }
}

Причина: Для обеспечения простой обязательной возвратной модели результатов перевода, а также поддержки типов TypeScript.

Значение, возвращаемое API множественного числа

Аналогично Значению, возвращаемому API перевода, API множественного числа, такое как $tc и tc, возвращает только строку. Объекты и массивы больше не возвращаются.

Причина: Для обеспечения простой обязательной возвратной модели результатов перевода, а также поддержки типов TypeScript.

Удаление getChoiceIndex

CAUTION

Код реализации опции getChoiceIndex будет полностью удален в версии v10.

Чтобы кастомизировать правила множественного числа, Vue I18n v8.x расширяет getChoiceIndex класса VueI18n.

Vue I18n v8.x:

js
VueI18n.prototype.getChoiceIndex = function (choice, choicesLength) {
  // this === экземпляр VueI18n, поэтому свойство locale существует
  if (this.locale !== 'ru') {
    // продолжить с реализацией по умолчанию
  }

  if (choice === 0) {
    return 0;
  }

  const teen = choice > 10 && choice < 20;
  const endsWithOne = choice % 10 === 1;

  if (!teen && endsWithOne) {
    return 1;
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2;
  }
  return (choicesLength < 4) ? 2 : 3;
}

В Vue I18n v9 и новее вы можете кастомизировать это с помощью следующих опций:

Режим Legacy API:

js
import { createI18n } from 'vue-i18n'

function customRule(choice, choicesLength, orgRule) {
  if (choice === 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 === 1
  if (!teen && endsWithOne) {
    return 1
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return choicesLength < 4 ? 2 : 3
}

const i18n = createI18n({
  // ...
  pluralizationRules: {
    ru: customRule,
    // ...
  },
  // ...
})

Режим Composition API:

js
import { useI18n } from 'vue-i18n'

function customRule(choice, choicesLength, orgRule) {
  if (choice === 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 === 1
  if (!teen && endsWithOne) {
    return 1
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return choicesLength < 4 ? 2 : 3
}

const MyComp = {
  setup() {
    const { t } = useI18n({
      // ...
      pluralRules: {
        ru: customRule,
        // ...
      },
      // ...
    })

    // ...
  }
}

Причина: Класс VueI18n был удален.

Изменение значения по умолчанию для опции warnHtmlInMessage

В Vue I18n v8.x значением warnHtmlInMessage было "off". Соответственно, предупреждения не выводятся в консоль даже если сообщение содержит HTML.

В Vue I18n v9 и новее изменены значения по умолчанию следующим образом:

  • Режим Legacy API: свойство warnHtmlInMessage: "warn"
  • Режим Composition API: булево свойство warnHtmlMessage, по умолчанию true

В режиме разработки, если вы не измените это значение, вы будете получать предупреждения в консоли по умолчанию.

В режиме продакшена проверка наличия HTML в сообщении не производится для максимальной производительности.

Причина: Для обеспечения более надежной безопасности локализационных сообщений

Информация о версии

Информация о версии теперь доступна через синтаксис импорта вместо статического свойства класса VueI18n.

Vue I18n v8.x:

js
import VueI18n from 'vue-i18n'

console.log(VueI18n.version)

Vue I18n v9 или новее:

js
import { VERSION } from 'vue-i18n'

console.log(VERSION)

Причина: Оптимизация tree shaking, а также класс VueI18n был удален.

Удаление доступности Intl

Удалено, так как основные браузеры теперь поддерживают ECMAScript Internationalization API.

Vue I18n v8.x:

js
import VueI18n from 'vue-i18n'

console.log(VueI18n.availability)

Причина: Конец жизни IE9, а также класс VueI18n был удален.

Удаление пользовательского форматера

CAUTION

Код реализации опции formatter будет полностью удален в версии v10. В качестве альтернативы, vue-i18n имеет пользовательский формат сообщений как экспериментальную функцию.

Причина: Из-за сложности предоставления пользовательских форматов в новых API компилятора и времени выполнения. Мы планируем поддерживать эту возможность в следующем мажорном релизе для этих API. Если вы хотите использовать формат ICU сообщений, вы можете использовать @formatjs/vue-intl

Удаление опции preserveDirectiveContent

CAUTION

Код реализации опции preserveDirectiveContent будет полностью удален в версии v10.

Директива v-t для Vue 3 теперь сохраняет контент по умолчанию. Поэтому эта опция и её свойства были удалены из инстанса VueI18n.

Vue I18n v8.x:

js
import VueI18n from 'vue-i18n'

const i18n = new VueI18n({
  // ...
  preserveDirectiveContent: true,
  // ...
})

Причина: Сохранение содержимого элемента с директивой v-t

Синтаксис форматирования сообщений

Удаление массива как объекта для интерполяции списков

В Vue I18n v8.x интерполяция списков могла использовать массив как объект параметра, например:

js
import VueI18n from 'vue-i18n'

const i18n = new VueI18n({
  // ...
  messages: {
    en: {
      greeting: 'hello, {0}!'
    }
  },
  // ...
})
html
<p>{{ $t('greeting', { '0': 'kazupon' }) }}</p>

В Vue I18n v9 и новее вы не можете использовать массивы как объекты для интерполяции списков, используйте массив:

html
<p>{{ $t('greeting', ['kazupon']) }}</p>

Причина: Предоставление Translation API с согласованной сигнатурой аргументов

Обработка специальных символов

Сообщения, которые может переводить Vue I18n, могут быть высоко интерполированы с использованием синтаксиса форматирования сообщений, такого как:

txt
@.caml:{'нет яблок'} | {0} яблоко | {n} яблок

Синтаксис форматирования сообщений может использовать следующие специальные символы:

  • {, }, @, $, |

Начиная с Vue I18n v9 и новее, синтаксис форматирования сообщений теперь обрабатывается компилятором форматирования сообщений. Если вы используете эти специальные символы как часть сообщения, это приведет к ошибке компиляции. Если вы хотите использовать эти специальные символы, вы должны использовать литеральную интерполяцию.

txt
// Например, использование `@` для адреса электронной почты
{emailIdentity}{'@'}{emailDomain}

Причина: Чтобы компилятор форматирования сообщений корректно обрабатывал специальные символы синтаксиса форматирования, необходимо ограничить их использование.

Удаление группировки скобок для связанных сообщений

В Vue I18n v8.x различали ссылки на ключи в связанных сообщениях и сообщения, использующие скобки (), чтобы отличать их друг от друга.

Vue I18n v8.x:

js
const messages = {
  en: {
    message: {
      dio: 'DIO',
      linked: 'Есть причина, ты проиграл, @:(message.dio).'
    }
  }
}

В Vue I18n v9 и новее скобки больше не требуются, поскольку компилятор форматирования сообщений позволяет обрабатывать именные, списочные и буквальные интерполяции.

Vue I18n v9 или новее:

js
const messages = {
  en: {
    message: {
      dio: 'DIO',
      linked: "Есть причина, ты проиграл, @:{'message.dio'}."
    }
  }
}

Директива v-t

Удаление модификатора preserve

CAUTION

Код реализации модификатора preserve будет полностью удален в версии v10.

Аналогично Удалению опции preserveDirectiveContent, директива v-t для Vue 3 теперь сохраняет контент по умолчанию. Поэтому модификатор preserve был удален из директивы v-t.

Vue I18n v8.x:

html
<p v-t.preserve="'hello'"></p>

Причина: Сохранение содержимого элемента с директивой v-t

Компонент перевода

Переименование i18n-t из i18n

Имя тега компонента перевода (называемого функциональным компонентом i18n в Vue I18n v8.x) было изменено.

Vue I18n v8.x:

html
<i18n path="message.greeting" />

Vue I18n v9 или новее:

html
<i18n-t keypath="message.greeting" />

Причина: имя тега совпадает с блоками кастомных i18n <i18n>, что создает путаницу с именами блоков и подвержено ошибкам в SFC.

Свойство tag необязательное

В Vue I18n v8.x свойство tag можно было использовать для отображения дочерних элементов без корневого элемента, указав имя тега и булево значение false.

Vue I18n v8.x:

html
<i18n :tag="false" path="message.greeting">
  <span>привет!</span>
</i18n>

Начиная с Vue I18n v9 или новее, вы можете сделать то же самое, просто опустив свойство tag.

Vue I18n v9 или новее:

html
<i18n-t keypath="message.greeting">
  <span>привет!</span>
</i18n-t>

Причина: Теперь Vue 3 поддерживает фрагменты

Переименование свойства keypath из path

Vue I18n v8.x:

html
<i18n path="message.greeting" />

Vue I18n v9 или новее:

html
<i18n-t keypath="message.greeting" />

Удаление синтаксиса place с атрибутом place и свойством places

В Vue I18n v9 и новее атрибут place и свойство places были удалены из интерполяции компонентов.

Vue I18n v8.x:

html
<i18n path="info" tag="p" :places="{ limit: refundLimit }">
  <span place="limit">{{ refundLimit }}</span>
  <a place="action" :href="refundUrl">{{ $t('refund') }}</a>
</i18n>

Vue I18n v9 или новее:

html
<i18n-t keypath="info" tag="p">
  <template #limit>
    <span>{{ refundLimit }}</span>
  <template>
  <template #action>
    <a :href="refundUrl">{{ $t('refund') }}</a>
  <template>
</i18n-t>

Причина: Возможность сделать то же самое с помощью слотов

Компонент NumberFormat

Свойство tag необязательное

Аналогично разделу компонента перевода, в компоненте NumberFormat (называемом функциональным компонентом i18n-n в Vue I18n v8.x) свойство tag можно было использовать для отображения дочерних элементов без корневого элемента, указав имя тега и булево значение false.

Vue I18n v8.x:

html
<i18n-n :tag="false" :value="100" format="currency">
  <span v-slot:integer="slotProps" styles="font-weight: bold">{{ slotProps.integer }}</span>
</i18n-n>

Начиная с Vue I18n v9 или новее, вы можете сделать то же самое, просто опустив свойство tag.

Vue I18n v9 или новее:

html
<i18n-n :value="100" format="currency">
  <span v-slot:integer="slotProps" styles="font-weight: bold">{{ slotProps.integer }}</span>
</i18n-n>

Причина: Теперь Vue 3 поддерживает фрагменты