Перейти к основному содержимому

Интернационализация и локализация

Версия: 1.0 Дата: 26.04.2026 Статус: Готов к обсуждению

Назначение документа

Документ определяет кросс-доменный слой интернационализации и локализации (internationalization and localization, i18n/L10n) Vitiana — единые каноничные правила работы с языками, валютами, часовыми поясами, форматами дат и чисел, юрисдикциями и регуляторными режимами для всей платформы. Включает:

  • Каноничную модель: SupportedLanguage, SupportedCurrency, RegionLocale, LocaleResolutionPolicy, FxRateSnapshot, TimezonePolicy.
  • Базовый набор языков и валют первой волны.
  • Каноничные различения (source vs presentation, supplier currency vs settlement currency vs display currency).
  • Политику разрешения локали (locale resolution policy) — как платформа выбирает язык, валюту, часовой пояс для конкретного запроса.
  • Политику валютных операций (foreign exchange, FX) — фиксация курсов в момент коммерческой фиксации, отдельная от внутренних взаиморасчётов.
  • Форматирование дат, чисел, валют, телефонов, адресов.
  • Многоязычный контент через ContentTranslation (отсылка к Медиа и контент).
  • Юрисдикционные следствия (расширение по странам — расширение compliance-обязательств).
  • Фазы развёртывания.

Документ читается после:

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

Интернационализация и локализация — сквозной кросс-доменный слой. Без него каждый домен решает локализацию по-своему: поисковая выдача в одном формате, уведомления — в другом, платёжные документы — в третьем. Это разрушает целостность платформы и создаёт регуляторные риски (несоответствие в форматах документов разных контуров).

Реальное состояние реализации (home-to-go-api): уже работают locations и translations ru/uk для 182 стран, выполнен полный geo chain. Это сильный стартовый актив для географической части. Платформа продолжает этот актив, добавляя единый слой управления валютами, часовыми поясами и форматированием.

Правило 00000 (платформа главенствует над поставщиками) применяется здесь напрямую: каноничный набор языков и валют — выбор платформы, не наследование от поставщиков. Stuba отдаёт цены в EUR — платформа конвертирует. HomeToGo отдаёт описания на английском — платформа переводит. Никакой поставщик не диктует, какие языки и валюты поддерживает платформа.

Главное решение

Интернационализация и локализация — единый кросс-доменный слой с каноничными сущностями, едиными правилами разрешения и единой политикой fallback.

Это означает:

  • Каноничный набор поддерживаемых языков и валют — фиксированное множество, расширяемое по плану расширения географии.
  • Единые каноничные различения — source language ≠ canonical language ≠ presentation language. Применимо ко всем контурам (поиск, контент, уведомления, документы).
  • Единая политика разрешения локалиLocaleResolutionPolicy определяет, какой язык, валюта, часовой пояс используется для конкретного запроса. Не каждый контур придумывает свою.
  • Единая политика fallback — при отсутствии перевода или валюты — каноничный путь: запрос → предпочитаемая → fallback страны → английский.
  • Валюта коммерческой фиксации фиксируется в момент Quote — после фиксации цена в этой валюте не меняется ни при каких обстоятельствах. Конвертация — отдельная операция со своим следом.
  • Многоязычный контент через ContentTranslation — единая сущность для всех контентных доменов.
  • Часовой пояс — первоклассный атрибут для всех временных полей платформы. Отображение в локальном времени получателя, хранение в UTC.
  • Юрисдикция — определяющий фактор для compliance, налогов, форматов документов. Каждое расширение географии — расширение юрисдикционной модели.

Правило «один язык внутри одного предложения» (фиксация в feedback_language_rules для документации) применяется и к контенту платформы — пользователь видит только свой язык, без вкраплений английского без расшифровки.

Каноничная модель i18n/L10n

Главные сущности

SupportedLanguage — поддерживаемый язык

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

{
language_code: string (ISO 639-1, two-letter),
language_code_full: string (BCP 47, например ru-UA),
display_name_native: string,
display_name_english: string,
text_direction: enum,
active_in_phase: integer,
fallback_chain: array,
applicable_surfaces: array,
is_active: boolean,
created_at: timestamp,
updated_at: timestamp
}

