数据流

三条链路共享同一个骨架:编辑器入口生成官方 GatherText 配置 → 官方执行器按步骤调度 → 插件命令let 读写 CLIFF → 官方生成器编译二进制

              ┌──────────── 编辑器入口 ────────────┐
              │ Dashboard 按钮 / 控制台命令 / CI    │
              └───────────────┬───────────────────┘

              生成 GatherText ini(CommonSettings + GatherTextStep{N})

        UGatherTextCommandlet 反射 CommandletClass → 执行插件命令let

   ┌──────────────┬───────────────────────┬──────────────────────┐
   │ CliffImport   │ CliffExport            │ CliffAITranslate      │
   └──────┬───────┴───────────┬───────────┴──────────┬───────────┘
          ▼                   ▼                      ▼
   manifest/archive      <culture>/<clan>.cliff   DeepSeek 写回 .cliff
          ▼                   ▼                      ▼
   .locmeta/.locres      .cliffmap.json 侧车      再走 CliffImport

链路一:导入(CLIFF → UE)

步骤执行者细节
1编辑器入口生成 <Target>_CliffImport.iniCommonSettings + GatherTextStep0CommandletClass=CliffImport)+ GatherTextStep1CommandletClass=GenerateTextLocalizationResource
2官方执行器GUI 走官方子进程 + 同款 Slate 窗口;无头走嵌入式 UGatherTextCommandlet::Execute
3UCliffImportCommandlet读取 SourcePath / ManifestName / ArchiveName / NativeCulture / CulturesToGenerate,以及 CliffFilePath(可多个)或 CliffDirectory + CliffImportCulture
4解析每个 .cliff 文本交给 FCliffDocument::ParseAndValidate;有任何 error 级 issue 即整体失败并逐条打印行号
5装配为 Target 构造 FLocTextHelper(TargetPath, ManifestName, ArchiveName, NativeCulture, Cultures)LoadAll
6写 manifest每条 entry 调 AddSourceText(namespace, key, source, context);上下文带上 cliff.* 元数据
7写 archivestatus: initial 只写 manifest;其余状态写对应 culture 的 archive 译文(空译文与自翻译被拒绝写入)
8保存SaveManifest / SaveArchive,依次写各 culture
9编译官方 GenerateTextLocalizationResourceFTextLocalizationResourceGenerator 产出 .locmeta 与每个 culture(含 NativeCulture)的 .locres,flags 为 EGenerateLocResFlags::None
10刷新FTextLocalizationManager::UpdateFromLocalizationResource 热刷新;任务结束后广播 LocalizationDelegates::OnLocalizationTargetDataUpdated

导入时的两个关键约定:

  • 先原生语言后外语:任务内的文件按「原生语言优先」排序,外语归档条目的「生效源」(官方 NativeText 语义)也随之同步,因此导入顺序不影响最终一致性。
  • 元数据就地挂接:同一身份(Namespace + Key + Source)不再新增重复 manifest context,而是把 cliff.* 挂到已存在的 context 上;否则官方 GenerateLocRes 会因同一 key 的多个 context 解析出冲突译文。

链路二:导出(UE → CLIFF)

步骤执行者细节
1编辑器入口生成 <Target>_CliffExport.iniCommonSettings + GatherTextStep0CommandletClass=CliffExport,带 DestinationPathCliffNamespace
2UCliffExportCommandlet读取配置并调用 FCliffExporter::ExportTarget
3读数据主路径:FLocTextHelper::LoadAll 读 manifest + 全部 culture archive;辅助路径:ExportFromLocResFile 直接读编译后的 .locres(此时源文本靠 manifest 补齐,配不上则逐条告警)
4分 clan每个 clan 生成一个 FCliffDocument。clan 的确定顺序:cliff.clan 元数据 → Namespace 反向映射表 → kebab-slug 回退(并记 warning)
5造 ID分组路径与条目 ID 由 SourceLocation / Key 切片生成稳定 kebab-case;冲突时追加 `CRC32(Namespace
6回填语义type / emotion / status / context / reference 优先取 cliff.* 元数据,其次按映射表推导;完全无信息 → sentence + warning
7自校验序列化结果先过一遍 ParseAndValidate,有 error 级 issue 则导出失败
8落盘<OutputDirectory>/<Culture>/<Clan>.cliff(UTF-8 无 BOM、LF)
9侧车<OutputDirectory>/<Manifest 基础名>.cliffmap.json,记录 canonical id ↔ (namespace, key)

链路三:AI 翻译

Saved/CliffAITranslate/<Target>/    ← 每次执行前清空重建
① CliffExport      → <Culture>/<Clan>.cliff(只含 source 与已有 target)
② CliffAITranslate → 逐语言扫描 .cliff、只翻译缺 target 的条目、写回同目录
③ CliffImport      → manifest / archive + GenerateTextLocalizationResource
④ Generate Reports→ 官方字数报告
  • 每个目标语言一条独立对话,多语言并发执行(上限 Max Concurrent Cultures)。
  • AI 请求全部发生在命令let(Editor 子进程)内,用异步 HTTP + 统一事件循环驱动,不阻塞主编辑器 UI。
  • 管线结束后,翻译好的 .cliff 会被拷回 Content/Localization/<Target>/,成为可评审、可提交的中间产物。

官方数据模型速查

官方结构关键字段插件如何对应
FManifestEntryNamespace + Source + Contexts[]CLIFF 的 clan → Namespace,source → Source
FManifestContextKey / SourceLocation / DevNotes / KeyMetadataObjcliff.* 元数据挂在这里
FArchiveEntryNamespace / Key / Source / Translationtarget 写 Translation;外语条目 Source 记录「生效源」
FTextLocalizationResourceLocalizedString / SourceStringHash / Priority由官方生成器产出,插件只读回验证
FTextLocalizationMetaDataResourceNativeCulture / CompiledCultures决定导出时的 native 文化发现

NOTE

.locres 不保存源文本与元数据(只有 SourceStringHash 与译文),所以「只用二进制导出」必然丢语义。这也是导出侧车主路径存在的原因,详细规则见 导出管线