真实的 payload 很少全是正文。同一个对象里,既有 title 和 body,也常常会带上 id、slug、资源 URL、模板名称、枚举代码——这些值承担的是标识和连接内容的作用,翻译后必须与输入时完全一致。风险往往悄无声息:如果你把一个名为 id 的字段和待翻译文本一起交给模型,它可能会觉得把 "post-42" 本地化后“读起来更顺”,或者顺手规范化一个 URL,甚至“纠正”某个枚举值。只要有一个标识符被改动,线上就可能出现断链或查找失败,而且会出现在模型自作主张“帮忙”的那个语言环境里。
lockedKeys 让这件事不再靠猜。你可以按精确名称或 glob 指定绝不能改动的键,本地化引擎会将这些值排除在翻译之外,然后把源值逐字合并回每个目标语言环境的 outputData。被锁定的值不会被翻译、规范化,也不会被改写。什么标识符传进去,什么标识符就原样返回,而且每个语言环境都一致。
lockedKeys 是 create-jobs 请求中的一个字段。完整的请求结构和 202 响应请参见 Create jobs;本页只介绍 lockedKeys 该怎么写,以及匹配规则如何生效。
按名称锁定键#
将 lockedKeys 与 data 一起传入。每一项都是一个模式;最简单的写法,就是直接填写你想原样保留的键名。
{
"sourceLocale": "en",
"targetLocales": ["de", "fr"],
"data": {
"id": "post-42",
"title": "How async APIs reduce latency",
"tags": ["performance", "infra"],
"author": { "id": "u_abc", "name": "Sam" },
"body": "Async APIs let your app stay responsive while translations process in the background."
},
"lockedKeys": ["id"]
}裸模式 id 会在它作为完整路径段出现的任何位置匹配键 id——这里既包括顶层的 id,也包括嵌套的 author.id。每个德语和法语任务里的 outputData 都会精确保留 "post-42" 和 "u_abc"。只有 title、name 和 body 会被翻译;tags 则保持原样,因为它不包含任何被锁定的路径,而其中的字符串值仍会像其他文本一样照常翻译。
最后这一点值得单独拎出来说清楚,因为这正是持怀疑态度的人最先会问的问题。
被锁定的值会被翻译吗?
不会。你在 lockedKeys 中指定的键会被排除在翻译之外,并且其源值会原封不动地合并回每个目标语言环境的 outputData。你传入的值返回时不会发生任何变化——不会被翻译、不会被规范化,也不会被改写。锁定是通过 lockedKeys 对结果作出的保证,而不是给模型的一个“尽量遵守”提示。
按名称全局匹配,或按位置精确匹配#
裸模式就是键名,它会在整棵树中的任意位置、任意深度,以完整路径段的形式匹配该名称。如果 audioSrc 在不同父级下嵌套出现了十二次,那么单个模式 audioSrc 就会把这十二处全部锁定。你不需要逐条枚举路径来覆盖每一次出现——这就是最常见的用法,而且只要一行。
当你需要按位置精确控制时——比如只锁定某一次出现而不锁定另一次,或者锁定数组中的每个元素而不影响其他内容——就使用以 / 作为路径分隔符的 glob。数组索引会像普通路径段一样出现,因此 users/0/email 和 users/*/email 都是合法路径。
| 模式 | 锁定内容 |
|---|---|
audioSrc | 树中任意深度的每个 audioSrc 叶子值 |
metadata | 无论出现在何处,整个 metadata 子树都会被锁定 |
metadata/author | 无论出现在何处,都会锁定这段 metadata/author 路径序列及其下方所有内容 |
users/*/email | 每个用户的 email——* 是一个路径段,可匹配任意索引 |
users/0/email | 仅锁定第一个用户的电子邮件地址 |
**/{audioSrc,imageSrc} | 通过花括号备选同时匹配两个叶子名称 |
上面有两个模式会有意锁定不止一个叶子值。metadata 会锁定该键下的整个子树——其下所有值,不管看起来像不像可翻译内容,都会被保留。metadata/author 会在它出现的任何地方锁定这段序列以及其下方的所有内容。当整个区块本身就是结构性内容时——比如配置对象、原始嵌入内容——适合使用子树锁定;当一个原本可翻译的区块里,只有某一个字段必须保持不变时,则使用叶子锁定(metadata/author/name)。
这是 glob,不是正则
* 精确匹配一个路径段;** 可跨越任意数量的路径段;{a,b} 表示在多个备选项之间进行花括号展开。这里没有字符类或部分 token 匹配——模式作用于完整的路径段,而不是子字符串。请写 users/*/email,不要写正则表达式。
返回结果是什么样#
锁定改变的是模型会翻译哪些内容——不会改变结果的结构。outputData 会精确镜像输入结构:被锁定的键仍位于原始位置并保留原始值,周围可翻译的字符串则会被翻译。不会有任何内容被删除、重命名或重新排序。
对于上面的输入,每个目标语言环境的 outputData 都会保留原样的 id: "post-42" 和 author.id: "u_abc",而 title、name 和 body 则会翻译成目标语言。完整的任务响应——outputData、各阶段的 steps 以及状态——记录在 Get a single job 中。
一个限制,先说清楚#
lockedKeys 每个请求最多接受 100 个模式。这个上限限制的是模式数量,而不是它们匹配到的键数量——单个 audioSrc 或 users/*/email 就可以在大型 payload 中锁定成千上万个值,而且只算一个模式。如果你快要用到 100 个不同模式,通常说明改用更宽泛的 glob(**/{id,slug,href})或子树锁定,就能用少得多的几行表达同样的意图。
lockedKeys 也是按请求生效、临时指定的:它只会为这一组任务锁定键。因此,对于那些在任何任务中都不应该被翻译的术语——例如产品名称、带商标的功能名、必须保持字面形式的单位——更长期的做法是把它们作为引擎词汇表中的不可翻译条目,在每次调用时自动应用。参见 Glossaries。与特定 payload 结构绑定的结构性字段,用 lockedKeys;在所有内容中都恒定不变的词汇,则用词汇表。