Поля:

  • language_code — двухбуквенный ISO 639-1 (uk, ru, cs, pl, en, kk).
  • language_code_full — BCP 47 с региональным вариантом, если значимо (ru-UA против ru-RU).
  • display_name_native — название на самом языке (українська, русский, čeština, polski, English, қазақ тілі).
  • display_name_english — название на английском.
  • text_direction — направление текста (ltr — слева направо для всех языков первой волны; rtl — справа налево для арабского, иврита в фазе 4+).
  • active_in_phase — с какой фазы поддерживается.
  • fallback_chain — каноничная цепочка fallback (например, для uk: uk → ru → en; для kk: kk → ru → en).
  • applicable_surfaces — на каких поверхностях используется (некоторые языки могут быть только для интерфейсов агентств, не для конечных клиентов).

SupportedCurrency — поддерживаемая валюта

{
currency_code: string (ISO 4217),
display_name_native: object,
symbol: string,
decimal_places: integer,
rounding_increment: numeric,
display_format_template: object,
applicable_phase: integer,
is_settlement_currency: boolean,
is_display_currency: boolean,
applicable_regions: array,
is_active: boolean,
created_at: timestamp,
updated_at: timestamp
}

Поля:

  • currency_code — ISO 4217 (UAH, EUR, CZK, PLN, KZT, USD).
  • display_name_native — объект с названием на каждом поддерживаемом языке ({uk: "гривня", ru: "гривна", en: "hryvnia"}).
  • symbol — символ валюты (, , , , , $).
  • decimal_places — число дробных разрядов (типично 2; 0 для японской иены — для будущих фаз).
  • rounding_increment — шаг округления (например, 0.05 для CHF).
  • display_format_template — каноничный шаблон форматирования по локалям (например, для EUR: de1.234,56 €; en€1,234.56).
  • is_settlement_currency — может ли быть валютой взаиморасчёта с поставщиком.
  • is_display_currency — может ли быть валютой отображения клиенту.

RegionLocale — региональная локаль

Сущность, представляющая сочетание языка, валюты, часового пояса и форматных правил для конкретного региона.

{
locale_id: UUID,
region_code: string (ISO 3166-1 alpha-2),
language_code: string,
currency_code: string,
timezone_id: string (IANA, например, Europe/Kyiv),
date_format: string,
time_format: string,
number_format: object,
phone_format: object,
address_format: object,
first_day_of_week: enum,
is_default_for_region: boolean,
is_active: boolean
}

Каждая страна первой волны имеет одну или несколько RegionLocale:

  • Украина (UA): uk-UA (главная) + ru-UA (вторая).
  • Чехия (CZ): cs-CZ (главная) + en-CZ (для иностранных клиентов).
  • Польша (PL): pl-PL (главная) + en-PL.
  • Казахстан (KZ): kk-KZ (главная) + ru-KZ (вторая).

LocaleResolutionPolicy — политика разрешения локали

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

{
policy_id: UUID,
applicable_surfaces: array,
resolution_rules: array,
default_locale_id: UUID,
fallback_locale_id: UUID,
apply_subject_preferences: boolean,
apply_tenant_preferences: boolean,
apply_geo_inference: boolean,
apply_browser_hints: boolean,
is_active: boolean
}

Политика определяет, в каком порядке учитываются источники предпочтения:

  1. Явно переданная клиентом локаль (через параметр запроса или заголовок Accept-Language).
  2. Сохранённое предпочтение субъекта (для авторизованного клиента из RecipientPreferences).
  3. Конфигурация тенанта (тенант может задать локаль по умолчанию для своей поверхности).
  4. Геогеогра́фический вывод (по IP-адресу или явному региону).
  5. Подсказки браузера (Accept-Language).
  6. Глобальный default (en-US или специфический для платформы).

FxRateSnapshot — снимок курса валют

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

{
snapshot_id: UUID,
base_currency: string,
quote_currency: string,
rate: numeric,
rate_source: string,
rate_timestamp: timestamp,
margin_applied: numeric,
applicable_purpose: enum,
associated_entity_type: enum,
associated_entity_id: UUID,
expires_at: timestamp
}

