логотип PurpleSchool
логотип PurpleSchool

Многоязычные приложения на Vue с i18n

Автор

Алексей Иванов

Введение

Приложения, которые поддерживают несколько языков, становятся стандартом для современных веб-сервисов. Пользователи хотят видеть интерфейс и получать сообщения на своем родном языке, а для разработчика вопрос поддержки нескольких языков больше не роскошь, а востребованная особенность. В экосистеме Vue для этих задач существует мощное и удобное решение — библиотека vue-i18n. С помощью vue-i18n можно буквально за несколько шагов добавить поддержку локализации (интернационализации, или i18n) в Vue-приложение любого масштаба.

В этой статье вы узнаете, как подключить vue-i18n, организовать структуру языковых файлов, менять языки на лету, управлять динамическими переводами и параметрами внутри переводимых строк. Также разберем, какие возможности и подводные камни предоставляет этот популярный инструмент.

Основы интеграции vue-i18n в Vue-приложение

Установка vue-i18n

Для начала вам потребуется установить саму библиотеку. Сделать это можно через npm или yarn:

npm install vue-i18n@next

Если вы работаете с Vue 2, используйте совместимую версию:

npm install vue-i18n@8

Обратите внимание: для Vue 3 нужен vue-i18n версии 9+, для Vue 2 — версия 8.

Подключение vue-i18n к приложению

Теперь, когда пакет установлен, давайте подключим его к приложению. Смотрите, как это делается для Vue 3 (Composition API):

// main.js
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import App from './App.vue'

// Импортируем объект с переводами
import messages from './locales'

// Инициализируем i18n
const i18n = createI18n({
  locale: 'en', // язык по умолчанию
  fallbackLocale: 'ru', // запасной язык
  messages, // все переводы
})

const app = createApp(App)
app.use(i18n)
app.mount('#app')

Если вы работаете с Vue 2, подключение немного отличается:

// main.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import App from './App.vue'
import messages from './locales'

Vue.use(VueI18n)

const i18n = new VueI18n({
  locale: 'ru',
  fallbackLocale: 'en',
  messages,
})

new Vue({
  i18n,
  render: h => h(App)
}).$mount('#app')

Теперь i18n доступен во всех компонентах.

Организация и хранение переводов

Лучшие практики хранения переводов

Обычно переводы хранят в виде JSON или JS-объектов. На небольших проектах можно все переводы держать внутри одного файла:

// src/locales/index.js
export default {
  en: {
    welcome: "Welcome",
    logout: "Log out",
  },
  ru: {
    welcome: "Добро пожаловать",
    logout: "Выйти",
  }
}

Но если проект масштабируется, стоит разделить переводы по отдельным файлам:

src/
└── locales/
    ├── en.json
    └── ru.json

И собирать их вместе:

import en from './locales/en.json'
import ru from './locales/ru.json'

export default { en, ru }

Этот подход обеспечивает удобство масштабирования и поддержку большого числа языков.

Структура файла с переводом

Используйте вложенность для группировки строк по разделам интерфейса:

{
  "navbar": {
    "home": "Home",
    "about": "About us",
    "contact": "Contacts"
  },
  "auth": {
    "login": "Sign in",
    "logout": "Log out"
  }
}

Эта структура избавляет от конфликтов и дублирования ключей.

Основные возможности vue-i18n

Статические и динамические переводы

Вы легко можете добавить простую статическую строку через директиву $t:

<template>
  <div>{{ $t('welcome') }}</div>
</template>

Если необходимо работать с вложенными ключами, используйте точку:

<template>
  <nav>
    <a>{{ $t('navbar.home') }}</a>
    <a>{{ $t('navbar.about') }}</a>
  </nav>
</template>

Подстановка параметров

Vue-i18n поддерживает шаблоны с параметрами. Пример определения и использования строки с параметром:

{
  "greeting": "Hello, {name}!"
}

Обратите внимание на фигурные скобки для плейсхолдеров. Теперь подставим значение:

<template>
  <div>{{ $t('greeting', { name: userName }) }}</div>
</template>
<script>
export default {
  data() {
    return { userName: 'Alex' }
  }
}
</script>

Результат: "Hello, Alex!"

Плюральные формы

Число может влиять на форму слова. Vue-i18n позволяет определять множественные формы:

{
  "car": "No cars | One car | {count} cars"
}

Вызовите с параметром count:

<div>{{ $tc('car', 0) }}</div> <!-- No cars -->
<div>{{ $tc('car', 1) }}</div> <!-- One car -->
<div>{{ $tc('car', 5) }}</div> <!-- 5 cars -->

Если нужны параметры, комбинируйте их:

<div>{{ $tc('car', carCount, { count: carCount }) }}</div>

А если проект требует поддержки сложных правил множественного числа (например, для русского или польского языков), подключите специальные правила pluralizationRules.

Смена языка на лету

Покажу, как сделать переключатель языков:

<template>
  <select v-model="$i18n.locale">
    <option value="en">English</option>
    <option value="ru">Русский</option>
  </select>
</template>

Обратите внимание: $i18n.locale — реактивное свойство. Изменение его значения тут же переключает все тексты на другой язык.

Если вы используете Composition API, доступ к locale выглядит так:

import { useI18n } from 'vue-i18n'

setup() {
  const { locale } = useI18n()
  // Теперь можно менять locale.value
  return { locale }
}

Загрузка переводов по требованию (Lazy loading)

В больших приложениях грузить все языки сразу — не лучшая идея. Реализуем асинхронную подгрузку языковых файлов:

// Предположим, что мы динамически импортируем нужный язык
async function loadLocaleMessages(i18n, locale) {
  const messages = await import(`./locales/${locale}.json`)
  i18n.global.setLocaleMessage(locale, messages.default)
  i18n.global.locale.value = locale
}

