Локализация Vue-приложения — не просто перевод строк. На одном из проектов с 8 языками мы получили вспухший бандл на 2 мегабайта только из-за статической загрузки всех переводов. Клиент жаловался на медленный TTFB и низкий LCP. Пришлось переписывать на ленивую загрузку — бандл уменьшился в 5 раз, метрики Core Web Vitals пришли в норму. Такая история повторяется часто: разработчики недооценивают влияние переводов на производительность.
Правильная настройка vue-i18n решает не только проблемы с размером бандла, но и типичные ошибки: неправильная плюрализация для русского языка, конфликты с SSR при гидратации, отсутствие типизации ключей. Наш опыт — 5+ лет работы с Vue и более 20 проектов по локализации — гарантирует надёжное решение, которое работает с первого раза.
Официальная документация vue-i18n рекомендует использовать Composition API и ленивую загрузку для крупных проектов. Мы придерживаемся этого подхода и адаптируем его под конкретные задачи.
Почему стоит использовать vue-i18n?
Vue I18n — официальное расширение, полностью интегрированное с Vue 3. Оно поддерживает Composition API, ленивую загрузку, форматирование дат/чисел и SSR через Nuxt. По сравнению с самодельными решениями, vue-i18n даёт готовые механизмы плюрализации и интерполяции, что сокращает время разработки в 2 раза. Кроме того, это отраслевой стандарт для экосистемы Vue.
Как решить проблему гидратации с SSR?
При SSR Vue I18n может вызывать ошибки гидратации из-за несовпадения локалей на сервере и клиенте. Решение — синхронизировать локаль через cookie или заголовок запроса, а также использовать sync: false в конфигурации. В Nuxt модуль @nuxtjs/i18n делает это автоматически, считывая локаль из accept-language и сохраняя в cookie.
Пример конфигурации с cookie
// nuxt.config.ts
export default defineNuxtConfig({
i18n: {
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
alwaysRedirect: true
}
}
})
Когда нужна ленивая загрузка переводов?
Для приложений с десятками локалей загружать все переводы сразу на старте — непозволительная роскошь. Начальный бандл может вырасти на мегабайты, что критично для LCP и TTI. Ленивая загрузка загружает только актуальный язык, а остальные — по требованию. Это уменьшает размер бандла в 4–10 раз в зависимости от числа языков.
| Подход |
Размер бандла (10 языков) |
Время загрузки |
UX |
| Статическая загрузка |
~1 MB |
2 секунды |
- |
| Ленивая загрузка |
~100 KB |
0.3 секунды |
+ |
Как мы настраиваем vue-i18n?
Установка и базовая конфигурация
npm install vue-i18n@9
// src/i18n/index.ts
import { createI18n } from 'vue-i18n'
import ru from './locales/ru.json'
import en from './locales/en.json'
export type MessageSchema = typeof ru
const i18n = createI18n<[MessageSchema], 'ru' | 'en'>({
legacy: false,
locale: 'ru',
fallbackLocale: 'en',
messages: { ru, en },
datetimeFormats: {
ru: { short: { day: 'numeric', month: 'short', year: 'numeric' } },
en: { short: { month: 'short', day: 'numeric', year: 'numeric' } }
},
numberFormats: {
ru: { currency: { style: 'currency', currency: 'RUB' } },
en: { currency: { style: 'currency', currency: 'USD' } }
}
})
export default i18n
Основные возможности
- Плюрализация: поддерживает до 4 форм для русского языка.
- Форматирование дат и чисел: встроенные форматеры с привязкой к локали.
- TypeScript: строгая типизация ключей через MessageSchema.
- Ленивая загрузка: загружаем переводы только для текущего языка.
Как организовать ленивую загрузку переводов?
Для больших приложений критично не грузить все переводы сразу. Реализуем через динамический импорт:
// src/i18n/index.ts
const i18n = createI18n({ legacy: false, locale: 'ru', messages: { ru } })
const loaded = new Set(['ru'])
export async function loadLocale(locale: string) {
if (loaded.has(locale)) return
const msgs = await import(`./locales/${locale}.json`)
i18n.global.setLocaleMessage(locale, msgs.default)
loaded.add(locale)
}
Используем в роутере:
router.beforeEach(async (to) => {
const locale = to.params.locale || 'ru'
await loadLocale(locale)
i18n.global.locale.value = locale
})
Чем отличается настройка для Nuxt?
Для Nuxt используем официальный модуль, который автоматически интегрируется с vue-i18n, поддерживает SSR и SEO. Конфигурация минимальна:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
locales: [
{ code: 'ru', language: 'ru-RU', file: 'ru.json', name: 'Русский' },
{ code: 'en', language: 'en-US', file: 'en.json', name: 'English' }
],
defaultLocale: 'ru',
lazy: true,
langDir: 'locales/',
strategy: 'prefix_except_default'
}
})
Что входит в настройку i18n?
| Этап |
Длительность |
Результат |
| Анализ требований |
0.5 дня |
Список языков, ключи, формат |
| Конфигурация плагина |
0.5 дня |
Работающая базовая локализация |
| Интеграция с роутером |
1 день |
Локализованные маршруты |
| Настройка ленивой загрузки |
1 день |
Минимальный бандл при старте |
| Тестирование |
0.5 дня |
Проверка всех языков и плюрализации |
Сроки и стоимость
Базовая настройка vue-i18n для 2 языков занимает 1 день. Полная интеграция с Nuxt, ленивой загрузкой и локализованными маршрутами — 2–3 дня. Стоимость настройки vue-i18n под ключ — от 8 000 ₽ для базового Vue-приложения, от 18 000 ₽ при интеграции с SSR и кастомными маршрутами.
Мы сопровождаем внедрение: помогаем разобраться с нюансами плюрализации в русском языке (четыре формы против двух в английском), настраиваем строгую типизацию ключей через TypeScript и документируем правила добавления переводов для всей команды. Это исключает дублирующие ключи и хардкод строк в компонентах. В итоге добавление нового языка занимает 2–4 часа вместо нескольких дней.
Получите консультацию — свяжитесь с нами, чтобы обсудить детали. Мы гарантируем, что после настройки ваше Vue-приложение корректно отображается на всех целевых языках и не теряет в производительности.
Фронтенд-разработка React: от аудита до production
Бандл вырос до 3.1 MB gzip — это реальная цифра из проекта, который пришёл к нам на аудит. Причина: moment.js (72 KB) тянул локали для всех 160 языков, lodash импортировался целиком вместо tree-shake, три компонентные библиотеки подключены одновременно. TTFB отличный, но TTI (Time to Interactive) на мобильном — 14 секунд. Пользователи уходили, конверсия упала на 40%. Мы переписали фронтенд: убрали дублирование библиотек, внедрили динамические импорты и SSR. Результат — бандл уменьшился до 850 KB gzip, TTI — 2.1 секунды, LCP — 1.8 с.
Frontend — это не «нарисовать красиво». Это производительность, типизация, рендеринг-стратегия, bundle management и поддерживаемость на годы.
Почему Next.js — стандартный выбор для SEO?
React — наш основной UI-фреймворк для сложных интерфейсов. Next.js — стандартный выбор для проектов с SEO-требованиями или SSR. App Router (с версии 13) принёс React Server Components, streaming и fetch с built-in кешированием. Это реальные преимущества: страница каталога с тысячами товаров рендерится на сервере без отправки логики фильтрации на клиент, JS-бандл меньше на 30%.
Но App Router — другой способ мышления. "use client" нужно ставить осознанно. Реальная ошибка: разработчик помечает весь layout как "use client" из-за одного состояния навигации — и теряет все преимущества RSC. Правило: держать Server Components как можно выше в дереве, "use client" — только для интерактивных листовых компонентов. ISR (Incremental Static Regeneration) — мощный инструмент для контентных сайтов. На каталоге из 50 000 страниц с ISR и CDN — TTFB < 50 ms для любой страницы.
Как TypeScript предотвращает баги в продакшене?
TypeScript обязателен на любом проекте, который планируется поддерживать дольше 3 месяцев или в команде больше одного разработчика. Аргумент «пишем быстро без типов» работает только первые 2 недели. После — баги, связанные с неопределёнными значениями, возникают каждую неделю.
Конкретная польза: рефакторинг API-ответа — изменил тип в одном месте, TypeScript показывает все места, где нужно адаптировать код. Без типов — баг в продакшене через неделю. strict: true в tsconfig.json — обязательно. noImplicitAny, strictNullChecks, strictFunctionTypes. Боль от Type 'undefined' is not assignable в разработке стоит меньше, чем Cannot read properties of undefined в продакшене. tRPC — end-to-end типизация от бэкенда до фронтенда без отдельной схемы — изменяя тип процедуры, вы сразу видите места на фронтенде, требующие правки.
Vue 3 + Nuxt 3 — альтернативный стек для SSR
Vue 3 с Composition API — другой стиль разработки, ближе к React Hooks. <script setup> и composables делают код более переиспользуемым. Nuxt 3 — фреймворк для Vue с SSR/SSG, аналогичный Next.js. useAsyncData и useFetch — встроенные composables с дедупликацией запросов и hydration. Auto-imports удобны, но могут запутывать при debug. Nuxt Content — модуль для Markdown/MDX-файлов, идеален для документации.
Hydration mismatch — специфическая боль SSR на Vue и React. Решение: <ClientOnly> компонент для браузерного контента, suppressHydrationWarning для dynamic timestamps.
Производительность: метрики и инструменты
Bundle analysis — стартовая точка. @next/bundle-analyzer или rollup-plugin-visualizer — запускаем перед каждым мажорным деплоем. Цель: ни одна страница не должна требовать > 200 KB JS gzip для first paint.
Динамические импорты для тяжёлых компонентов:
const RichEditor = dynamic(() => import('@/components/RichEditor'), {
ssr: false,
loading: () => <EditorSkeleton />,
});
Редактор (Tiptap, Quill, CodeMirror) — типичные кандидаты на dynamic import. Без этого они попадают в основной бандл. React DevTools Profiler — для поиска лишних ре-рендеров. React.memo, useMemo, useCallback — точечные инструменты. Преждевременная мемоизация всего подряд добавляет overhead без пользы. Профилируйте сначала, оптимизируйте потом.
Виртуализация длинных списков: @tanstack/virtual или react-window рендерят только видимые элементы. Таблица с 50 000 строк: с виртуализацией — 60fps, без — браузер зависает при скролле.
State management: без оверинжиниринга
Для большинства приложений достаточно:
-
React Query / TanStack Query — для серверного состояния (данные из API, кеширование, инвалидация)
-
Zustand — для глобального клиентского состояния (легковесный, без бойлерплейта Redux)
-
React Hook Form — для форм
Redux Toolkit оправдан для очень сложного глобального состояния с большим количеством взаимодействий. Для большинства задач — это overkill. Recoil, Jotai — атомарные подходы для независимых кусков состояния.
CSS и дизайн-система
Tailwind CSS последней версии — наш стандартный выбор для новых проектов. Utility-first, отличная интеграция с компонентными библиотеками (Radix UI, Headless UI), PostCSS pipeline. CSS Modules — альтернатива когда нужна более явная изоляция стилей. Radix UI + Tailwind (Shadcn/ui паттерн) — headless компоненты с полным контролем над стилями. Нет dependency lock-in: компоненты копируются в проект и полностью кастомизируются. Storybook — для документирования компонентной библиотеки.
React DevTools Profiler — официальный инструмент от команды React.
Тестирование
| Уровень |
Инструмент |
Что тестируем |
| Unit |
Vitest |
Утилиты, хуки, чистые функции |
| Component |
Testing Library |
Рендер, взаимодействия |
| E2E |
Playwright |
Критичные пользовательские флоу |
| Visual |
Chromatic (Storybook) |
Регрессия UI |
E2E тесты через Playwright — для checkout, авторизации, критичных форм. Не для всего подряд: поддержка большой e2e-сюиты дорогая, поэтому выбираем 3-5 ключевых сценариев.
Ориентиры по срокам и состав работ
| Задача |
Срок |
| SPA (дашборд, CRM-интерфейс) |
8–16 недель |
| Next.js сайт с SSR/ISR |
6–14 недель |
| Frontend для существующего API |
4–10 недель |
| Компонентная библиотека |
6–12 недель |
Стоимость рассчитывается после декомпозиции на компоненты, экраны и интеграции с API. Мы используем N+1 оценку: прибавляем 20% на риски.
Что входит в работу: исходный код в Git, документация по архитектуре и компонентам, доступ к CI/CD, обучение вашей команды (2-3 встречи), гарантия 3 месяца на выявленные баги. Дополнительно — покрытие юнит-тестами ключевых модулей.
У нас 5 лет опыта в фронтенд-разработке, более 50 выполненных проектов, команда из 10 инженеров, владеющих React, Vue, Angular. Работаем с технологиями, описанными в документации React и TypeScript. Дополнительные сведения можно найти в Wikipedia: React и Wikipedia: TypeScript.
Чек-лист типичных ошибок при начале проекта
- Игнорирование tree-shaking: импорт целой библиотеки вместо выборочных модулей.
- Отсутствие code-splitting: тяжёлый код загружается сразу, а не по требованию.
- Пренебрежение типобезопасностью: отсутствие
strict в tsconfig — прямой путь к багам.
- Избыточная мемоизация:
useMemo и useCallback там, где они не нужны.
- Выбор неподходящего state-менеджера: Redux Toolkit на маленьких проектах.
Какой стек выбрать для фронтенд-разработки React?
Мы сравниваем инструменты по реальным метрикам. Next.js быстрее Nuxt в сборке SSR на 20–30% при одинаковом размере страницы. TypeScript снижает количество production-багов на 60–70% по сравнению с JavaScript. Экономия на поддержке такого проекта — до 500 000 рублей в год за счёт сокращения времени на отладку. Если вам нужен лёгкий SPA с минимальной стоимостью — достаточно React + Vite. Для контентного сайта с SEO — Next.js с ISR даёт TTFB ниже 50 мс даже при 50 000 страниц.
Получите консультацию по вашему проекту: оценим текущий код и предложим план оптимизации. Закажите аудит — найдём узкие места и покажем, как сократить бюджет без потери качества.