Каждая конвертация валют — со своим снимком, не «текущий курс на момент чтения».

Поля:

  • rate_source — источник курса (provider:stripe / provider:adyen / provider:central_bank_eu / provider:central_bank_ua / internal_aggregated).
  • margin_applied — маржа платформы поверх курса источника (если применима, открыто фиксируется).
  • applicable_purpose — для чего используется (quote_display / booking_payment / supplier_settlement / partner_billing / internal_reporting).
  • associated_entity_type — к какой сущности привязан снимок (quote, booking, settlement).
  • expires_at — срок действия снимка (для отображения в поиске — типично минуты; для коммерческой фиксации — на весь срок коммерческой фиксации; для бронирования — навсегда).

TimezonePolicy — политика часовых поясов

Сущность, определяющая правила применения часовых поясов в каждом контуре платформы.

{
policy_id: UUID,
applicable_surface: string,
applicable_context: enum,
storage_format: enum,
display_timezone_source: enum,
is_dst_aware: boolean
}

Каноничные правила:

  • Хранение — все временные метки хранятся в UTC. Без исключений.
  • Отображение пользователю — в локальном часовом поясе субъекта.
  • Источник часового пояса для отображения — приоритет: явное предпочтение субъекта → часовой пояс из RegionLocale → часовой пояс из IP/геолокации → UTC.
  • Учёт перехода на летнее время (DST) — обязательный через библиотеку IANA timezones (без жёсткого зашивания смещений).

Связь с другими каноничными сущностями

  • Quote (см. Семантика предложений, цены, бронирования) хранит ссылку на FxRateSnapshot, зафиксированный в момент создания.
  • Booking хранит ссылку на FxRateSnapshot платежа клиента и отдельную ссылку на снимок взаиморасчёта с поставщиком (если валюты разные).
  • Tenant имеет конфигурацию default_locale_id и список supported_locales (что предлагать конечному клиенту).
  • RecipientPreferences (см. Уведомления и коммуникации) хранит предпочтительную локаль получателя.
  • ContentTranslation (см. Медиа и контент) — связан с SupportedLanguage.
  • SearchSession.client_locale (см. Поиск и обнаружение) — заполняется через LocaleResolutionPolicy.

Базовый набор языков первой волны

КодBCP 47Native nameАнглийское имяПрименениеFallback
ukuk-UAукраїнськаUkrainianГлавный для UAuk → ru → en
ruru-UA, ru-KZрусскийRussianUA, KZ, частично PLru → en
cscs-CZčeštinaCzechГлавный для CZcs → en
plpl-PLpolskiPolishГлавный для PLpl → en
enen-US, en-GBEnglishEnglishГлобальный fallback, разработчикиen → en-US
kkkk-KZқазақ тіліKazakhГлавный для KZkk → ru → en

Правила расширения языкового набора

Расширение языков по фазам, по триггерам:

  • Фаза 2 — добавляются de (Германия) и sk (Словакия) при подходе к расширению в широкую Европу.
  • Фаза 3tr (Турция), hr (Хорватия), bg (Болгария), hu (Венгрия), ro (Румыния), sl (Словения).
  • Фаза 4ar (арабский, для расширения в сторону MENA), zh (китайский, для расширения в сторону Азии). Эти языки добавляют требование text_direction: rtl для арабского и иной системы письма для китайского.

Каждое добавление языка — архитектурное решение с обоснованием в реестре. Не «по запросу», а по триггеру.

Запрет на «временные» языки

Язык, добавленный в SupportedLanguage, остаётся в нём без обратного хода — нельзя «отключить» язык после того, как пользователи начали его использовать. Это нарушает право на услугу и ломает работу.

Допустимо: is_active: false для нового языка во время предварительного тестирования (пока не было пользователей).

Базовый набор валют первой волны

