Поддержка региональных вариантов

Поддержка региональных вариантов в i18next основана на работе с языковыми тегами стандарта BCP 47, где язык и регион кодируются в одном идентификаторе. Такой подход позволяет разделять не только разные языки, но и локализованные формы одного языка: различия в орфографии, форматах дат, числах, падежах и терминологии.

Типичный формат идентификатора:

  • en — английский язык без уточнения региона
  • en-US — английский (США)
  • en-GB — английский (Великобритания)
  • ru — русский язык
  • ru-RU — русский (Россия)
  • pt — португальский
  • pt-BR — бразильский португальский
  • zh — китайский (обобщённый)
  • zh-CN, zh-TW — упрощённый и традиционный варианты

i18next трактует такие идентификаторы как иерархию, где региональный вариант может наследовать базовый язык.


Иерархия языков и механизм fallback

Основой работы региональных вариантов является механизм fallback. Если перевод для регионального кода отсутствует, используется более общий язык.

Пример иерархии:

en-US → en → fallbackLng
ru-KZ → ru → fallbackLng
pt-BR → pt → fallbackLng

Конфигурация fallback задаётся через fallbackLng:

import i18n from 'i18next';

i18n.init({
  lng: 'en-US',
  fallbackLng: 'en',
  resources: {
    en: {
      translation: {
        greeting: "Hello"
      }
    },
    en-US: {
      translation: {
        greeting: "Howdy"
      }
    }
  }
});

В этом примере при запросе en-US используется специфичная строка "Howdy", а при отсутствии ключа — значение из en.


Структура ресурсов для региональных локалей

Организация ресурсов напрямую влияет на масштабируемость поддержки регионов. Варианты структурирования:

Разделение по языку и региону

locales/
  en/
    translation.json
  en-US/
    translation.json
  en-GB/
    translation.json
  ru/
    translation.json
  ru-RU/
    translation.json

Пример содержимого:

// locales/en/translation.json
{
  "currency": "USD",
  "dateFormat": "MM/DD/YYYY"
}
// locales/en-GB/translation.json
{
  "currency": "GBP",
  "dateFormat": "DD/MM/YYYY"
}

Наследование через базовый язык

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

i18n.init({
  fallbackLng: 'en',
  resources: {
    en: {
      translation: {
        currency: "USD",
        greeting: "Hello"
      }
    },
    "en-GB": {
      translation: {
        currency: "GBP"
      }
    }
  }
});

Значение greeting для en-GB будет взято из en.


Поддержка множественных fallback уровней

i18next позволяет задавать каскад fallback-локалей:

i18n.init({
  fallbackLng: {
    'en-GB': ['en-GB', 'en', 'default'],
    'ru-KZ': ['ru-KZ', 'ru', 'default']
  }
});

Такая структура полезна при частичном перекрытии региональных различий.


Автоматическое определение регионального варианта

Модуль i18next-browser-languagedetector позволяет извлекать регион из окружения пользователя:

import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';

i18n
  .use(LanguageDetector)
  .init({
    fallbackLng: 'en',
    detection: {
      order: ['navigator', 'htmlTag', 'cookie', 'localStorage']
    }
  });

Если браузер возвращает en-US, библиотека попытается использовать именно этот вариант.


Нормализация языковых кодов

i18next приводит к единому формату:

  • EN-usen-US
  • ru_ruru-RU
  • pt_brpt-BR

Это позволяет избегать дублирования ресурсов из-за различий в написании.


Региональные различия в форматировании

Хотя i18next отвечает за перевод строк, интеграция с Intl API обеспечивает локализацию форматов.

Числа

const value = 123456.78;

new Intl.NumberFormat('en-US').format(value); // 123,456.78
new Intl.NumberFormat('de-DE').format(value); // 123.456,78

В связке с i18next региональный код используется как единый источник локали.


Даты

new Intl.DateTimeFormat('en-GB').format(new Date());
new Intl.DateTimeFormat('en-US').format(new Date());

Разделение локалей в i18next часто синхронизируется с форматированием дат через пользовательские хелперы:

i18n.services.formatter.add('date', (value, lng) => {
  return new Intl.DateTimeFormat(lng).format(new Date(value));
});

Региональные различия в переводах

Различия между региональными вариантами часто касаются:

  • терминологии
  • формальных обращений
  • валют
  • единиц измерения
  • юридических формулировок

Пример:

const resources = {
  en: {
    translation: {
      "payment": "Payment"
    }
  },
  "en-US": {
    translation: {
      "payment": "Checkout"
    }
  },
  "en-GB": {
    translation: {
      "payment": "Payment"
    }
  }
};

Региональные изменения могут быть минимальными, но важными для UX.


Namespace-структура с учётом регионов

i18next поддерживает разделение по namespace, что позволяет комбинировать региональные вариации и модули приложения.

en-US:
  common.json
  checkout.json
  profile.json
i18n.init({
  ns: ['common', 'checkout', 'profile'],
  defaultNS: 'common',
  resources: {
    "en-US": {
      common: {
        title: "Dashboard"
      },
      checkout: {
        button: "Pay now"
      }
    }
  }
});

Переопределение регионов на уровне ключей

Региональные различия могут быть точечными, без дублирования всей локали.

{
  "en": {
    "button.save": "Save"
  },
  "en-US": {
    "button.save": "Save changes"
  }
}

Такая структура снижает объём повторяющихся переводов.


Работа с множественными региональными группами

Для языков с множеством регионов применяется группировка:

i18n.init({
  fallbackLng: 'en',
  load: 'languageOnly'
});

Режим languageOnly отключает строгую привязку к региону:

  • en-USen
  • en-GBen

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


Разделение ресурсов при CDN-архитектуре

При масштабировании приложения региональные переводы часто загружаются отдельно:

i18n.init({
  backend: {
    loadPath: '/locales/{{lng}}/{{ns}}.json'
  }
});

Запросы могут выглядеть так:

/locales/en-US/common.json
/locales/ru-RU/common.json

Это позволяет минимизировать объём загружаемых данных.


Региональные особенности плюрализации

Некоторые языки используют разные правила множественного числа в зависимости от региона.

i18next подключает ICU или встроенные правила:

i18n.init({
  compatibilityJSON: 'v3',
  returnObjects: true
});

Пример:

{
  "item": "{{count}} item",
  "item_plural": "{{count}} items"
}

Регион может влиять на отображение форм через кастомные правила.


Смешанные сценарии: язык + регион + устройство

При сложной конфигурации выбирается приоритет:

  1. Явно установленный язык
  2. Браузерный язык
  3. Регион устройства
  4. fallbackLng
i18n.init({
  lng: 'ru-KZ',
  fallbackLng: 'ru'
});

Если ru-KZ отсутствует, используется ru.


Конфликты между региональными ключами

Конфликты возникают при:

  • частичном дублировании ключей
  • несовместимых форматах
  • неправильной иерархии fallback

Пример проблемной структуры:

ru/
ru-RU/
ru-KZ/

без чёткой стратегии наследования приводит к неоднозначности выбора ресурса.