| name | legal-translation-US |
| metadata | {"author":"Wouter van den Berg - wouter@monteclima.com - linkedin.com/in/wjvandenberg","license":"mit","version":"2026-05-13"} |
| description | 将法律文件从任何语言翻译为英文,同时保留 .docx 格式, 并翻译跟踪更改与页眉/页脚。当用户要求将法律文件、合同、契据、 协议或任何正式法律文本翻译为英文时使用本技能。 当用户提到翻译包含法律内容的 .docx 文件,或要求对法律文件进行 “保留格式的翻译”时,也触发本技能。本技能覆盖所有法律领域: 金融、并购、公司事务、知识产权、房地产、监管、消费者、税务、 诉讼、软件即服务等。即使用户只是说“翻译这份合同”或“把这个 翻译成英文”,只要文件具有法律性质,就使用本技能。
|
法律文件翻译技能
将法律文件从任何语言翻译为达到出版质量的英文,同时保留所有原始 .docx 格式(字体、样式、页眉、表格、编号等)。
步骤前检查点——动手前先通读本文件
本技能的纪律要求你真正阅读 SKILL.md,而非仅将其加载到上下文中。在执行任何步骤(步骤 1 至步骤 11)之前,在对话中发布一行简短的确认语句:“Understanding of skill discipline is confirmed, now initiating translation process.”(使用该确切措辞)。不要打印技术细节(硬规则位置、验证器名称、步骤文件)——用户不想要满屏的内部状态文本。写下确认语句这一行为本身即证明你已处于正确位置;保持简洁。
如果在你即将输入该语句时,发现无法凭记忆说出(a)硬规则块位于何处,(b)apply_translations_textmatch.py 自动调用哪些验证器(共有四个),或(c)包含你即将执行的步骤的文件——停止,重新缓慢 Read('SKILL.md'),然后发布一行确认。内部验证是必需的;面向用户的验证展示则非必需。
压缩恢复触发器——视为会话开始
如果本轮对话始于压缩后的记录(标志:描述先前工作的系统消息、“摘要”前言、“本会话是从上一段上下文已耗尽的对话中继续的”标题,或任何表明工作已推进但你在本轮未 Read('SKILL.md') 的上下文迹象),你必须将恢复视为会话开始。**压缩摘要不能替代实际规则。**摘要可能将一条 100 行的规则压缩成一行,丢弃在具体案件中起关键作用的限定语,或省略包含你即将遭遇的失败模式答案的附录。
具体而言,每次压缩恢复时,在任何工具调用之前:
- 完整
Read('SKILL.md')。
Read() 你即将操作的当前步骤文档。
Read() 压缩前正在使用的任何词汇表/子词汇表。
- 恢复工作前,发布一行“Understanding of skill discipline is confirmed, now initiating translation process.”
这不是“重读已读过的内容”;而是阅读你在本轮尚未读过的内容。强制阅读顺序在每次压缩恢复时同样适用,与首次会话开始完全相同。绝不信任压缩摘要对规则的转述——如果摘要提及某条规则,去文件中读取该规则的原文后再适用。
不要询问用户——以下为绝对默认值
以下为不可协商的默认值。不要停下来向用户询问。静默按默认值执行;仅当用户已在其原始请求中给出明确指示时才切换。如果你发现自己正在起草关于其中任何一项的澄清问题,停止——提问本身就是错误的做法:
-
**美式英语为标准。**始终翻译为美式英语。切换到英式英语的唯一情形是用户已在其请求中明确说明(如“translate into UK English”、“use British English”等表述)。不要询问使用英式还是美式。不要预先确认。直接翻译为美式英语,如果愿意,可在交付消息中提及可按要求提供英式英语。
-
**顺序、单一上下文翻译是唯一模式。**翻译一份文档,或在一个会话中翻译多份文档时,直接在主上下文窗口中顺序进行。不要问“我是否应该顺序进行?”或“该技能强制顺序——您希望如何进行?”——顺序是唯一模式。仅当用户明确要求子代理/并行处理时才询问用户,此时应警告质量风险并推荐顺序进行。
-
**先完成一份文档的全部 11 个步骤,再开始下一份。**翻译多份文档时,先完整完成文档 1 的整个流水线(步骤 1 至 11,包括最终重新打包和验证),再开始文档 2 的步骤 1。不要以并行批次翻译两份文档,不要将文档 1 的重新打包推迟到“最后一起做”。每份文档都是独立的一次顺序运行。
-
35 段批处理上限为强制要求(由 validate_translations.py 执行)。不要询问是否使用更大的批次。
-
每个定义部分段落都必须填写 en_runs(由 validate_en_runs.py 执行)。不要询问。
-
**自动调用的验证器始终运行。**不要询问是否跳过某个门禁。除非用户明确批准(例如已知可接受的粗体丢失使用 --allow-bold-loss),否则不要传递覆盖标志。
-
**每份文档强制刷新。**在同一会话中开始处理新文档时,重新 Read('SKILL.md'),到达每个步骤文件时重新 Read(),并重新 Read() 相关词汇表和子词汇表。不要询问。
-
**压缩恢复重读为强制要求。**如果本轮始于压缩后的记录,在任何工具调用前 Read('SKILL.md') 和当前步骤文档。压缩摘要不能替代实际规则(见上文“压缩恢复触发器”小节)。不要询问。
-
**聊天模式不放松纪律。**在聊天模式(无工作区文件夹、无自动管理的待办列表)下,同样的 11 个步骤、同样的 paragraphs.json 检查点、同样的逐批验证器、同样的强制阅读顺序全部同等适用(见“防漂移保障”中的“聊天模式纪律”)。不要询问在聊天模式下是否允许捷径——不允许。
如果用户明确覆盖上述任何一项,遵从用户——但绝不虚构澄清问题。
多文档工作流
如果你在同一 Claude 会话中翻译多份文档,将每份文档视为一次全新工作流的开始。即使文档相似(同一项目、同一当事方、同一领域),每份文档的刷新也是不可协商的:
- **先完成文档 1 的全部 11 个步骤,再开始文档 2。**不要在文档间批量翻译(交错批次翻译文档 1 + 文档 2),不要将文档 1 的重新打包推迟到“最后一起做”,不要在多份文档之间拆分验证或最终交付。每份文档都是从步骤 1(设置)到步骤 11(验证)的独立顺序运行。只有在文档 1 作为成品 .docx 交付后,文档 2 的步骤 1 才开始。
- 每份新文档开始时重新
Read('SKILL.md'),完整读取。不要假定上一份文档的阅读仍活跃在你的工作记忆中。
- **到达新文档的相应步骤时,重新
Read() 每个步骤文件。**预检横幅按文档适用。
- **每份新文档的步骤 3 时,重新
Read() 每个适用的分语言子词汇表和英文参考词汇表。**如果领域发生变化,对文档 1 是正确的子词汇表“避免”列条目未必对文档 2 是正确的。借译漂移(Calque drift)正是此处可预测的失败模式。
- **将逐批验证器状态文件(
.validate-state.json)视为文档作用域。**每份文档有自己的工作目录;状态文件位于其中。
子词汇表和步骤文件的重新读取属于文档设置的一部分,而非会话设置。“我刚刚为上一份文档读过这个”——跳过它们正是本技能旨在防止的漂移。
**当多份文档在范围内时,不要询问用户如何进行。**顺序、先完整完成一份文档是唯一模式(见上文“不要询问”目录)。直接从文档 1 的步骤 1 开始。
重要:单文档工作流——不进行代理并行化
本技能设计为一次处理一份文档,由 Claude 在其主上下文窗口中翻译。顺序、单一上下文翻译是默认且唯一的运行模式。不要询问用户“我是否应该顺序进行?”——顺序正是本技能的做法。直接开始文档 1,完成全部 11 个步骤,如有文档 2 再开始。
唯一需要用户输入的情形是用户明确要求子代理或并行处理。此时:
- 部署任何代理前停止并询问用户——他们真的想要这样吗?可能并不想。
- 明确警告基于代理的并行翻译很可能降低质量:代理缺乏保持术语一致、跟踪定义词和处理交叉引用所需的全文上下文。代理输出之间的不一致难以检测和修复。
- 推荐在主上下文窗口中顺序翻译文档。
如果用户未明确要求代理,该问题根本不会出现——静默顺序进行。
黄金法则:以原文为底稿进行文本匹配
.docx 的格式存于 word/document.xml 中每个 <w:p> 元素上设置的段落属性(样式、编号、缩进、间距)中。这些属性很脆弱——任何通过 Python XML 解析器重新序列化的操作都可能损坏它们,损坏方式在 XML 中看似正常,但在 Word 中渲染错误(编号错乱、标题级别错误、缩进丢失)。
可靠的方法是:**以原始源语言 .docx 作为格式底稿,只替换每个段落内的文本 run(w:r 元素)。**段落结构、样式、编号、间距、缩进——一切保持原样不变。只有文字改变。
关键在于,替换必须通过按源语言文本内容匹配段落来进行,而非按索引位置。段落提取可能引入小的索引偏移(空段落计数方式不同、域代码、嵌套内容)。文本匹配自动处理任何偏移,并已验证在全部测试文档上产生零样式/编号不匹配。
**表格和容器段落是一等公民。**法律文件通常包含嵌套在表格(w:tbl/w:tr/w:tc/w:p)、文本框和结构化文档标签中的段落——签名块、表单字段、带表格数据的附表、当事方信息表都使用这些结构。提取和应用都必须使用递归段落搜索(而非仅 w:body 的直接子级)来查找并翻译这些段落。否则签名块、附表表格和表单字段将保留源语言。
架构概览
原始 .docx(源语言)
│
├──▶ 提取段落 → paragraphs.json(文本 + 格式元数据)
│ │
│ ▼
│ 翻译所有段落(填写 "en" 字段)
│ │
│ ▼
│ 验证翻译(字符比率检查)
│ │
│ ▼
└──▶ 应用翻译 ◀──────┘
(文本匹配到原始 document.xml,
仅替换 w:r 元素,
扫描源语言残留,
然后就地后处理)
│
▼
最终 .docx(英文,格式与原始文件完全一致)
不存在中间“已翻译 document.xml”步骤。翻译直接从 JSON 应用到原始文件上。这消除了早期方法中导致级联格式损坏的段落数量不匹配问题。
硬规则。不可协商。由技能的门禁强制执行。
这五条规则适用于流水线的每个步骤,而非仅步骤 4。每个步骤文件末尾都有一项内部合规检查,要求你确认已遵守这些规则。偏离会触发阻止你工作的门禁;事先合规总是比撞上门禁更快。
硬规则。不可协商。由技能的门禁强制执行。
-
**一次处理一份文档。**先为一份文档完成整个流水线(步骤 1 至 11),再开始下一份。绝不将跨文档的翻译打包进一个 paragraphs.json,绝不“为提高效率”并行运行两条翻译流水线。翻译质量是逐段注意力的产物;工作流围绕此设计。
-
**每批 ≤35 段(硬上限,由 validate_translations.py 强制执行)。**最多翻译 35 段,然后在写下一批之前运行 validate_translations.py paragraphs.json。跳过批次正是本技能针对的失败模式——当任务感觉繁重时,本能是合并批次,结果是输出带有本可被早期验证捕获的错误。验证器的状态文件强制每次调用最多 35 段新翻译段落;超过 35 段的批量验证将被阻止,除非传递 --accept-large-batch。
-
**步骤 5(应用)验证完整的验证覆盖。**如果任何具有非空 en 的段落未经 validate_translations.py 验证,应用将被阻止。无法跳过步骤 4b 的逐批验证仍通过步骤 5。
-
**阅读每个段落的完整 text 字段。**不要使用摘要、抽样或“翻译大意”的捷径——翻译时每个词都必须在你的上下文窗口中。
-
**为每个定义部分段落填写 en_runs。**如果检测到的定义部分中的任何段落缺少 en_runs,应用将被阻止。识别定义部分的结构线索以及如何填写 en_runs,见下文规则 3。
强制阅读顺序
本技能的纪律要求你在正确的步骤阅读正确的文件。每个步骤的完整程序细节存于 skill-docs/ 中,组织为八个文件。执行每个步骤之前,你必须完整 Read('skill-docs/0X-...md')。绝不可略读。绝不可跳过步骤文件。绝不可凭记忆转述步骤。
每个步骤文件末尾有一项分步骤内部合规检查;你必须在继续前完成该检查。如果在任何时刻你发现自己在未于本会话中读取相应步骤文件的情况下执行步骤——停止,立即读取该文件,然后继续。
阅读顺序为:
skill-docs/01-setup-and-extract.md — 步骤 1+2:转换 + 提取段落
skill-docs/03-lexicons-and-segments.md — 步骤 3+3b:识别文档类型、读取词汇表、为跟踪更改搭建 en_segments
skill-docs/04-translate.md — 步骤 4:翻译每个段落(最重的步骤)
skill-docs/04b-translate-gates.md — 步骤 4b+4c+4d:逐批验证、交叉引用、词汇表合规
skill-docs/05-apply.md — 步骤 5:将翻译应用到原始文件
skill-docs/06-postprocess-and-reorder.md — 步骤 6+7:后处理和定义重排
skill-docs/08-aux-and-quality.md — 步骤 8+9:辅助 XML 文件和质量检查
skill-docs/10-repack-and-validate.md — 重新打包前钩子 + 步骤 10+11:重新打包为 .docx 并最终验证
每个文件应在工作流到达相应步骤时 Read()。它们不是附录。
词汇表优先级——跨语言惯例以跨语言参考为准
技能的词汇表分为两层,二者权威性并不相同。步骤 3 时你必须两者都读,但在跨语言英文惯例的问题上,跨语言参考始终优先:
sub-lexicons/<language>-<domain>.md — 特定语言术语映射。对源语言术语在其本土语境中如何以英文呈现具有权威性。示例:日语子词汇表将 条 → "Article (Art.)",对诸如 民法第30条 → "Article 30 of the Civil Code" 的法条引用映射正确。该映射在其范围内是正确的。
references/<domain>.md(general-legal.md、finance-banking.md、energy-infrastructure.md、trading-capital-markets.md 等)— 跨语言英文惯例。对英文法律写作无论源语言为何都如何处理某种惯例具有权威性:内部交叉引用用 Section(美式默认)还是 Clause(英式)还是 Article、定义词大写、“et al.”与“etc.”、日期和货币格式、列表中的逗号用法、缩写风格等。
**当两者看似不一致时,跨语言参考优先。**日语子词汇表的 条 → "Article" 是引用映射;references/general-legal.md 规定合同中的内部交叉引用在美式英语(默认)下用“Section”,英式英语下用“Clause”(例如默认美式变体下 本契約第3条 → "Section 3 of this Agreement",英式下 → "Clause 3 of this Agreement",绝不使用 "Article 3 of this Agreement")。参考规则将子词汇表映射限定于法条引用——它不否定子词汇表,而是告诉你子词汇表的映射何时适用、何时不适用。同样的逻辑适用于每种跨语言惯例:当质量检查发现内部引用中出现“Article 3”而子词汇表提供了 Article 映射时,该质检发现是正确的,而非误报——在将其视为误报前阅读 references/general-legal.md。
在依赖子词汇表映射处理跨语言惯例之前,始终阅读相关的 references/*.md。如果只查阅了子词汇表,你只有一半的答案。
流水线概览
各步骤功能的高层摘要。细节见步骤文件。
| # | 步骤 | 动作 | 文件 |
|---|
| 1 | 设置 | 必要时将 .doc 转换为 .docx,解包到工作目录 | skill-docs/01-setup-and-extract.md |
| 2 | 提取 | extract_paragraphs.py 生成带格式元数据的 paragraphs.json | skill-docs/01-setup-and-extract.md |
| 3 | 词汇表 | 识别文档领域,加载英文参考和分语言子词汇表 | skill-docs/03-lexicons-and-segments.md |
| 3b | 搭建 | (仅限跟踪更改文档)为碎片化跟踪更改构建 en_segments 骨架 | skill-docs/03-lexicons-and-segments.md |
| 4 | 翻译 | 为每个段落填写 en 和 en_runs,每批 ≤35 段 | skill-docs/04-translate.md |
| 4b | 逐批验证 | 每批后运行 validate_translations.py | skill-docs/04b-translate-gates.md |
| 4c | 交叉引用 | 解决翻译文本中的断裂交叉引用 | skill-docs/04b-translate-gates.md |
| 4d | 词汇表合规 | 应用前扫描 lexicon_compliance.py | skill-docs/04b-translate-gates.md |
| 5 | 应用 | apply_translations_textmatch.py(自动调用 4 个验证器) | skill-docs/05-apply.md |
| 6 | 后处理 | post_process.py(术语、间距、美式英语等) | skill-docs/06-postprocess-and-reorder.md |
| 7 | 重排 | 含定义的文档运行 reorder_definitions.py | skill-docs/06-postprocess-and-reorder.md |
| 8 | 辅助文件 | 翻译页眉/页脚/批注/脚注/尾注 | skill-docs/08-aux-and-quality.md |
| 9 | 质量检查 | quality_check.py 检查源语言残留 | skill-docs/08-aux-and-quality.md |
| 10 | 重新打包 | repack_docx.py(自动调用 validate_apply --strict) | skill-docs/10-repack-and-validate.md |
防漂移保障
本技能强制的纪律源于反复的事后复盘。漂移是这样一种失败模式:你(操作者)在技能加载后开始翻译,然后在长时间工作过程中开始凭记忆转述规则、跳过逐批验证,或判定某个步骤“这次不适用”。最终状态是看起来合理、但术语微妙出错、跟踪更改丢失或定义格式遗漏的输出。
防御措施是分层且不可选的:
-
**强制步骤文件阅读。**8 个 skill-docs/0X-...md 文件中的每一个都必须在它所覆盖的步骤处完整 Read。每个文件末尾有一项操作者必须完成的内部合规检查。
-
**硬规则全技能适用。**上述 5 条硬规则不只针对步骤 4。每个步骤的合规检查都要求你重新确认它们。
-
自动调用门禁。apply_translations_textmatch.py 自动运行四个应用前验证器(依次为 validate_en_runs、validate_segment_shapes、validate_reject_all,应用后运行 validate_apply --strict)。repack_docx.py 再次自动运行 validate_apply --strict。post_process.py 自动运行 strip_noop_tracked_changes.py。这些都无法从命令行跳过。
-
逐批验证。validate_translations.py 强制每次调用最多 35 段新翻译段落。状态文件 .validate-state.json 使批次覆盖可审计。
-
**技能门禁语义。**门禁触发会产生 SKILL GATE FIRED — INTENTIONAL BLOCK, NOT A SCRIPT ERROR 横幅。这是脚本在履行职责,而非脚本故障。不要通过修补脚本或跳过验证器来绕过门禁——修复输入(通常是 paragraphs.json)并重新运行。
-
**脚本完整性错误。**任何以 FILE INTEGRITY CHECK FAILED — script truncated 横幅退出的脚本,都表明该脚本的本地安装已损坏。停止——在重新运行受影响的步骤之前,从 .skill / .zip 压缩包重新安装技能。不要通过跳过步骤、通过包装器调用脚本或将结果视为“可选”来绕过故障。技能中的每个脚本都带有完整性检查;任何一个脚本失败都是安装侧的硬问题,只能通过重新安装修复。
-
**聊天模式纪律。**本技能的设计假设存在工作文件夹(例如 Cowork 模式),其中 paragraphs.json、final/word/document.xml 和 .validate-state.json 检查点是步骤间持久化的真实文件。在聊天模式(无工作文件夹、无自动管理的待办列表)下,纪律必须自我强制执行——而且略读或压缩的诱惑实质更高。会话开始时,你必须检测聊天模式(见 skill-docs/01-setup-and-extract.md 步骤 1a)并逐字发布面向用户的聊天模式警告——每个会话一次,措辞按文档数量匹配“this document”与“these N documents”。步骤 11a 时,向 verify_diligence.py 传递 --mode chat,以便勤勉报告在检测到漂移时可附加 Cowork 建议。具体而言:
paragraphs.json 仍是强制要求。如果没有工作区文件夹,将其写入 /tmp/<workdir>/paragraphs.json(或环境提供的任何持久路径),并将该路径传递给每个脚本。不要不写真实文件就“在上下文中”翻译——validate_translations.py 读取该文件并写入状态文件;两者必须是真实文件,逐批验证器才能强制 35 段上限。
- 35 段批处理上限在聊天模式下与 Cowork 模式完全相同。不要“为节省上下文”、“因为文档很小”或“因为用户在等待”而合并批次。验证器的状态文件检查仍会触发;绕过它正是本节标记的合理化行为。
- 强制阅读顺序在聊天模式下完全相同。如果你在未于本轮
Read('skill-docs/04-translate.md') 的情况下到达步骤 4,停止并阅读它。更小的分步骤文件结构(每个步骤文档约 700 行,而非单个 2500 行的 SKILL.md)使略读更具诱惑力;抵制它。每个步骤文档的编写意图都是在操作者到达相应工具调用前完整阅读。
- 每个步骤文档底部的内部合规检查在聊天模式下是强制性的。在进入下一步骤前明确走查检查清单。不要转述或跳过条目。
apply_translations_textmatch.py 和 内部的自动调用验证器在聊天模式下不可协商。如果验证器触发,修复输入——不要传递覆盖标志(“就这一次”)——不要通过 Python 包装器运行脚本以绕过完整性检查。
如果你发现自己正在将偏离合理化(“就这一次”、“文档很小”、“我后处理时会抓到”、“我在聊天模式下所以可以在上下文中保留”),停止。失败模式恰恰就是那种合理化。
为什么文本匹配很重要
从 .docx 提取段落时,提取脚本分配连续的 idx 值。但 .docx 文档可能包含提取脚本与原始 XML 段落列表计数方式不同的元素:域代码、结构化文档标签、嵌套表格和其他结构元素可能导致 idx 值相对实际 XML 段落索引发生漂移。
在真实世界测试中,一份文档对 564 个 XML 段落显示了 577 条 JSON 条目——漂移达 6-13 个位置。基于索引的匹配将英文文本放到了错误的原始段落上,造成级联格式损坏:条款标题渲染为正文、正文被自动编号、附表内容缩进错误、最后约 60 段保持源语言。
基于文本的匹配消除了整类错误。每条翻译无论索引漂移如何都能找到其正确的目标段落,产生零样式/编号不匹配。
表格嵌套段落(签名块、附表、表单字段)
法律文件经常包含表格内的段落:签名块、带账户明细的附表表格、当事方信息表、表单字段。这些段落嵌套为 w:tbl > w:tr > w:tc > w:p,而非 w:body 的直接子级。
两个脚本必须一致地处理这些:
- 提取(
extract_paragraphs.py)使用 root.iter('{W}p')——完全递归,无论嵌套深度如何都能找到所有段落。
- 应用(
apply_translations_textmatch.py)必须使用 findall('.//{W}p')(递归),而非 findall('{W}p')(仅直接子级)。
在提取时使用递归搜索、应用时使用直接子级搜索,会导致应用步骤搜索更小的段落集(例如 564 而非 577),使表格嵌套段落无法匹配。结果:签名块、附表表格和表单字段保持未翻译。
在 6 份法律文档的测试中,3 份包含表格嵌套段落(分别为 13、14 和 26 个)。它们都是签名块、附表表格和当事方信息表——没有递归搜索就会保持源语言。
目标英语变体:美式英语(不要询问用户)
本技能翻译为美式英语。美式是硬编码标准。不要询问用户“英式还是美式英语?”——答案就是美式。英式英语适用的唯一情形是用户已经在其原始提示中给出明确指示(如“translate into UK English”、“use British English”等表述)。如果没有,静默使用美式;可以在交付消息中提及“可按要求提供英式英语”,而不是打断翻译去询问。
**防漂移规则——每次变体选择前阅读。**在你做出任何依赖英语变体的决定之前(页面上写什么、向 post_process.py --variant 传递什么标志、向 quality_check.py --variant 传递什么标志、交付消息中单词如何拼写),执行以下操作:
- 回到用户本次翻译的原始提示。
- 搜索明确的美式英语指示:“UK English”、“British English”、“British spelling”、“UK spelling”,或明显等价的表述。
- 当且仅当找到时才使用英式英语。
- 否则——包括用户提到了英方当事方、英方相对方、位于英国的收件人或任何其他感觉像英国的情境——使用美式英语。
不要从上下文、客户国籍、文件准据法、文件名或任何中间消息推断“英式英语”。只有用户原始提示中的明确指示才能切换变体。如有任何疑问,选择美式。此重新检查必须在以下每个决策点进行;不要缓存会话早期做出的决定:
- 起草包含变体敏感拼写或词汇的翻译时;
- 调用
post_process.py 时(默认传递 --variant us);
- 调用
quality_check.py 时(默认传递 --variant us);
- 向用户撰写交付消息时。
**用户如何切换到英式英语:**用户必须在其请求中给出直接指示——如“translate into UK English”、“use British English”、“British spelling”等表述。给出时,为该翻译应用英式英语,并向后处理和质检脚本都传递 --variant uk。如果用户没有明确说,美式胜出——可以在交付消息中提及可按要求提供英式英语,而不是打断翻译去询问。
变体管辖的内容:
- 拼写:organise/organize、authorise/authorize、favour/favor、defence/defense、fulfil/fulfill、programme/program、judgement/judgment(英式法律)、analyse/analyze。
- 日期格式:“15 April 2026”(英式)与“April 15, 2026”(美式)。对翻译引入的日期一致应用;源文档中原始语言的日期除翻译月份名称外保持原样。
- 引号惯例:主要引语用单引号、内部用双引号,引语非引文一部分时逗号和句号放在闭合引号外(英式);双引号且标点在闭合引号内(美式)。注意:法律起草实务在两种变体下都常用双引号标记定义词——无论变体为何,定义词标记都保留双引号。
- 通用法律词汇:claimant/plaintiff、counsel/attorney(当源词是通用词、非法域特定头衔时)、post/mail、flat/apartment 以及类似的日常语域选择。
变体不管辖的内容:
- **法域特定法律术语。**当源文件提及特定法律体系的机构、法规、公职人员或程序概念时,按该体系的正确英文表达翻译——不要因为读者偏好美式英语就将其美化为美式等价词,也不要将其英化。意大利语 avvocato 保持 avvocato(或通用词“lawyer”),而非“solicitor”或“attorney”;德语 Rechtsanwalt 保持 Rechtsanwalt(或“lawyer”);美国 attorney-at-law 在英式英语翻译中保持 attorney;英国 solicitor 在美式英语翻译中保持 solicitor。同样适用于法规名称、法院名称、程序阶段和职务头衔——变体偏好管辖术语周围的语域和拼写,而非术语本身。
- **源文件给出的法规和机构名称。**无论变体为何,都按子词汇表和参考文件中确立的英文表达翻译。
如果你不确定某个特定术语是“通用法律词汇”(受变体管辖)还是“法域特定”(不受管辖),按法域特定处理并保留确立的英文表达。过度英化或过度美化法域特定术语,是比语域略有偏差更严重的错误。
脚本参考
| 脚本 | 用途 |
|---|
extract_paragraphs.py | 将带格式元数据的段落提取到 JSON(含跟踪更改删除文本) |
coalesce_fragmented_tcs.py | 若源文件有跟踪更改则强制——检测字符级跟踪更改碎片(例如西班牙语“Duodécima”逐字母改为“Decimotercera”),并在首个 ins/del 上以占位符、中间 run 以空字符串搭建 en_segments;tc_segments 保持不变 |
validate_translations.py | 检查翻译完整性(字符比率)。步骤 4 中的逐批调用是手动的;最终应用前遍次从 apply_translations_textmatch.py 内部自动运行。 |
validate_segment_shapes.py | 若源文件有跟踪更改则强制——应用前形状检查器:成对扫描 en_segments 中的 XML 边界风险形状(冠词冲突、无空白的跨边界字母冲突——非拉丁文字陷阱、跟踪更改边界上的数字、跨边界的双空格、裸冠词跟踪更改段、内部驼峰式冲突)。对含跟踪更改的文档从 apply_translations_textmatch.py 自动运行。 |
validate_reject_all.py | 若源文件有跟踪更改则强制——从 en_segments 重建全部接受和全部拒绝视图,扫描可读性缺陷(双冠词、重复词、孤立介词、粘连词、双空格、空括号、禁用搭配)。对含跟踪更改的文档从 apply_translations_textmatch.py 自动运行。 |
lexicon_compliance.py | 强制(应用前和重新打包前)——扫描 JSON 或 document.xml 中源自词汇表“避免”列的借译和硬规则违规。应用前运行是手动的(步骤 4d);重新打包前运行在打包前从 repack_docx.py 内部自动触发。 |
apply_translations_textmatch.py | 主要——通过文本匹配将翻译应用到原始文件。自动运行 validate_translations.py(仅 BLOCK code 2)、对含跟踪更改的文档自动运行 validate_segment_shapes.py 和 validate_reject_all.py(全部在应用前),并在应用后运行 validate_apply.py --strict。 |
repack_docx.py | 强制——将翻译后的 XML 重新打包为 .docx(替换外壳 zip)。打包前自动运行 lexicon_compliance.py --stage pre-repack 和(提供 --paragraphs 时)validate_apply.py --strict。 |
translate_numbering.py | 翻译 word/numbering.xml 中的编号格式字符串 |
translate_headers_footers.py | 翻译 word/headerN.xml 和 word/footerN.xml 中的文本 |
translate_comments.py | 若文档有批注则强制——对 word/comments.xml 进行命名空间安全的翻译 |
常见陷阱及规避方法
Python XML 解析器损坏 .docx 格式
ElementTree 和 lxml 在重新序列化时剥离命名空间声明(xmlns:o、xmlns:v 等)。这导致“unreadable content”错误。文本匹配脚本分两层处理:先将原始 XML 头部嫁回输出,然后验证文档正文实际使用的所有命名空间前缀都存在于根元素中(注入缺失的)。这种双层方法同时捕获解析器引起的剥离和原始文件本身声明不完整的情况。
表格嵌套段落未被翻译
如果应用脚本使用 findall('{W}p')(仅直接子级)而非 findall('.//{W}p')(递归),表格内的段落不可见。签名块、附表表格和表单字段保持源语言。提取和应用中始终使用递归搜索。
借译漂移——“我读了词汇表,但还是用了禁用短语”
最隐蔽的质量问题。起草者打开 references/general-legal.md,滚动浏览表格,注意到存在“避免”列,开始翻译,然后——因为荷兰语源文件 30 个段落里都有 deze onderhavige overeenkomst——将其译为 “this present agreement”。词汇表在“避免”列中明确列出 “the present agreement”,但到该短语出现时,起草者的注意力已漂移到翻译任务上,词汇表规则被遗忘。
以此方式漏网的真实示例(均来自一份荷兰语 SOK):
- “this present agreement”(荷语 deze onderhavige overeenkomst)— 修正: “this Agreement”
- “framework conditions”(荷语 randvoorwaarden)— 修正:“conditions” / “parameters”
- “in more concrete terms”(荷语 concretiseren)— 修正:“set out” / “specify”
- “environs fund”(荷语 omgevingsfonds)— 修正:“community fund” / “local-impact fund”
- “acceptance by the environs”(荷语 acceptatie door de omgeving)— 修正:“acceptance by the local community”
**为什么“读过一次”词汇表不够。**对一张 250 行术语表的记忆会在几个翻译批次内衰减。“避免”列是黑名单——强制执行它的唯一可靠方法是(a)在每个新批次重新打开子词汇表并重新扫描与即将翻译短语相关的章节,(b)在步骤 4d(应用前)运行 scripts/lexicon_compliance.py——重新打包前运行在步骤 10(repack_docx.py)内部自动触发。合规脚本很便宜(< 1 秒),并通过正则捕获每个已记载的借译。没有借口让列出的“避免”列短语进入最终输出。
**合规扫描标记出借译时如何应对。**不要与发现结果对抗。“避免”列具有权威性。打开引用的子词汇表,转到该行,选择首选表达,修补 paragraphs.json,重新应用,重新扫描,重复直到退出码为 0。
子词汇表在跨语言参考管辖处过度适用(词汇表优先级误读)
一种与借译漂移相邻但机制不同的失败模式。翻译者完整阅读分语言子词汇表,找到源术语的映射(例如日语 条 → "Article (Art.)"),并统一应用该映射——包括在映射本不该管辖的语境中。跨语言 references/general-legal.md 规则规定合同内部交叉引用在美式英语(默认)下用“Section”,英式英语下用“Clause”,而非“Article”(例如默认美式变体下 本契約第3条 → "Section 3 of this Agreement"),但翻译者只查阅了子词汇表,将其映射视为所有用途的权威,通篇产出“Article 3”。当 quality_check.py 后来标记内部引用中的“Article N”时,翻译者误读质检发现为误报,通过正则批量将“Article”替换为“Section”以让门禁通过——治标不治本,未查阅权威来源。
**根本原因。**只读子词汇表而未读对应的 references/<domain>.md。子词汇表映射在其范围内是正确的(日语 条 对 民法第30条 这样的法条引用确实是“Article”);跨语言参考按用法限定映射(合同内部引用在美式下用“Section”,英式下用“Clause”)。两层是互补的,而非冗余。
**修正。**步骤 3 时两层都读。跨语言 references/*.md 是每次步骤 3 的强制阅读,与子词汇表相同。先读子词汇表以找到术语映射;再读跨语言参考以确认映射适用于当前用法。有疑问时,跨语言参考优先(见本文件前文“词汇表优先级——跨语言惯例以跨语言参考为准”)。当 quality_check.py 标记跨语言惯例违规时,默认视为真实发现——references/*.md 是真相来源,子词汇表是映射来源。
脚注、尾注和批注留在源语言
.docx 将脚注/尾注/批注内容存储在单独的 XML 文件中(word/footnotes.xml、word/endnotes.xml、word/comments.xml)——不在 word/document.xml 内。如果只提取、翻译并应用到 document.xml,所有脚注、尾注和批注都会静默保持源语言。这是高严重度缺陷。始终在步骤 2 检查这些文件,与正文一起翻译,并将其纳入步骤 10 的重新打包。
辅助 XML 被 ElementTree 损坏(导致“unreadable content”)
症状:翻译后的 .docx 在 Word 中无法打开,报“unreadable content”或“file is corrupt”错误。通过 LibreOffice 的 PDF 渲染可能仍然成功,使该缺陷容易被忽略。
原因:xml.etree.ElementTree 在重新序列化 XML 时重命名命名空间前缀。如果输入使用 w14:paraId、mc:Ignorable、w16cid:* 等,ElementTree 会在输出中将它们重写为 ns1:paraId、ns2:Ignorable、ns3:*。根元素也会丢失大部分 xmlns:* 声明。结果是 XML 顶部声明 w: 但正文深处使用 ns1:、ns2: 等——Word 无法解析的未绑定前缀。
在哪里咬人:word/comments.xml、word/footnotes.xml、word/endnotes.xml、word/headerN.xml、word/footerN.xml。主 document.xml 流水线避免了此问题,因为 apply_translations_textmatch.py 使用 lxml 并将原始根标签嫁回;但辅助文件通常用临时内联 Python 翻译,ElementTree 正是从这里混入。
为什么仅靠头部嫁接不够:本技能的早期版本建议捕获原始 <w:comments ...> 开标签并在 ElementTree 写完后再用正则替换回去。这恢复了根元素的命名空间声明,但正文属性(ns2:paraId、ns1:Ignorable……)仍然损坏。Word 按元素强制前缀绑定,因此仅嫁接根不够。
正确修正——以下三种方法任一即可:
- **(批注首选)**使用随附的
translate_comments.py 脚本。它纯粹通过正则替换文本,不解析 XML 树,因此前缀永远不会被重命名。
- **(页眉/页脚/编号首选)**使用随附的
translate_headers_footers.py / translate_numbering.py 脚本。它们使用 lxml,能正确保留前缀。
- **(脚注/尾注或任何其他辅助文件)**在
<w:t> / <w:delText> 元素内使用纯正则文本替换,原始 XML 的每个其他字节逐字保留。示例模式见步骤 8d。
不要:在任何辅助 XML 文件上使用 xml.etree.ElementTree,即使带头部嫁接、即使带 ET.register_namespace。对使用 w14:、w15:、w16:*、mc: 或任何声明在根上但正文深处引用的命名空间的文件,它都不安全。
批次规模膨胀(关键质量风险)
一个持续观察到的失败模式:批次规模从 30-35 开始,但随着翻译推进和完成压力增大,静默增长到 50、60 甚至 80+。这总是降低质量——后续批次出现截断条款、转述文本、丢失定义词和术语不一致。损害在翻译时不可见,但在审查时显而易见。**每批必须最多 35 段。**每批前说明范围。如果剩余不足 35 段,作为最终批次翻译——不要并入上一批。
提取与原始文件之间的段落数量不匹配
提取产生的 JSON 条目可能多于或少于实际 XML 段落。文本匹配使此问题无关紧要——多余条目被跳过,缺失条目使文本保持源语言。
改变样式的脚本破坏编号
绝不使用改变段落样式的脚本(例如 LeganceTitle2 → FWBL2)来“修复”编号。样式与编号定义以复杂方式交互。文本匹配方法从不触碰样式。
reorder_definitions.py 提取的术语多于或少于预期(LibreOffice ST_OnOff)
症状:拒绝重排,列出一个或多个“可疑”提取术语,含引号、单词 means / indica / shall mean,或以冒号结尾。或者 --expected-defs N 报告数量错误。
原因:粗体 run 检测将关闭的粗体 run 误读为开启。最常见的原因是 <w:b w:val="0"/>——LibreOffice 在 .odt → .docx 转换时发出该标记以显式关闭粗体。ECMA-376 ST_OnOff 允许词法值 true | false | 1 | 0 | on | off(不区分大小写)。Rev11 修复了 reorder_definitions.py 和其他属性读取器以识别完整的假值集,因此这应该很罕见——但如果未来输入碰到其他 OOXML 怪癖,术语健全性守卫仍能捕获该症状。
修正:
- 用
--dry-run 重新运行以检查脚本提取了什么:
python <skill-path>/scripts/reorder_definitions.py \
--doc <workdir>/final/word/document.xml \
--dry-run --expected-defs <N>
- 如果某个单独的粗体检测变体是罪魁祸首,扩展相关脚本中的
is_on() / _ST_ONOFF_FALSE。
- 如果原因不明,按源顺序交付。重排是高价值但非强制的遍次——按源顺序的定义仍然清晰可读。
quality_check.py 会发出 definition_order 警告;在交付说明中将其记录为已知误报。
不要临时修补脚本以“强行”排序。 不变式检查无论如何都会中止。如果重排无法干净运行,按源顺序交付是受支持的兜底方案。
拆分或合并段落
如果翻译将一段源段落拆分为两段,文本匹配将无法为虚构段落找到匹配。始终:一段源段落 = 一段英文段落。
多 w:t run 在提取期间静默截断段落文本
在 .doc→.docx 转换中,LibreOffice 经常将条款编号和正文放在单个 <w:r> 元素中,用 <w:tab/> 分隔:
<w:r><w:t>11.3.1</w:t><w:tab/><w:t>Il 10% del Corrispettivo...</w:t></w:r>
使用 r.find('{W}t') 只返回第一个 w:t(“11.3.1”),静默丢弃整个正文。在一份测试文档中,这影响了 45 个段落和 1,547 个字符——包括付款里程碑条款和金融当事方同意条款。
症状:提取的 paragraphs.json 包含文本短得可疑的条目(只有一个如“11.3.1”的条款编号或如“(i)”的子引用),而原始文档显然有更多内容。翻译者将这些视为纯编号段落并原样翻译,使实质性文本在输出中保持未翻译。
修正:提取脚本必须遍历每个 w:r 的所有子元素,从每个 w:t 元素收集文本。见已修补的 extract_paragraphs.py。
纯正字法源编辑产生的无意义红线
源语言草稿通常包含仅修正源语言正字法的跟踪更改——缩写标点(荷兰语 mn → m.n.)、拼写改革(荷兰语 pro-actief → proactief、德语 daß → dass)、连字符(荷兰语 zonneenergie → zonne-energie)、变音符号恢复(coordinaat → coördinaat),或行尾断行引入的软连字符痕迹。翻译后,两侧坍缩为相同英文文本:mn 和 m.n. 都变成“in particular,”;zonneenergie 和 zonne-energie 都变成“solar energy”;coordinaat 和 coördinaat 都变成“coordinate”。英文输出中对应的红线看起来毫无意义——“in particular”被删除又插入“in particular”——并让任何看不到源荷兰语/德语/法语等的审阅者困惑。
症状:翻译后的文档有不起任何作用的跟踪更改标记。审阅者在红线视图中看到如“in particular ↔ in particular”或“proactive ↔ proactive”的短语。
修正(两步):
- 翻译时:当源编辑仅为正字法时,给
del 和 ins 段相同的英文文本。完整规则和决策测试见步骤 4 的“折叠纯正字法跟踪更改编辑——强制”。
apply_translations_textmatch.py 和 post_process.py 之后:运行 strip_noop_tracked_changes.py。它查找文本内容归一化为相同字符串的相邻 del/ins 对,删除 del 并展开 ins。它还剥离翻译后存活的空/纯标点包装。有意义的编辑(日期数字、术语替换、真实内容变更)原样保留。
字符碎片化源编辑在英文红线中的孤儿源字符
与正字法坍缩病理(del 和 ins 在英文中含义相同)不同,一些源草稿包含的跟踪更改编辑是单个单词被替换为另一个单词但逐字母编辑——单次概念编辑产生 5-10 个字符级 ins / del 段。分段感知的翻译者无法干净地将此映射到英文,因为英文替换整个单词,而非字符范围。
症状:红线视图中的英文条款标题读起来像 "Clause 13~~Clause 12~~eé cim otercera. Governing law…" 或 "D ecimo Clause 14~~Clause 13~~. General provisions"——正确的已接受条款编号落在正确位置,但孤儿源语言字符从中间段泄漏进标题。
修正(两步):
- 步骤 3b(翻译前):对
paragraphs.json 运行 coalesce_fragmented_tcs.py。脚本检测在两侧重组为连贯单词的连续字符级 ins/del 簇,并在每个标记段落写入预填的 en_segments 骨架,簇的第一个 ins/del 上为 <<TRANSLATE: …>> 占位符,簇的每个其他段上为空字符串 ""。它不修改 tc_segments。见步骤 3b 和步骤 4 的“混乱 / 字符碎片化整词编辑”小节。
- 翻译者将占位符替换为最终英文,空字符串槽保持
""。然后应用步骤使用 apply_translations_textmatch.py 的 v2026+ 行为——"en": ""(键存在、值为空)的段清除匹配 run,完全没有 "en" 键的段保留源——以产生无孤儿源字符的干净接受/拒绝红线。
跟踪更改删除文本留在源语言
当段落包含跟踪更改(w:ins/w:del 标记)时,可见的“已接受”文本存于 w:t 元素,但带删除线的已删除文本存于 w:delText 元素——一种不同的元素类型。如果应用脚本只遍历 w:t,w:delText 内容永远不会被触碰并保持源语言。任何查看跟踪更改的人都会立即看到。
修正:提取脚本现在从 w:delText 元素捕获 deleted_text。翻译者必须在 en 旁提供 en_deleted。应用脚本将 en 分配到活动的 w:t 元素、en_deleted 分配到 w:delText 元素,分别处理。见步骤 4 的“跟踪更改段落——强制双重翻译”。
跟踪更改段落中的粗体泄漏
<w:ins> 包装内的 run 携带原始跟踪插入的格式,通常包括粗体(通过 basedOn 链如 Cmsor2 → Cmsor1 从段落样式继承)。旧的应用方法在每个 run 上保留原始 rPr,导致粗体泄漏进翻译后的正文。用户在当事方部分、定义词段落或任何含跟踪更改的段落看到随机单词变粗。
修正:应用脚本现在对非标题跟踪更改段落中的所有 run 应用 <w:b w:val="0"/>(显式关闭粗体)。这与 make_run_et() 对非跟踪更改段落所做的相匹配,并防止样式继承的粗体泄漏进翻译后的正文。
翻译者修改忠实原文的翻译以满足质检检查器
quality_check.py 的截断模式是启发式的。当启发式标记一个实际上是对源文件的忠实翻译的段落时——最常见的是列表连接词如 ; and / , and(意大利语 ; e 的翻译)——正确的应对不是修剪连接词以让检查器闭嘴。这样做会静默剥离源作者有意起草的语义内容,结果是翻译不再匹配源文件。
症状。paragraphs.json 中的某个段落已在质检失败和通过之间被更改,而源文件的更改未反映。该段落现在以裸 ; 结尾(或其他标点重写),而非源文件原有的连接词。
**缓解。**当质检标记某个段落时,先对照源文件检查该问题。如果源连接词(; e、; o、, e、, o)存在且翻译忠实反映它(; and、; or、, and、, or),则质检标记是误报——保留忠实翻译,在交付说明中记录该误报,然后继续。**达到 0 个质检问题是可取的,但绝不以保真为代价。**截至 rev34,截断检查有一个列表连接词白名单,自动抑制这一特定误报;上述规则仍适用于未来出现的任何其他类误报。
维护者纪律
未来的修订版需要至少保持与今天相同的纪律覆盖强度。任何编辑本技能的人有三条规则:
-
如果你更改硬规则,同时更新本文件(硬规则部分)和受影响的步骤文件的内部合规检查。两者必须保持同步。
-
如果你新增步骤,更新强制阅读顺序、流水线概览和上一个步骤文件的“下一步:”指针。按既定模板新增 skill-docs/0X-...md(顶部预检横幅,底部内部合规检查)。
-
**步骤特定的程序细节属于 skill-docs/,不属于这里。**跨领域纪律(规则、防漂移、惯例、常见陷阱)属于本文件。不确定时,优先本文件——始终加载的内容优先于条件加载的内容。
开始工作流
完整阅读 SKILL.md 后,前往 skill-docs/01-setup-and-extract.md 开始步骤 1。