КодSymbolNative name (ru)ПрименениеПрименение в первой волне
UAHгривнаГлавная для UADisplay + Settlement в UA
EURевроГлавная для CZ, PL, EU broaderDisplay + Settlement в CZ, PL
CZKчешская кронаАльтернативная для CZDisplay, ограниченно Settlement
PLNпольский злотыйАльтернативная для PLDisplay, ограниченно Settlement
KZTтенгеГлавная для KZDisplay + Settlement в KZ
USD$доллар СШАКросс-валютный референс, USD-цены поставщиковSettlement reference

Правила расширения валютного набора

  • Фаза 2GBP при выходе на UK; RON (Румыния), HUF (Венгрия), BGN (Болгария) при расширении в широкую Европу.
  • Фаза 3TRY (Турция), GEL (Грузия), AZN (Азербайджан), AMD (Армения).
  • Фаза 4AED (ОАЭ), CNY (Китай), и другие при выходе в новые регионы.

Каноничные различения для валют

В платформе разводятся пять разных значений валюты для одного и того же бронирования (фиксация из api-contracts.md Локализация и валюты):

  1. Supplier currency — валюта, в которой поставщик выставляет счёт платформе.
  2. Canonical settlement currency — валюта взаиморасчёта платформы с поставщиком (может отличаться от supplier currency, если поставщик принимает несколько).
  3. Quote display currency — валюта, в которой клиенту показывается цена при коммерческой фиксации.
  4. Booking payment currency — валюта, в которой клиент платит (может отличаться от display currency, если клиент платит через провайдер платёжных услуг с другой валютой счёта).
  5. Conversion reference — валюта-ориентир для исторических сравнений и аналитики (типично USD).

Каждая разница между ними — отдельная конвертация с собственным FxRateSnapshot и собственной маржой.

Запрет на скрытую FX-маржу

  • ❌ Маржа платформы, не отражённая в FxRateSnapshot.margin_applied.
  • ❌ Курс отображения, отличающийся от курса фиксации без объяснения клиенту.
  • ❌ Двойная конвертация (USD → EUR → UAH вместо USD → UAH) без обоснования и без отражения в снимках.

Политика валютных операций

Фиксация курса в момент коммерческой фиксации

Главный закон — курс конвертации фиксируется в момент создания Quote и не меняется до конца жизненного цикла этой коммерческой фиксации:

SearchProjection.indicative_price (UAH)
↓ — клиент выбрал предложение
Quote.created
↓ — фиксируется FxRateSnapshot для конвертации supplier_currency → display_currency
Quote.confirmed
↓ — клиент платит
Booking.payment_initiated
↓ — если payment_currency ≠ display_currency, фиксируется второй FxRateSnapshot
Booking.confirmed
↓ — для взаиморасчёта с поставщиком используется fixed FxRateSnapshot
Settlement.cleared

Окна актуальности курсов

Цель использованияОкно актуальностиИсточник
Отображение в поиске (indicative_price)МинутыПлатформенный кэш курсов с обновлением каждые 5 минут
Коммерческая фиксация (Quote)Срок жизни Quote (типично 5–30 минут)Снимок на момент создания, никогда не пересчитывается
Бронирование (Booking)НавсегдаСнимок на момент платежа
Взаиморасчёт (Settlement)НавсегдаСнимок на момент создания Settlement
Аналитика (DWH)НавсегдаДневной средний курс или конкретный снимок

Источники курсов

Внешние источники

  • Центральные банки (Европейский ЦБ, НБУ, НБК) — официальные курсы для compliance-отчётности.
  • Провайдеры платёжных услуг (Stripe, Adyen) — реальные курсы конвертации платежа.
  • Финансовые провайдеры (Wise, Revolut Business, специализированные FX-провайдеры) — для оптимизации стоимости.
  • Финансовые агрегаторы (XE.com, OpenExchangeRates) — для индикативных курсов.

Каноничный приоритет источника

ЦельГлавный источникРезервный
Платёж клиентаКурс провайдера платёжных услугКурс центрального банка
Взаиморасчёт с поставщикомКурс банка платформыКурс центрального банка
Compliance-отчётностьКурс центрального банка применимой юрисдикции
Поиск (отображение)Платформенный агрегированный курсФинансовый агрегатор
АналитикаДневной средний курс центрального банка

Защита от арбитража