Такой подход позволяет разбивать бандл и не загружать пользователю лишний контент.

Использование переводов во script

Кроме шаблонов, переводы доступны в JS-коде компонентов:

methods: {
  showAlert() {
    alert(this.$t('auth.login')) // "Sign in"
  }
}

Или с Composition API:

import { useI18n } from 'vue-i18n'

setup() {
  const { t } = useI18n()
  function showMessage() {
    alert(t('auth.login'))
  }
  return { showMessage }
}

Локализация дат, времени и чисел

Vue-i18n умеет форматировать даты и числа согласно выбранной локали. Для этого надо дополнительно определить форматы:

const i18n = createI18n({
  // ...
  datetimeFormats: {
    en: { short: { year: 'numeric', month: 'short', day: 'numeric' } },
    ru: { short: { year: 'numeric', month: 'short', day: 'numeric' } }
  },
  numberFormats: {
    en: { currency: { style: 'currency', currency: 'USD' } },
    ru: { currency: { style: 'currency', currency: 'RUB' } }
  }
})

Использование в шаблоне:

<div>{{ $d(new Date(), 'short') }}</div> <!-- 18 Mar 2024 -->
<div>{{ $n(2100, 'currency') }}</div> <!-- $2,100.00 / 2 100,00 ₽ -->

Работа с fallback и кастомной логикой

Vue-i18n позволяет назначать fallbackLocale — язык, на который будет переключаться приложение, если для основного не найден перевод. Например, если для 'es' (испанский) нет нужной строки, будет взята версия из 'en' (английский).

Если хотите расширить эту логику (например, fallback только для некоторых ключей), используйте обработчики отсутствующих переводов — missing handlers.

const i18n = createI18n({
  // ...
  missing(locale, key, vm) {
    // Например, выводим в консоль все пропущенные ключи
    console.warn(`Missing translation for key "${key}" in locale "${locale}"`)
    return key // Можно вернуть ключ как fallback
  }
})

Это полезно при разработке и локализации на множество языков.

Локализация на уровне отдельных компонентов

Вы можете определить переводы прямо внутри компонента. Смотрите, как это делается:

export default {
  i18n: {
    messages: {
      en: { hello: "Hello from component" },
      ru: { hello: "Привет из компонента" }
    }
  }
}

Такая изолированная локализация подходит для виджетов, которые могут использоваться вне основного приложения.

Советы по архитектуре и оптимизации

  • Старайтесь создавать переводимые строки с уникальными ключами и структурой, чтобы избежать конфликтов между командами.
  • Разносите общие и проектные переводы по разным секциям, чтобы их было легко обновлять.
  • Используйте проверку покрытия переводами (i18n-линтеры или собственные скрипты), чтобы не пропустить строки на новых языках.
  • Актуализируйте переводы одновременно с обновлениями приложения.

Тестирование многоязычного приложения

Убедитесь, что ваше приложение корректно отображает все тексты для разных языков, а переключение языков не вызывает ошибок. Для автоматического тестирования можно использовать Jest с мок-объектами переводов или cypress/end-to-end тесты для проверки UI.

Заключение

Vue-i18n предоставляет мощный, удобный и гибкий инструмент для поддержки многоязычности в приложениях на Vue любого масштаба. Вы можете хранить переводы так, как удобно команде, легко управлять сменой языка, подставлять параметры, обрабатывать plural-формы, локализовывать даты и числа. Подключить и использовать i18n довольно просто, как показано в примерах. Если вы поддерживаете или создаёте многоязычный продукт — не игнорируйте такие возможности, чтобы ваши приложения были удобны для пользователей по всему миру.

Частозадаваемые технические вопросы по теме статьи и ответы на них

Как добавить поддержку RTL (right-to-left) языков (например, арабский или иврит)?

Чтобы корректно отображать RTL-языки, в момент смены языка проверьте, является ли язык RTL, и добавьте в body тег <body dir="rtl">. Пример:

const rtlLanguages = ['ar', 'he']
watch(locale, (val) => {
  document.body.dir = rtlLanguages.includes(val) ? 'rtl' : 'ltr'
})

Используйте подходящие шрифты в CSS и при необходимости меняйте layout компонентов для RTL.

Как собрать отдельные чанки переводов при сборке (code splitting)?

Воспользуйтесь динамическим импортом языковых файлов, как показано выше, и не забудьте указывать алиасы для Webpack/Vite, чтобы импортировать языки по пути вида @/locales/en.json.

Как добавить поддержку локализации маршрутов в Vue Router?

Для route-based переводов создайте отдельные объекты с переведенными путями, и подключайте их к роутеру через функцию-обертку, подставляя актуальный префикс маршрута (например /ru/about).

Как обновлять переводы без перезапуска приложения (например, при редактировании в админке)?

Используйте метод setLocaleMessage для обновления переводов на лету. После загрузки изменений вызовите:

i18n.global.setLocaleMessage(localeCode, newMessages)

и переводы в интерфейсе применятся сразу.

Как вывести список всех ключей с отсутствующими переводами?

Переберите все ключи базового языка, сравните с другими переводами, выведите разницу в консоль или в отчет. Можно использовать готовые linter-плагины (eslint-plugin-i18n-json) или модульные Node.js скрипты для проверки наличия ключей в файлах.

Стрелочка влевоГайд по импорту и регистрации компонентов на VueИнтеграция FLIR данных с VueСтрелочка вправо

Постройте личный план изучения Vue до уровня Middle — бесплатно!

Vue — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueИнструкция по установке и компонентам Vue sliderРабота с таблицами во Vue через TanStackУправление пакетами и node modules в Vue проектахУправление пакетами Vue js с помощью npmКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Vue 3 и Pinia

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий