| name | legal-translation |
| metadata | {"author":"Wouter van den Berg - wouter@monteclima.com - linkedin.com/in/wjvandenberg","license":"mit","version":"2026-05-12"} |
| description | 将任何语言的法律文件翻译为英文,同时保留 .docx 格式,并翻译修订追踪和页眉/页脚。 每当用户要求将法律文件、合同、契据、协议或任何正式法律文本翻译为英文时使用本技能。 当用户提及翻译包含法律内容的 .docx 文件,或要求对法律文件进行"保留格式的翻译"时, 同样触发本技能。本技能覆盖所有法律领域:金融、并购、公司、知识产权、房地产、监管、 消费者、税务、诉讼、SaaS 等。即使用户只说"翻译这份合同"或"把这个翻译成英文", 只要文件性质属于法律文件,就使用本技能。
|
法律文件翻译技能
将任何语言的法律文件翻译为可出版质量的英文,同时保留所有原始 .docx 格式(字体、样式、页眉、表格、编号等)。
步骤前检查点——开始任何操作前先通读本文件
本技能的纪律取决于你是否真正阅读了 SKILL.md,而不仅仅是在上下文中加载了它。在执行任何步骤(步骤 1 至步骤 11)之前,在聊天中发布一行简短的确认信息:"对技能纪律的理解已确认,现在开始翻译流程。"(使用此确切措辞)。不要打印技术细节(硬性规则的所在位置、验证器名称、步骤文件)——用户不想要一堵内部状态文本的墙。写下确认信息这一行为本身即证明你已处于正确的位置;保持简短。
如果在即将输入该行时,你意识到自己无法凭记忆说出(a)硬性规则块位于何处,(b)哪些验证器会从 apply_translations_textmatch.py 自动调用(共四个),或(c)你即将执行的步骤所在的文件——停止,重新缓慢 Read('SKILL.md'),然后发布一行确认信息。内部验证是必需的;面向用户的验证展示则不是。
压缩续接触发——视为会话开始
如果本轮对话始于压缩后的转录(迹象:描述先前工作的系统消息、"摘要"前言、"本会话是从先前因上下文耗尽而中断的对话继续"的标题,或任何表明工作已在本轮你尚未 Read('SKILL.md') 的情况下取得进展的上下文),你必须将续接视为会话开始。**压缩摘要不能替代实际规则。**摘要可能将一条 100 行的规则压缩为一行,删去在当前案件中起决定作用的限定语,或省略包含你即将遇到的故障模式答案的附录。
具体而言,在每次压缩续接时,在任何工具调用之前:
- 完整
Read('SKILL.md')。
Read() 你即将操作的活动步骤文档。
Read() 压缩前你正在使用的任何词典/子词典。
- 在恢复工作前发布一行"对技能纪律的理解已确认,现在开始翻译流程。"
这不是"重新阅读你已读过的内容";而是阅读你在本轮尚未读过的内容。强制阅读顺序在每次压缩续接时适用,与首次会话开始时完全相同。切勿信任压缩摘要对规则的转述——如果摘要提到了某条规则,请前往文件阅读该规则的准确文本后再应用。
不要询问用户——这些是绝对默认值
以下为不可协商的默认值。不要暂停向用户询问这些事项。静默按默认值执行;仅在用户已在原始请求中给出明确指示时才切换。如果你发现自己在起草关于其中任何一项的澄清问题,停下——提问本身就是错误动作:
-
**英式英语是标准。**始终翻译为英式英语。唯一切换到美式英语的情形是用户已在请求中明确说明(如"翻译为美式英语"、"使用美国英语"等表述)。不要询问使用英式还是美式。不要抢先确认。直接翻译为英式英语即可,如果愿意,可在交付消息中提到美式英语可按需提供。
-
顺序、单上下文的翻译是唯一模式。翻译一份文件或多份文件时,只需在主上下文窗口中顺序进行。不要问"我是否应按顺序进行?"或"该技能规定顺序进行——您希望我如何继续?"——顺序是唯一模式。仅当用户明确要求子代理/并行处理时才询问用户,此时应警告质量风险并推荐顺序进行。
-
**一份文件完成全部 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 作为格式基础,仅替换每个段落内的文本运行(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 个新翻译段落的硬性上限;除非传递 --accept-large-batch,否则对超过 35 段进行批量验证会被阻止。
-
**步骤 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:识别文档类型、阅读词典、为 TC 搭建 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 等)— 跨语言英文惯例。对**英文法律写作如何处理某种惯例(无论源语言为何)**具有权威性:内部交叉引用用 Clause 还是 Article、定义词的大小写、"et al." 还是 "etc."、日期和货币格式、列表中的逗号用法、缩写风格等。
**当两者看似不一致时,跨语言参考优先。**日语子词典的 条 → "Article" 是引用映射;references/general-legal.md 规定合同中的内部交叉引用使用 "Clause"(例如 本契約第3条 → "Clause 3 of this Agreement",而非 "Article 3 of this Agreement")。参考规则将子词典映射限定于立法引用——它不与子词典矛盾,而是告诉你子词典的映射何时适用、何时不适用。同样的逻辑适用于每一种跨语言惯例:当质量检查发现内部引用中出现 "Article 3" 而子词典提供 Article 映射时,QC 发现是正确的,而非误报——在将其视为误报之前先阅读 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 | 搭建 | (仅限 TC 文档)为碎片化 TC 构建 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 文件中的每一个都必须在其涵盖的步骤处完整阅读。每个都以操作者必须完成的内部合规检查结束。
-
硬性规则适用于整个技能。 上述 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。这些都无法从 CLI 跳过。
-
逐批验证。 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 完全相同。不要"为节省上下文"、"因为文档很小"或"因为用户在等待"而捆绑批次。验证器的状态文件检查仍会触发;绕过它正是本节所指出的合理化借口。
- 强制阅读顺序在聊天模式中同样适用。如果你到达步骤 4 而本轮尚未
Read('skill-docs/04-translate.md'),停止并阅读。更小的逐步骤文件结构(一个约 700 行的步骤文档,而非单个 2500 行的 SKILL.md)使略读更具诱惑力;抵抗住。每个步骤文档的编写目的都是让操作者在到达相应工具调用前完整阅读。
如果你发现自己将偏差合理化("就这一次"、"文档很小"、"我会在后处理中捕获"、"我在聊天模式所以可以在上下文中保存"),停止。故障模式正是这种合理化。
为什么文本匹配很重要
从 .docx 提取段落时,提取脚本会分配顺序 idx 值。但 .docx 文档可能包含提取脚本与原始 XML 段落列表计数方式不同的元素:域代码、结构化文档标签、嵌套表格和其他结构元素可能导致 idx 值相对于实际 XML 段落索引发生漂移。
在真实世界测试中,一份文档显示 577 条 JSON 条目对应 564 个 XML 段落——漂移达 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 vs 577),从而无法匹配表格嵌套段落。结果是:签名栏、附表表格和表单字段仍未翻译。
在 6 份法律文件的测试中,3 份包含表格嵌套段落(分别为 13、14 和 26 个)。如果没有递归搜索,它们全部——签名栏、附表表格和当事人信息表单——都会停留在源语言。
目标英文变体:英式英语(不要询问用户)
本技能翻译为英式英语。英式是硬编码标准。不要询问用户"英式还是美式英语?"——答案是英式。适用美式英语的唯一情形是用户已经在原始提示中给出明确指示(如"翻译为美式英语"、"使用美国英语"等表述)。如果没有,静默按英式进行;可以在交付消息中提到"美式英语可按需提供",而不是打断翻译去询问。
**防漂移规则——在每次变体选择前阅读此条。**在做出任何依赖英文变体的决定之前(页面上放什么、向 post_process.py --variant 传递什么标志、向 quality_check.py --variant 传递什么标志、交付消息中如何拼写某个词),执行以下操作:
- 回到用户对此翻译的原始提示。
- 在其中搜索明确的美式英语指示词:"US English"、"American English"、"American spelling"、"US spelling" 或明确等同的表述。
- 当且仅当找到时,使用美式英语。
- 否则——包括用户提到美国当事人、美国相对方、美国收件人或任何其他感觉美式的情况——使用英式英语。
不要从上下文、客户国籍、文件准据法、文件名或任何中间消息推断"美式英语"。只有用户原始提示中的明确指示才能切换变体。如有任何疑问,选择英式。此重新检查必须在以下每个决策点进行;不要缓存会话早期的决定:
- 起草包含变体敏感拼写或词汇的翻译时;
- 调用
post_process.py 时(默认传递 --variant uk);
- 调用
quality_check.py 时(默认传递 --variant uk);
- 向用户撰写交付消息时。
**用户如何切换到美式英语:**用户必须在请求中包含直接指示——如"翻译为美式英语"、"使用美国英语"、"美式拼写"等表述。当他们这样做时,为该翻译应用美式英语,并向后处理和质量检查脚本均传递 --variant us。如果他们未明确说明,英式胜出——可以在交付消息中提到美式英语可按需提供,而不是打断翻译去询问。
变体管辖的内容:
- 拼写: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(含 TC 删除文本) |
coalesce_fragmented_tcs.py | 如果源文件有 TC 则为强制性 — 检测字符级 TC 碎片(如西班牙语 "Duodécima" → "Decimotercera" 逐字母编辑),并在首个 ins/del 上以占位符、中间运行以空字符串搭建 en_segments 骨架;tc_segments 保持不变 |
validate_translations.py | 检查翻译完整性(字符比率)。步骤 4 中的逐批调用是手动的;最终应用前检查从 apply_translations_textmatch.py 内部自动运行。 |
validate_segment_shapes.py | 如果源文件有 TC 则为强制性 — 应用前形状检查器:逐对扫描 en_segments 中的 XML 边界风险形状(冠词冲突、跨越边界且无空白的字母冲突——非拉丁文字陷阱、TC 边界的数字、横跨边界的双空格、裸冠词 TC 片段、内部 camelCase 冲突)。在 TC 文档上从 apply_translations_textmatch.py 自动运行。 |
validate_reject_all.py | 如果源文件有 TC 则为强制性 — 从 en_segments 重建全部接受和全部拒绝视图,并扫描可读性缺陷(双冠词、重复词、孤立介词、连写词、双空格、空括号、禁用搭配)。在 TC 文档上从 apply_translations_textmatch.py 自动运行。 |
lexicon_compliance.py | 强制性(应用前和重新打包前) — 扫描 JSON 或 document.xml 中来自词典"避免"列的仿译和硬性规则违反。应用前运行为手动(步骤 4d);重新打包前运行在打包前从 repack_docx.py 内部自动触发。 |
apply_translations_textmatch.py | 主要 — 通过文本匹配将翻译应用到原始文件。自动运行 validate_translations.py(仅 BLOCK 代码 2),在 TC 文档上另运行 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 等)。这会导致"内容不可读"错误。textmatch 脚本分两层处理:首先将原始 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 规则规定合同内部交叉引用使用 "Clause" 而非 "Article"(如 本契約第3条 → "Clause 3 of this Agreement"),但译者只查阅了子词典,将其映射视为所有用途的权威,并在全篇产出 "Article 3"。当 quality_check.py 后来标记内部引用中的 "Article N" 时,译者将 QC 发现误读为误报,并通过正则批量将 "Article" 替换为 "Clause" 以使门禁通过——在未查阅权威来源的情况下解决了症状。
**根本原因。**阅读子词典而未阅读匹配的 references/<domain>.md。子词典映射在范围内是正确的(日语的 条 在 民法第30条 等立法引用中确实是 "Article");跨语言参考按用法限定映射的适用(内部合同引用用 "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 的重新打包。
ElementTree 损坏辅助 XML(导致"内容不可读")
症状:翻译后的 .docx 在 Word 中拒绝打开,出现"内容不可读"或"文件已损坏"错误。通过 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 段,将其作为最终批次翻译——不要合并到上一批中。
提取与原始文件的段落数不匹配
提取可能产生多于或少于实际 XML 段落的 JSON 条目。文本匹配使这无关紧要——多余的条目被跳过,缺失的条目使文本停留在源语言。
改变样式的脚本破坏编号
切勿使用更改段落样式的脚本(如 LeganceTitle2 → FWBL2)来"修复"编号。样式与编号定义以复杂方式交互。文本匹配方法从不触碰样式。
reorder_definitions.py 提取的术语多于或少于预期(LibreOffice ST_OnOff)
症状:拒绝重排,列出包含引号、means / indica / shall mean 字样或以冒号结尾的一个或多个"可疑"提取术语。或者 --expected-defs N 报告数量错误。
原因:粗体运行检测将关闭粗体的运行误读为开启粗体。最常见的原因是 <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 运行在提取期间静默截断段落文本
在 .doc→.docx 转换中,LibreOffice 经常将条款编号和正文放在由 <w:tab/> 分隔的单个 <w:r> 元素中:
<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 中的"折叠仅正字法的 TC 编辑——强制性"。
- 在
apply_translations_textmatch.py 和 post_process.py 之后:运行 strip_noop_tracked_changes.py。它找到文本内容规范化为相同字符串的相邻 del/ins 对,移除 del 并解包 ins。它还会剥离翻译后存活的空/纯标点包装器。有意义的编辑(日期数字、术语替换、真实内容变更)保持原封不动。
字符碎片化源编辑在英文红线中残留孤立的源字符
与正字法折叠病态(两侧在英文中含义相同)不同,某些源草稿包含这样的 TC 编辑:单个词被替换为不同的单个词,但逐字母编辑——为单个概念编辑产生 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": ""(键存在、值为空)的片段清除匹配的运行,完全没有 "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> 包装器内的运行携带原始追踪插入的格式,通常包含粗体(通过 basedOn 链如 Cmsor2 → Cmsor1 从段落样式继承)。旧的应用方法在每个运行上保留原始 rPr,导致粗体泄漏进翻译后的正文。用户会在当事人部分、定义词段落或任何有修订追踪的段落中看到随机加粗的词。
修正:应用脚本现在对非标题 TC 段落中的所有运行应用 <w:b w:val="0"/>(显式关闭粗体)。这与 make_run_et() 对非 TC 段落所做的处理一致,防止样式继承的粗体泄漏进翻译后的正文。
译者修改忠实于源文的翻译以满足 QC 检查器
quality_check.py 的截断模式是启发式的。当启发式标记一个实际是源文忠实翻译的段落时——最常见的是列表连接词如 ; and / , and(意大利语 ; e 的翻译)——正确的回应不是裁剪连接词以让检查器安静。这样做会静默剥离源文作者有意起草的语义内容,结果是翻译不再与源文匹配。
症状。paragraphs.json 中的某个段落从 QC 失败到 QC 通过之间被修改,而未反映源文的变化。该段落现在以裸露的 ;(或其他标点改写)结尾,而非源文原有的连接词。
**缓解。**当 QC 标记一个段落时,首先对照源文检查该问题。如果源连接词(; e、; o、, e、, o)存在且翻译忠实地反映它(; and、; or、, and、, or),则 QC 标记是误报——保留忠实翻译,在交付说明中记录该误报,然后继续。**达到 0 QC 问题值得追求,但绝不以保真为代价。**截至 rev34,截断检查具有列表连接词白名单,可自动抑制这一特定误报;上述规则仍适用于未来出现的任何其他类别的误报。
维护者纪律
未来的修订版需要将纪律覆盖保持至少与今天同等强度。任何编辑本技能的人的三条规则:
-
如果更改硬性规则,同时更新本文件(硬性规则部分)和受影响的步骤文件的内部合规检查。两者必须保持同步。
-
如果添加步骤,更新强制阅读顺序、流程概览和上一个步骤文件的"Next:"指针。按照既定模板添加新的 skill-docs/0X-...md(顶部为预检横幅,底部为内部合规检查)。
-
**步骤特定的程序性细节属于 skill-docs/,而非本文件。**跨领域纪律(规则、防漂移、惯例、常见陷阱)属于本文件。如不确定,优先本文件——始终加载的内容优于条件加载的内容。
开始工作流
完整阅读 SKILL.md 后,继续阅读 skill-docs/01-setup-and-extract.md 以开始步骤 1。