导出管线
导出把官方本地化数据(manifest + archive,或编译后的 .locres)转成按 culture 输出的 .cliff 文件,并额外写出原键侧车。
配置项
| 键 | 必需 | 说明 |
|---|---|---|
SourcePath | ✅ | Target 的本地化数据目录 |
ManifestName / ArchiveName | ✅ | 如 Game.manifest / Game.archive |
NativeCulture | ✅ | 原生语言 |
CulturesToGenerate | ✅ | 要导出的 culture(可重复出现) |
DestinationPath | ✅ | 输出目录,布局为 <DestinationPath>/<Culture>/<Clan>.cliff |
CliffNamespace | ✅ | CLIFF header 的 namespace(来自 Project Settings 的 CLIFF Namespace) |
SourceLanguage | ⛔ | 覆盖 header 的 source-language(默认取 NativeCulture) |
数据来源
| 路径 | 使用场景 | 能力 |
|---|---|---|
FLocTextHelper::LoadAll(manifest + 全部 culture archive) | 主路径 | 完整:源文本、译文、cliff.* 元数据、SourceLocation 全都在 |
ExportFromLocResFile(直接读 .locres) | 只有二进制产物时 | 降级:源文本靠同目录 manifest 补齐;补不上的条目逐条告警并落到 sentence |
WARNING
.locres只有SourceStringHash与译文,没有源文本、没有元数据。纯二进制导出必然丢失type/emotion/status细分与原始 Key,只建议用于一致性验证(“二进制能不能读回来”),不要作为日常导出路径。
clan 与文件划分
文件级 clan(写入 header 与文件名):取 ManifestName 的基础名并 kebab 化,即 一个 culture 一个 .cliff 文件:
| ManifestName | header clan | 文件名 |
|---|---|---|
Game.manifest | cliff-game | cliff-game.cliff |
CliffLocalizationSuiteRuntime.manifest | cliff-localization-suite-runtime | cliff-localization-suite-runtime.cliff |
kebab 化后若不是合法 name(须以字母开头、只含 [a-z0-9-]),回退为 cliff。
条目级 clan:每条目还会单独解析一个语义 clan,写入侧车的 clan 字段(供审计与还原使用):
cliff.clan元数据(archive 条目的KeyMetadataObj)—— 最可靠,来自上一次导入Namespace反向映射表(Clan to Namespace的逆查)- kebab-slug 回退:把 UE Namespace 转成小写 kebab-case(
UObjectDisplayNames→u-object-display-names),并记录告警:UE namespace '…' has no semantic clan mapping; exported as clan '…'.
TIP
第 3 条只应作为兜底。若导出结果里出现一堆 slug 化的 clan 名,说明映射表缺条目——补上
Clan to Namespace即可,见 语义映射。
NOTE
文件名只有
<Manifest 基础名>.cliff一个,而不是每个 clan 一个文件:CLIFF 的文件单位是(namespace, clan, target-language),插件把整个 Target 的一个 culture 视为一个 clan 文件,条目之间按分组路径区分语义层级。
分组路径与条目 ID
CLIFF 的 name 只允许小写 kebab-case([a-z][a-z0-9-]*),而 UE 的 Key 常常是源文本本身(含中文、|、大写、/)。导出按以下优先级生成:
- 元数据:
cliff.group/cliff.entry合法时直接沿用(保证往返稳定) SourceLocation推导:取代码路径的最后一段(/Script/MyGame.GlyphAnimationLayer:AddShadowColorAt→glyph-animation-layer),截断[之后的元数据描述,剔除.cpp/.h/.uasset等扩展名与_C结尾- Key 分段:把 Key 中的
|、/视作层级分隔,逐段 kebab 化,最后一段作为条目 ID,其余拼成分组路径 - 稳定哈希 ID:Key 是 32 位十六进制 GUID 时用
key-<小写 hex>;无法从 Key 推导时用entry-<CRC32(Namespace|Key) 的 8 位十六进制>
同一 culture 内按 Namespace|Key 去重,因此一个 identity 只会出现一次。原键不丢失——它被写入侧车,导入时原样还原。示例:
UE 输入:Namespace = "UObjectCategory"
Key = "MyGame|层|字形微调|阴影染色"
SourceLocation = "/Script/MyGame.GlyphAnimationLayer:AddShadowColorAt [Function Category meta-data]"
CLIFF 输出(header: namespace: my-game, clan: category):
[glyph-animation-layer]
<add-shadow-color-at>
source: "MyGame|层|字形微调|阴影染色"
type: label
status: translated
reference: ["/Script/MyGame.GlyphAnimationLayer:AddShadowColorAt"]
侧车:my-game.category.glyph-animation-layer.add-shadow-color-at
↔ (UObjectCategory, MyGame|层|字形微调|阴影染色)
语义字段回填
| CLIFF 字段 | 来源优先级 |
|---|---|
type | ① cliff.type 元数据 ② Namespace to Type 映射表 ③ 无 → sentence + warning |
emotion | ① cliff.emotion 元数据 ② Namespace to Emotion 映射表 ③ 无 → 按 type 的默认值(dialogue/monologue/idiom → [neutral],其余 → [objective]) |
status | ① cliff.status 元数据 ② 有译文 → translated;无译文 → initial |
context | ① cliff.context 元数据 ② SourceLocation + SiteDescription + DevNotes 拼接 |
reference | SourceLocation(文件:行 或 资产路径) |
max-width | 仅当元数据中存在时导出(UE 没有对应来源) |
reviewer | 仅当元数据中存在时导出 |
NOTE
官方审核模型只有「有译文且源文本匹配 = 已审」的二元语义,因此导出的
status在元数据缺失时只能落到translated/initial。reviewed/final的细分完全依赖上一次导入写入的cliff.status元数据与侧车。
文本保真
source/target原样写出,ICU 花括号、占位符、HTML / 富文本标记都不做改写- 字符串按 CLIFF 转义表处理(
\n、\t、\"、\\),其余字符原样保留 - 输出为 UTF-8 无 BOM、LF 换行,字段采用规范形式(
key: value,冒号后一个空格)
输出布局与侧车
<DestinationPath>/
├── Game.cliffmap.json # 原键侧车(本次导出的全部条目)
├── zh-Hans/
│ └── cliff-game.cliff # 一个 culture 一个文件
└── ja/
└── cliff-game.cliff
侧车结构:
{
"version": 1,
"namespace": "my-game",
"entries": [
{
"id": "my-game.category.glyph-animation-layer.add-shadow-color-at",
"namespace": "UObjectCategory",
"key": "MyGame|层|字形微调|阴影染色",
"clan": "category",
"culture": "zh-Hans"
}
]
}
字段说明与还原规则见 原键侧车。
自校验与失败
- 序列化后的每个文档先过
FCliffDocument::ParseAndValidate - 有 error 级 issue → 导出失败,列出 issue(含行号)
- 命令let 汇总输出:
CLIFF export succeeded: <documents> documents, <entries> entries -> '<DestinationPath>'.
TIP
导出是评审入口:
.cliff是纯文本、diff 友好的稳定文件名,建议把导出目录纳入版本控制(连同侧车),让翻译与评审发生在 Git 里,而不是在二进制资产里。