При изменении курса между моментом отображения в поиске и моментом коммерческой фиксации — клиент может попытаться использовать рассогласование (выбрать предложение с устаревшей выгодной ценой). Защита:

  • Окно индикативной цены в поиске — короткое (минуты).
  • При создании коммерческой фиксации — пересчёт цены на текущий курс (с отображением клиенту, если изменилось значимо).
  • Допустимое отклонение — каноничный порог (например, 1%); при превышении клиент видит обновлённую цену и явно подтверждает.

Политика разрешения локали

Алгоритм по приоритету

1. Явный параметр запроса (?locale=ru-UA или Accept-Language)

2. Сохранённое предпочтение субъекта (из RecipientPreferences для авторизованного)

3. Конфигурация тенанта (для запросов через партнёрский интерфейс)

4. Геогеографический вывод по IP-адресу

5. Подсказки браузера (вторичные Accept-Language)

6. Глобальный default (en для разработчиков, ru для UA, и т.д.)

Применение по поверхностям

Каждая поверхность имеет свою LocaleResolutionPolicy:

  • Партнёрская поверхность (Partner API Surface) — главный приоритет: параметр запроса. Без явного параметра — fallback на конфигурацию партнёра. Геогеографический вывод не применяется (партнёр может работать из любой страны).
  • Потребительская витрина (B2C Storefront Surface) — главный приоритет: сохранённое предпочтение субъекта; для нового пользователя — геогеографический вывод по IP.
  • Поверхность для агентств (Agency Working Surface) — главный приоритет: предпочтение агента (из настройки рабочего места).
  • Tour Builder Closed Surface — главный приоритет: конфигурация тенанта (тур обычно создаётся в одной локали и не меняется).

Запрет смешения локалей

В рамках одной сессии (SearchSession, диалог поддержки, цепочка запросов в Tour Builder) — одна локаль на всю сессию. Изменение локали посередине ломает консистентность (часть результатов на одном языке, часть на другом).

Допустимо: пользователь явно меняет локаль через UI — создаётся новая сессия с новой локалью, текущая сессия завершается.

Forsetage forwarding policy и fallback

Каноничный путь fallback для контента

Когда запрашивается контент на языке X, но перевода нет:

Перевод на X отсутствует

Попытка fallback по цепочке (например, для uk: uk → ru → en)

Перевод на резервном языке отображается с пометкой языка

В метаданные ответа включается признак fallback_used: true

Метаданные позволяют клиенту:

  • Показать визуальный индикатор «перевод на запасном языке».
  • Логировать пропущенный перевод для последующего восполнения.

Fallback для валют

При запросе цены в валюте Y, не поддерживаемой платформой:

  • Возвращается цена в ближайшей поддерживаемой валюте.
  • В ответе включается признак currency_fallback_applied: true.
  • Указывается причина (запрашиваемая валюта не поддерживается).

Fallback для часовых поясов

При неопределённом часовом поясе субъекта:

  • Используется часовой пояс из RegionLocale тенанта.
  • Если и его нет — UTC с явной пометкой.

Форматирование

Каноничные форматы дат

КонтекстФормат для ru-UAФормат для cs-CZФормат для en-US
Краткая дата15.06.202615.06.202606/15/2026
Длинная дата15 июня 2026 г.15. června 2026June 15, 2026
День недели + датапн, 15 июня 2026po, 15. června 2026Mon, June 15, 2026
Время14:3014:302:30 PM
Дата + время15.06.2026, 14:3015. 06. 2026, 14:30June 15, 2026, 2:30 PM
ISO 8601 (для API)2026-06-15T14:30:00+03:00то жето же

Каноничные форматы чисел

КонтекстФормат для ru-UA/uk-UAФормат для cs-CZФормат для en-US
Целое1 234 5671 234 5671,234,567
Дробное1 234 567,891 234 567,891,234,567.89
Процент12,5 %12,5 %12.5%

Каноничные форматы валют

Применяется display_format_template валюты для конкретной локали:

ЛокальUAHEURUSD
uk-UA1 234,56 ₴1 234,56 €$1 234,56
cs-CZ1 234,56 ₴1 234,56 €1 234,56 $
en-US₴1,234.56€1,234.56$1,234.56

