架构总览

插件的核心设计原则只有一条:CLIFF 是官方本地化链路的一个步骤,而不是它的替代品。因此它不修改引擎源码,不自己写 .locres 二进制,也不自建 Dashboard 窗口,而是把自己挂到官方已有的扩展点上。

设计目标与约束

目标落地方式
不修改引擎只使用 Core / Developer / Editor 的公开类;引擎源码零 diff
不旁路官方数据写入走官方 FLocTextHelperFTextLocalizationResourceGenerator
融入官方工作流注册官方 LocalizationService Provider,按钮注入官方 Dashboard 工具栏
可无头运行导入/导出/AI 翻译都是官方 UGatherTextCommandletBase 子类,可由 -run=GatherText 驱动
不引入运行时依赖Runtime 模块零编辑器依赖、零 Python、零 HTTP

模块划分

Plugins/CliffLocalizationSuite/
├── CliffLocalizationSuite.uplugin
├── Content/Localization/            # 插件自带译文(7 Target × 15 语言)
└── Source/
    ├── CliffLocalizationSuite/       # Runtime:数据模型与解析
    │   ├── Public/Cliff/CliffDocument.h
    │   ├── Public/Cliff/CliffSemanticMapping.h
    │   ├── Public/Cliff/CliffSerializer.h
    │   ├── Public/Settings/CliffLocalizationSuiteSettings.h
    │   └── Private/…                # 解析器、校验器、设置实现、单测
    └── CliffLocalizationSuiteEditor/ # Editor:管线集成
        ├── Public/Cliff/CliffImporter.h
        ├── Public/Cliff/CliffExporter.h
        ├── Public/AI/CliffAITranslator.h
        ├── Public/Commandlets/CliffGatherCommandlets.h
        └── Private/…                # 工具箱、Provider、进度窗口、AI 客户端、单测
模块类型LoadingPhase职责
CliffLocalizationSuiteRuntimeDefaultCLIFF 数据模型、解析、校验、序列化、语义映射、UDeveloperSettings
CliffLocalizationSuiteEditorEditorDefault导入器、导出器、AI 翻译、Dashboard 集成、GatherText 命令let、控制台命令

依赖

// Runtime:纯数据与算法,可被 Game 目标引用
PublicDependencyModuleNames: Core, CoreUObject, Engine, DeveloperSettings

// Editor:官方管线与编辑器 UI
PublicDependencyModuleNames:  CliffLocalizationSuite, Core, CoreUObject, Engine,
                              LocalizationService, Slate, SlateCore
PrivateDependencyModuleNames: ApplicationCore, DesktopPlatform, EngineSettings, HTTP, InputCore,
                              Json, Localization, LocalizationCommandletExecution, UnrealEd

NOTE

Runtime 模块不依赖 UnrealEdAssetToolsSlate,所以 Game / Shipping 目标可以正常打包;Editor 模块 Type: Editor,不会进入运行时。

官方链路的接入点

UE 5.8 的官方本地化链路是:Editor 操作 → 生成 ini 配置 → GatherText 子进程按步骤执行 → manifest / archive → FTextLocalizationResourceGenerator 生成 .locmeta / .locres → FTextLocalizationManager 查表

官方没有第三方文件格式的注册接口(PO / CSV 都是 Dashboard 生成的 ini 里硬编码的 commandlet 行为),因此插件选择以下四个官方扩展点:

