Skip to content

Localization Adapters — архитектурная граница

Статус: seam заложен, вторая реализация живая (selfloc dogfooding). Спекулятивные адаптеры (Minecraft/Terraria/…) НЕ реализуются — документ проверяет только то, что граница не потребует их знания сегодня.

Разделение ответственности

Слой Владеет Примеры
Каноническое ядро (rimloc-domain/canonical.rs, rimloc-services/project*) source entry identity (locale-независимая), source value, target locale, контексты, provenance, revision, sourceChanged/new/obsolete/orphan, review state, TM, glossary, AI drafts, persistence, редактор Project, SourceEntry, Translation, project store, session
Адаптер платформы discovery/parse, build/export, target-специфичная валидация, runtime-приёмка RimWorld: DefInjected/Keyed/TKey/LoadFolders/About.xml/load order; RimLocApplication: UI-catalog schema, плейсхолдеры, plural/select
App Control Fabric (опционально) runtime-acceptance поверх живого приложения RimWorld Adapter → Runtime Bridge; RimLocApplicationAdapter → WDIO

Правило: ядро не знает RimWorld-типов; RimWorld-знание не размазывается по generic-коду. Generic core + rich adapter предпочитается слабому «универсальному» формату.

Идентичность проекта (§F9)

Project.adapter: AdapterIdentity { adapter_id, adapter_api_version, adapter_project_schema_version } (rimloc-domain canonical.rs).

  • Встроенные first-party id: adapter_ids::RIMWORLD ("rimworld"), adapter_ids::RIMLOC_APPLICATION ("rimloc-application").
  • Legacy-конверты без поля грузятся как rimworld (serde default) — они и были RimWorld-проектами; обратная совместимость не сломана.
  • Проект неизвестного адаптера отказывает чисто: ProjectLoadDiagnostic::UnknownAdapter { adapter_id, known } — сообщение называет чужой id, список известных и говорит, что файл цел, а семантика чужая. Никакой интерпретации чужой семантики как RimWorld, никакой коррупции.
  • Версии: новая версия контракта адаптера = additive-minor в рамках adapter_project_schema_version; смена семантики = bump версии, старые файлы читаются миграцией или честным отказом, никогда «как получится».

Adapter-specific метаданные

Типизированные, не «bag of random JSON»: RimWorld-специфика живёт в типизированных полях канона, которые СЕЛЕКТИРУЮТСЯ identity адаптера — EntryKind (keyed/def_injected/t_key/strings/backstories/patch_derived — семейства механизмов; selfloc-сообщения сознательно идут как Keyed), SourceEntryId.def_type (Option), InventoryContext (target_version/DLC/load order), SourceProvenance (version_selected/conditional_branch/patch_stage/selected_by — словарь winner_reason). Будущий адаптер расширяет набор СВОИМИ типизированными структурами за своим identity; generic-ядро не обязано их понимать.

Capability discovery (§F3/§F4)

Адаптер объявляет, что умеет; UI/сервисный слой подстраивается и НЕ рендерит рабоче выглядящие контролы для неумелых возможностей. Сегодня возможности выводятся из пути проекта (mod-дерево → RimWorld-экспорт; catalog-дерево → contribution bundle); machine-readable манифест возможностей — направление (первый живой образец — мост: testlab/runtime_bridge/capability-manifest.json в схеме Computer Fabric).

Runtime-acceptance интеграция (§F13)

Локализационный адаптер ОПЦИОНАЛЬНО несёт runtime-приёмку:

RimWorldAdapter → RimWorld Runtime Bridge (test-only, JSON v1, frame freshness)
RimLocApplicationAdapter → WDIO semantic app control (embedded, P0-гейты)
<future> → свой нативный рантайм-мост или generic CuaDriver fallback

Generic-ядро локализации от App Control Fabric НЕ зависит: связь — через адаптер.

Соблюдённые conformance-инварианты (тесты)

  • project_store::tests::legacy_envelope_without_adapter_defaults_to_rimworld — legacy грузится, identity честный;
  • …::adapter_identity_round_trips — версии проходят серализацию без потерь;
  • …::unknown_adapter_fails_cleanly_with_diagnostic — чужой адаптер = чистый отказ;
  • …::rimworld_and_selfloc_adapter_projects_coexist — два идентити в одном ядре;
  • ui_catalog::tests::selfloc_project_carries_rimloc_application_adapter_identity — selfloc dogfooding;
  • редактор/TM/review работают над любым адаптером (один write-path update_translation) — покрыто общим suite'ом (211/211).

Направление третьих сторон (только дизайн-шов, §F10/F11)

НЕТ коммитмента на загрузку нативных DLL/dylib в процесс RimLoc. Для будущих непроверенных/коммьюнити-адаптеров оценивать: отдельный процесс-хост + версионированный RPC · WASM/sandbox · filesystem capability grants. Встроенные доверенные адаптеры остаются нативными crates. UI-вкладка адаптеров «на вырост» не заводится: product UX вернётся к platform-выбору, когда появится второй РЕАЛЬНЫЙ внешний адаптер (§F16).