Как перестать бояться и начать локализовать: Интернационализация TypeScript-приложений
Вы когда-нибудь задумывались, почему одни проекты выходят на международный уровень, а другие остаются "русскоязычными стартапами"? Чаще всего ответ прост: локализация. Да, та самая страшная аббревиатура i18n, от которой у многих разработчиков начинается нервный тик. Но давайте честно: сделать TypeScript приложение интернационализированным — это не ракетостроение. Это просто набор правильных подходов и инструментов. Сегодня мы разберем это на практике, с живыми примерами кода, без воды и заумных теорий.
Почему TypeScript — идеальный кандидат для i18n?
TypeScript дает нам то, чего не хватает обычному JavaScript: статическую типизацию. Когда дело доходит до переводов, это становится суперсилой. Представьте: вы меняете ключ перевода, и TypeScript кричит еще до запуска приложения: "Эй, ты забыл обновить перевод в испанской локали!". Согласитесь, это лучше, чем ловить баги в продакшене.
Более того, современные библиотеки для i18n в TypeScript позволяют генерировать типы непосредственно из файлов перевода. Это означает, что автодополнение в IDE будет работать как часы. Никаких магических строк, никаких опечаток. Только чистый, безопасный код.
Выбор библиотеки: i18next vs react-intl
На рынке есть два основных игрока: i18next и react-intl (часть FormatJS). Оба отлично работают с TypeScript, но их подходы различаются.
- i18next — швейцарский нож интернационализации. Поддерживает плюрализацию, интерполяцию, контексты, ленивую загрузку. Отлично подходит для больших проектов.
- react-intl — более легковесный, заточен под React. Использует компонентный подход (
<FormattedMessage>) и мощную систему ICU MessageFormat.
В этой статье мы будем использовать i18next с официальным адаптером React react-i18next. Почему? Потому что это самый популярный стек и он дает максимальный контроль.
Пошаговая настройка: от нуля до первого перевода
Перейдем сразу к делу. Устанавливаем зависимости:
npm install i18next react-i18next i18next-browser-languagedetectorТеперь создадим файл конфигурации. Это сердце интернационализации нашего TypeScript-приложения.
// i18n.tsimport i18n from 'i18next';import { initReactI18next } from 'react-i18next';import LanguageDetector from 'i18next-browser-languagedetector';
import enTranslation from './locales/en/translation.json';import ruTranslation from './locales/ru/translation.json';
i18n .use(LanguageDetector) // автоматическое определение языка браузера .use(initReactI18next) // интеграция с React .init({ resources: { en: { translation: enTranslation }, ru: { translation: ruTranslation }, }, fallbackLng: 'en', // если перевод не найден interpolation: { escapeValue: false, // React уже экранирует }, });
export default i18n;Обратите внимание на fallbackLng. Это критически важно для пользовательского опыта: если придет пользователь с браузером на суахили, мы покажем ему английскую версию, а не пустой экран.
Структура файлов перевода
Создадим папку locales и внутри нее подпапки для каждого языка. Вот пример файла en/translation.json:
{ "welcome": "Welcome to our application!", "description": "This is a {{framework}} app with i18n support.", "items": { "zero": "No items", "one": "One item", "other": "{{count}} items" }}А вот его русский аналог:
{ "welcome": "Добро пожаловать в наше приложение!", "description": "Это приложение на {{framework}} с поддержкой i18n.", "items": { "zero": "Нет элементов",