#接入点官方类型插件用法
1GatherText 步骤动态发现ini 的 GatherTextStep{N} + CommandletClass,由 UGatherTextCommandlet 反射 NewObjectCliffImport / CliffExport / CliffAITranslate 成为管线的普通步骤
2Localization Service ProviderILocalizationServiceProvider modular feature(注册名 "LocalizationService"把 CLIFF 按钮注入官方 Dashboard 的 Target / TargetSet 工具栏
3官方编译生成器FTextLocalizationResourceGenerator::GenerateLocMeta/GenerateLocRes导入后编译 .locmeta / .locres,不自己写二进制
4官方刷新委托FTextLocalizationManager::UpdateFromLocalizationResourceLocalizationDelegates::OnLocalizationTargetDataUpdated导入后立即热刷新并刷新 Dashboard 缓存

关键类一览

类 / 结构模块说明
FCliffDocumentRuntime解析入口:Parse / ParseAndValidate / Validate / GetCanonicalId
FCliffHeader / FCliffGroup / FCliffEntryRuntimeCLIFF 数据模型
FCliffValidationIssue / ECliffValidationCategoryRuntime7 类 issue;IsError()extensionwarning 排除在失败之外
FCliffSemanticMappingRuntimeclan ↔ UE Namespace、Namespace → type / emotion 规则表
FCliffSerializerRuntime规范化 CLIFF 1.0 序列化(UTF-8 无 BOM、LF)
UCliffLocalizationSuiteSettingsRuntimeProject Settings(Identity / Semantic Mapping / Workflow / AI Translation)
FCliffImporterEditor.cliff → manifest / archive → 编译 → 热刷新
FCliffExporterEditormanifest + archive(或 .locres)→ 分组 .cliff + 原键侧车
FCliffEditorToolboxEditorDashboard 按钮、文件对话框、GatherText 配置生成、任务装配
FCliffLocalizationServiceProviderEditor官方 Provider 实现(工具栏注入)
FCliffAITranslatorEditorDeepSeek 翻译编排、自翻译判定、连接测试
UCliffImportCommandlet / UCliffExportCommandlet / UCliffAITranslateCommandletEditor三个官方 GatherText 步骤
FCliffCommandletExecutorUIEditor复刻官方样式的 Slate 进度窗口

设计取舍

为什么用「自定义 Commandlet + Provider 注入」而不是自建窗口

官方 Dashboard 不提供新增格式按钮的接口,但提供 ILocalizationServiceProvider 工具栏扩展点与 GatherText 步骤发现机制。走这两条路的收益是:日志与官方完全一致(LogGatherTextCommandlet 分段输出)、子进程行为一致、CI 可以直接复用同一套 ini 配置。代价是按钮行为受官方 Dashboard 的 Target / TargetSet 上下文约束。

为什么必须导出侧车

.locres 只有 SourceStringHash,没有源文本也没有元数据;而 UE 的 Key 常常就是源语言文本本身(可含中文、|、大写、/),无法直接作为 CLIFF 的 name。因此导出时生成稳定 ID 并把「原 UE Namespace / Key ↔ canonical ID」写进 .cliffmap.json,导入时还原,才能做到无损往返。

为什么状态要降级

UE 官方审核模型只有「有译文且源文本匹配 = 已审」的二元语义,没有 reviewed / final 的细分,也没有 emotion。插件因此把 CLIFF 的四态与 emotion 写入 archive 的 KeyMetadataObjcliff.status / cliff.emotion)并同时保留在侧车中;当这些信息丢失时,状态按官方语义降级(无译文 → initial,有译文 → 视为已审)。

为什么 ICU 原样透传

UE 的 FText::Format 只认识 plural / ordinal / gender / hpp 等修饰符,并不实现 ICU MessageFormat 的运行时求值。插件因此把 ICU 字符串原样存取,并在编译 .locres 时使用 EGenerateLocResFlags::None 关闭格式校验;CLIFF 侧的平衡校验仍在解析阶段执行。

插件自带的本地化数据

插件自身 UI 文本随包分发,.uplugin 声明 7 个 Localization Target:

TargetLoadingPolicy
CliffLocalizationSuiteRuntimeAlways
CliffLocalizationSuiteEditorEditor
CliffLocalizationSuiteEditorTutorialsNever
CliffLocalizationSuitePropertyNamesPropertyNames
CliffLocalizationSuiteToolTipsToolTips
CliffLocalizationSuiteKeywordsEditor
CliffLocalizationSuiteCategoryEditor

每个 Target 均为 native en + 15 种语言(zh-Hansenjakoesptarplderufrpt-BRtres-419it),数据位于 Content/Localization/。正因如此,插件的 AI 翻译管线必须把 NativeCulture 也纳入编译——否则编辑器界面使用的原生语言 .locres 永远不会重建。

下一步