语义映射
CLIFF 的 clan 表达「这段文本是什么语义家族」(界面标签、提示、专有名词、对话……),UE 的 Namespace 是 FTextId 的第一段。两者不是一回事,插件用三张可配置的映射表把它们接起来,绝不硬编码。
IMPORTANT
注意术语消歧:CLIFF 的
namespace(canonical ID 的第一段,插件中等于 CLIFF Namespace 设置)与 UE 的FTextKey Namespace是两个不同概念。本文凡写 UE Namespace 都指后者。CLIFF namespace 不进入 UE Namespace。
三张映射表
| 设置项 | 方向 | 用途 |
|---|---|---|
| Clan to Namespace | clan → UE Namespace | 导入时决定写进哪个 Namespace;导出时反向查找 clan |
| Namespace to Type | UE Namespace → CLIFF type | 导出时推导 type |
| Namespace to Emotion | UE Namespace → CLIFF emotion | 导出时推导默认 emotion |
位置:编辑 > 项目设置 > 插件 > CLIFF Localization Suite > Semantic Mapping。
默认值
FCliffSemanticMapping::CreateDefault() 提供的内置表。生效映射 = 内置默认表 + 项目设置中的条目(同键时项目设置覆盖默认值):
Clan to Namespace
| clan | UE Namespace |
|---|---|
category | UObjectCategory |
tooltip | UObjectToolTips |
short-tooltip | UObjectShortTooltips |
display-name | UObjectDisplayNames |
proper-noun | UObjectDisplayNames |
dialogue | Dialogue |
Namespace to Type
| UE Namespace | type |
|---|---|
UObjectCategory | label |
UObjectToolTips | prompt |
UObjectShortTooltips | prompt |
UObjectDisplayNames | proper-noun |
Dialogue | dialogue |
Namespace to Emotion
| UE Namespace | emotion |
|---|---|
Dialogue | neutral |
NOTE
display-name与proper-noun都映射到UObjectDisplayNames:前者是「类/字段显示名」这个来源,后者是「它按语义是专有名词」这个结论。反向查找时先命中者优先,因此导出的 clan 通常是表里的第一项。若你的项目需要更精确的命名,把不需要的条目删掉即可。
导入方向:clan → UE Namespace
FCliffSemanticMapping::ResolveNamespace(clan) 的实际行为(导入器 CliffImporter.cpp):
- 在
ClanToNamespace中命中 → 用该 UE Namespace(视为「显式」映射) - 未命中 → 回退为 CLIFF header 的
namespace(即项目标识本身,如p-cliff-l10n-suite),并记录 warning:CLIFF clan '…' has no semantic mapping; using CLIFF namespace '…' as UE namespace.
因此一个只写 clan: ui 而没有配置映射的项目仍然能导入,只是所有条目会落到以 CLIFF namespace 命名的 UE Namespace 下。若你希望它落到项目自己的 UI 命名空间(例如 MyGameUI),加一条映射即可:
; Config/DefaultEditor.ini(也可以直接在项目设置面板里编辑)
[/Script/CliffLocalizationSuite.CliffLocalizationSuiteSettings]
+ClanToNamespace=(("ui", "MyGameUI"))
导出方向:UE Namespace → clan / type / emotion
clan(ResolveClanFromNamespace):
ClanToNamespace反查(精确匹配值)→ 返回对应 clan- 未命中 → kebab-slug 化 UE Namespace:驼峰拆词 + 转小写 + 非
[a-z0-9-]字符替换为-+ 合并/裁剪连字符(UObjectDisplayNames→u-object-display-names) - slug 为空 → 用
ue - 未命中会记录 warning,提示你补映射表
type(ResolveTypeForNamespace):命中 NamespaceToType 则用之,否则返回空,由导出器落到 sentence + warning。
emotion(ResolveEmotionForNamespace):命中 NamespaceToEmotion 则用之;否则 emotion 字段不写,交给 CLIFF 的默认规则(dialogue / monologue / idiom → [neutral],其余 → [objective])。
UE 侧实际能拿到什么
| UE 文本来源 | UE Namespace | 能推导出的语义 |
|---|---|---|
C++ LOCTEXT | #define LOCTEXT_NAMESPACE,通常是模块名 | 无法单凭 Namespace 区分 label / dialogue → 默认 sentence |
C++ NSLOCTEXT | 显式参数 | 同上 |
资产 / 蓝图 FText | 资产内 namespace(包本地化 namespace 会被剥离) | 站点描述形如 "{StructPath} [Script Bytecode]",语义需靠规则表 |
| 类 / 字段 DisplayName | 固定 UObjectDisplayNames | proper-noun |
| 类 / 字段 Tooltip | 固定 UObjectToolTips / UObjectShortTooltips | prompt |
UObject Category 元数据 | 固定 UObjectCategory(由 GatherTextFromMetadata 产出) | label |
| DialogueWave | 固定 Dialogue | dialogue |
TIP
想把项目自己的 UI 文本也映射成
label,最省事的做法是给这类文本的 Namespace 加规则。例如源码里统一使用#define LOCTEXT_NAMESPACE "MyGameUI",然后:
Clan to Namespace: ui → MyGameUI
Namespace to Type: MyGameUI → label
导出时 MyGameUI 的条目就会写成 clan: ui + type: label,导入时又原路回到 MyGameUI。
降级与告警口径
| 情况 | 结果 |
|---|---|
| clan 无显式映射 | UE Namespace = CLIFF header 的 namespace(可正常往返,但建议补映射) |
| UE Namespace 无反向映射 | clan = kebab-slug + warning |
type 无法推导 | type: sentence + warning |
emotion 无法推导 | 不写该字段(CLIFF 默认规则生效) |
| 元数据存在 | 元数据优先于所有映射表(上一轮导入写入的语义不会被映射表覆盖) |
NOTE
因元数据优先级最高,调整映射表只会影响「从未经过 CLIFF 往返」的既有 UE 数据;已经导入过一次的条目会稳定保留其语义,不会因为改表而漂移。