Адреса и телефоны

Форматы адресов

Адресные поля каноничны (улица, дом, индекс, город, регион, страна), но порядок отображения различается по локали:

  • uk-UA, ru-UA — Страна, индекс, город, улица, дом.
  • cs-CZ, pl-PL — Имя, улица + дом, индекс + город, страна.
  • en-US — Имя, улица + дом, город, штат, индекс, страна.

Форматы телефонов

E.164 для хранения (+380441234567), форматирование для отображения по RegionLocale:

  • uk-UA+38 (044) 123-45-67
  • cs-CZ+420 123 456 789
  • en-US+1 (212) 555-1234

Юрисдикционные следствия

Юрисдикция определяет много правил

Расширение в новую страну — это не просто добавление языка и валюты. Это:

  • Новые регуляторные обязательства (см. Соответствие требованиям регуляторов).
  • Новые налоговые режимы (НДС, налог с продаж, маржинальный режим Tour Operators').
  • Новые правила формата документов (счёт, чек, акт сверки).
  • Новые требования к согласию (например, для некоторых стран — двойной opt-in для маркетинга).
  • Новые провайдеры платёжных услуг (см. Платёжный домен, Развилка 1).
  • Новые требования к локализации данных (для определённых стран — данные клиентов должны храниться внутри страны).

Каноничный процесс расширения географии

Каждое расширение проходит через стандартный поток:

  1. Бизнес-обоснование (рынок, размер, конкурентная позиция).
  2. Регуляторный анализ (compliance, налоги, соглашение об обработке данных).
  3. Локализация (язык, валюта, часовой пояс, форматы).
  4. Платёжный анализ (провайдеры платёжных услуг, лицензирование).
  5. Контентная локализация (переводы, культурная адаптация).
  6. Pilot — закрытое тестирование с ограниченным набором тенантов.
  7. Production launch.

Без прохождения всех 7 шагов — расширение в страну не выпускается.

Многоязычный контент

Полная политика — в Медиа и контент, раздел ContentTranslation. Здесь — кросс-доменное правило:

  • Все контентные сущности платформы (ContentBundle, NotificationTemplate, RankingPolicy.diversity_rules, документы интерфейсов и т.д.) используют одну и ту же сущность ContentTranslation для управления переводами.
  • Все домены используют одни и те же правила fallback и language_payloads структуру.
  • Не допускаются локальные системы переводов в отдельных доменах (например, отдельная база переводов для уведомлений).

Часовые пояса в каждом контуре

Где имеет значение часовой пояс

  • Бронирование — даты заезда/выезда в локальном часовом поясе объекта (а не клиента).
  • Платёж — момент платежа в UTC, отображение в часовом поясе клиента.
  • Уведомления — отправка с учётом часового пояса получателя (окна тишины — см. Уведомления и коммуникации).
  • Аналитика — агрегация по дням в часовом поясе тенанта (например, для расчёта дневных квот).
  • Tour Builder — расписание сегментов тура в часовом поясе локации каждого сегмента.
  • Платёжный цикл — расчётные периоды в часовом поясе валюты взаиморасчёта.

Запрет на «локальное время без указания пояса»

Любое временное поле без часового пояса — архитектурная ошибка. Все временные поля либо в UTC (для хранения), либо с явной зоной (для отображения).

Учёт потребления

Локализационные операции — типично дешёвые для платформы:

  • Конвертация валют — кэширование, низкая стоимость в реальном времени.
  • Форматирование — на стороне клиента или edge-слоя.
  • Переводы — обрабатываются единожды через ContentTranslation и переиспользуются.

Заметные расходы возникают только при обработке новых переводов (платное API машинного перевода или человеческие переводчики). Учёт ведётся через ml_inference_calls (для машинного перевода) и через журнал переводческих сервисов.

События платформы локализации

СобытиеКогдаГлавные потребители
locale.resolution.completedРазрешение локали для запросаПлатформа данных (для аналитики)
locale.fallback.appliedПрименён fallback (пропущенный перевод, неподдерживаемая валюта)Команда локализации, восполнение переводов
language.addedДобавлен новый язык в SupportedLanguageКонтур документации, команды контента
language.deactivatedЯзык переведён в неактивное состояниеКонтур аудита
currency.addedДобавлена новая валюта в SupportedCurrencyПлатёжный контур, команда финансов
region_locale.createdСоздана новая RegionLocaleВсе контуры, использующие локаль
fx.rate.snapshottedСоздан снимок курса для коммерческой фиксации или взаиморасчётаКонтур аудита, контур finance
fx.rate.divergence_detectedРасхождение между источниками курса превышает порогКоманда finance, оперативная команда
timezone.policy.appliedПрименена политика часового пояса для отображенияПлатформа данных

Полная таксономия — в Первоначальная таксономия событий.

Технологический выбор по фазам

ФазаРеестр локалейМашинный переводИсточник курсовЧасовые пояса
BootstrapХранение в основной БДСторонний сервис (DeepL/Google)Финансовый агрегаторБиблиотека IANA (tzdata)
2Расширенный реестр с api-as-product поддержкойСторонний с пост-редактированиемНесколько источников с резервированиемТо же
3Multi-region реестрСобственная модель для travel-семантикиПрямые интеграции с банками и платёжными провайдерамиЛокализованные правила DST для каждого региона
4Federated реестрLLM-based контекстный переводПолная экосистема FX-сервисовEdge-aware расчёты часовых поясов

Фазы развёртывания

Фаза Bootstrap (0–6 месяцев)

Что разворачивается:

  • Каноничная модель (SupportedLanguage, SupportedCurrency, RegionLocale, LocaleResolutionPolicy, FxRateSnapshot, TimezonePolicy) зафиксирована в схеме хранения.
  • Базовый набор 6 языков и 6 валют первой волны.
  • 4 каноничные RegionLocale (UA, CZ, PL, KZ).
  • Простой LocaleResolutionPolicy (явный параметр + fallback).
  • Базовый сторонний машинный перевод.
  • Источник курсов от одного финансового агрегатора.
  • Все временные поля в UTC.

Триггер выхода:

  • Готовность к первому боевому запуску — нужны зрелые правила обработки коммерческих фиксаций с FX.
  • Появление расхождений между источниками курсов — нужна резервная политика.

Фаза 2 — Production i18n (6–18 месяцев)

Что разворачивается:

  • Несколько источников курсов с резервированием.
  • Полная политика fallback со всеми каноничными цепочками.
  • Расширенная LocaleResolutionPolicy per-surface.
  • Журнал расхождений курсов с алертами.
  • Расширенное форматирование (адреса, телефоны).
  • Расширение языков по плану (de, sk при подходе к широкой Европе).
  • Партнёрский программный интерфейс выбора локали (для партнёров, обслуживающих своих клиентов в нескольких странах).

Триггер выхода:

  • Появление платформенной модели перевода (фаза 3).
  • Расширение в страны с сложной юрисдикцией (Турция, Великобритания).

Фаза 3 — Smart i18n (18–30 месяцев)

Что разворачивается:

  • Платформенная модель перевода для travel-семантики.
  • Multi-region хранение с локализацией данных.
  • Прямые интеграции с банками для курсов (без посредников).
  • Расширение в tr, hr, bg, hu, ro, sl языки.
  • Локализованные DST-правила.
  • Контекстная конвертация курсов (с учётом источника платежа клиента, типа карты).

Фаза 4 — Глобальная i18n (30+ месяцев)

Что разворачивается:

  • LLM-based контекстный перевод.
  • Поддержка rtl языков (арабский).
  • Поддержка иной системы письма (китайский — традиционный/упрощённый).
  • Полная экосистема FX-сервисов.
  • Edge-aware расчёты часовых поясов.

Архитектурные решения с тезисным обоснованием

Решение 1. Единый кросс-доменный слой, не локальные локализации

Цель: обеспечить консистентность платформы по всем поверхностям и доменам.

Тезисы:

  1. Без единого слоя каждый домен решает локализацию по-своему — поиск в одной форме, уведомления в другой. Это разрушает целостность.
  2. Юрисдикционные обязательства требуют единых форматов документов через все контуры.
  3. Современные платформы (Booking.com с десятками языков, Airbnb, Stripe) — все строят i18n как единый слой.

Решение 2. Каноничные различения валют (5 значений вместо одного)

Цель: обеспечить точную трассировку конвертаций и финансовую корректность.

Тезисы:

  1. Без различения возникают финансовые неточности (например, partner billing в одной валюте, а supplier settlement в другой — компенсация конвертацией невозможна).
  2. Регуляторы требуют прозрачности FX-операций — без снимков курсов компенсация невозможна.
  3. Каноничные различения уже зафиксированы в API Contracts. Этот документ их структурирует и привязывает к снимкам курсов.

Решение 3. Фиксация курса в момент коммерческой фиксации

Цель: обеспечить неизменность цены для клиента во время жизненного цикла коммерческой фиксации.

Тезисы:

  1. Цена — это коммерческое обещание. Клиент видит цену и решает покупать. Изменение цены до платежа разрушает доверие.
  2. Снимок курса — единственный надёжный механизм; «пересчёт по текущему курсу» приводит к жалобам и спорам.
  3. Современные платежные платформы (Stripe, Adyen) — все фиксируют курс в момент создания платёжного намерения.

Решение 4. Все временные поля в UTC, отображение в локальном часовом поясе

Цель: избежать класса ошибок «дата без зоны» и обеспечить корректные расчёты периодов через зоны.

Тезисы:

  1. «Локальное время без указания пояса» — самая распространённая ошибка в распределённых системах. Особенно критично с DST.
  2. UTC как универсальный формат хранения — стандарт индустрии.
  3. Локализация на отображении (через RegionLocale или предпочтение субъекта) — единственный корректный путь.

Решение 5. Цепочки fallback с явной пометкой результата

Цель: позволить отображение пользователю даже при отсутствии перевода без молчаливой подмены.

Тезисы:

  1. Полностью отсутствующий контент — хуже, чем переведённый на резервный язык.
  2. Молчаливая подмена создаёт впечатление «всё работает», в то время как переводы накапливают пропуски.
  3. Явная пометка fallback позволяет пользователю понять (через UI-индикатор), что это резервный язык, а команде — собрать данные о пропущенных переводах.

Открытые развилки

Развилка 1. Платформенная модель перевода — собственная или через партнёров

В фазе 3 — собственная модель для travel-семантики. Альтернатива — партнёрство с переводчиками или с сервисами специализированного перевода.

Эскалируется: при выходе из фазы 2.

Развилка 2. Локализация документов compliance

Налоговые документы (счета, чеки) и юридические документы (соглашения, политики) — формируются по правилам конкретной юрисдикции. Глубина локализации (только перевод vs. адаптация формата vs. полная переработка по локальным шаблонам) — открытая развилка.

Эскалируется: при детальной проработке compliance-документов в фазе 2 (production launch).

Развилка 3. Поддержка rtl языков и иных систем письма

Арабский, иврит, китайский, японский — открытый вопрос фазы 4. Требует значительной переработки UI-компонентов.

Эскалируется: при бизнес-обосновании выхода в эти регионы.

Развилка 4. Crowd-sourced улучшения переводов

Возможность получения улучшений переводов от партнёров и агентств для своих регионов. Коммерческие следствия (плата агентам за качественные правки).

Эскалируется: при появлении масштабных партнёров с региональной экспертизой.

Развилка 5. Конкретные провайдеры FX

В фазе 3 — выбор конкретных банков и финансовых провайдеров для прямых интеграций. Зависит от объёма платёжного оборота и от регулятивной квалификации платформы.

Эскалируется: при достижении объёма платежей, оправдывающего прямые интеграции.

Связанная документация

Корневые архитектурные документы

Связанные доменные документы

Реализационная база home-to-go-api

  • GEO_DATABASE.md — модель локаций с переводами для 182 стран.
  • GEO_CHAIN.md — реализация геоцепочки.
  • AMENITY_PLAN.md — справочник удобств с переводами на ru/uk.

Документы развития

Операционная сторона

Архитектурные правила