简介:ISO 22900-2:2017是道路车辆模块化车辆通信接口(MVCI)系列标准的第二部分,专门规定诊断协议数据单元(D-PDU API)的接口规范。这份中英文对照翻译文档由DeePL机器翻译生成,同时保留英文原文与中文译文,适合汽车电子诊断工程师、测试设备研发人员以及需要对接ODX与MVCI协议栈的技术人员阅读。文档覆盖了范围、规范性引用、术语定义、规范发布版本信息、模块化VCI用例等内容,并重点解释了D-Server如何利用ODX运行时数据将应用请求转换成字节流形式的D-PDU,再通过D-PDU API交付给MVCI协议模块,帮助理解请求转换、错误处理、数据编码、安全性、实时性等关键技术点。资源为单个docx文件,大小约760KB,排版清晰便于检索与对照。目前已有1864人学习浏览,对于从事车辆诊断协议开发或正在进行相关标准研究的读者,这份资料能够显著缩短阅读英文原版标准的时间,快速建立对D-PDU API核心概念与调用逻辑的整体认识。
1. 为什么 ISO 22900-2 D-PDU-API 文档会成为团队瓶颈
ECU 开发团队遇到 ISO 22900-2 D-PDU-API 译文的需求,通常不是有人想重复造轮子,而是来自一个具体场景:自动化测试脚本和诊断仪软件都要对接 D-PDU-API,组内文档和技术评审全是中文,标准文本只有英文。靠个人去读英文原版能推进,但在方案评审、审计记录和跨组协作时,每个人摘出的术语不一致,沟通成本立刻上来。把 ISO 22900-2-2017 D-PDU-API 中英文 DeePL翻译 作为可执行任务来做,核心其实不是“翻译”两个字怎么通顺,而是一整套处理工程文档的流程:先把标准拆成结构化文本,再让 DeepL 负责初译,最后用术语表与格式保护把质量拉回可用水平。这套流程适合小团队和独立工程师,不需要申请翻译预算,也不依赖外包排期。下面的章节按这条路径展开,先从标准本身的结构说起,再给出每条命令和参数。
2. 拆解 ISO 22900-2 D-PDU-API 文档结构
2.1 MVCI 体系里 D-PDU-API 的定位与接口分层
ISO 22900-2 是模块化车辆通信接口(MVCI)标准群的第二部分,名字里直接写明了 D-PDU-API 这个核心对象。这里的 API 负责把诊断工具与下层硬件解耦:上面是测试脚本和诊断应用,下面是不同的诊断协议通道。D-PDU-API 给出的不是一组零散的收发函数,而是一个包含服务类、数据类、事件回调的完整接口体系,调用方必须按照会话建立、参数配置、请求发送、响应接收的次序来使用它。对准备翻译的人而言,这意味着文档中有大量描述调用关系和数据结构的段落,这些段落与普通技术说明不同,它们的翻译正确性要建立在“接口行为可理解”之上,字面通顺并不等于可用。
理解这一层之后,再去看标准的章节安排就顺了:前面是规范性引用和术语定义,中间是接口要求与消息格式,后面是协议映射和一致性声明。术语定义这一块看起来像普通词汇解释,实际上每个条目都是后续条文的约束来源,翻译时必须保持单词与释义的严格对应,否则后面出现同一英文术语时容易找不回对照关系。另一个值得注意的点是标准版本差异。ISO 22900-2:2017 相对更早的版本在接口定义和术语上都有调整,网上流传的旧版中文摘录和新版不能直接互相引用,翻译时一切以 2017 版原文为准,遇到与旧资料冲突的地方记录差异而不是照抄旧译文,这能为后续版本更新省下大量澄清成本。
2.2 标准文本里真正难译的三类内容
第一类是规范性动词。ISO 标准里 shall、should、may 分别代表强制、建议和允许,整份文档反复出现。中文技术文档习惯把它们都译成“应当”或“可以”,这种混用在普通阅读时没多大影响,但在接口协议里,把 shall 和 should 混为一谈会让实现方误判约束等级,测试人员和供应商对不一致性的理解也不同。因此翻译管线里要把这类词的译法固定下来。
第二类是协议与数据类型相关表格。表格里通常包含枚举值、位掩码和状态码,这些内容本身不需要意译,但它们所在行的说明文本需要翻译,且不能打乱表格对齐关系。用 DeepL 直接翻译整个表格段落,模型会尝试重排内容,导致列错位、换行丢失。常规做法是优先做表格抽取,把每格内容独立作为待翻译单元。
第三类是跨章节引用。正文描述“见 6.2”或“按照 ISO 14229 规定”这类引用,机器翻译有时会把数字和标准号也一起改动。对这种引用要做占位符保护,把章节号、标准编号单独标记,让翻译引擎只能处理周围文字。这三类问题的处理策略可以汇总为下面这张表,后续管线配置会逐一对应。
| 难译内容 | 典型示例 | 处理策略 |
|---|---|---|
| 规范性动词 | shall / should / may | 建立固定译法并写入术语表 |
| 表格字段 | 枚举值、位掩码、状态码说明 | 逐格抽取翻译后重组 |
| 跨章节引用 | “见 6.2”、ISO 14229-1 | 用 XML 占位符保护 |
2.3 为什么通用翻译在接口定义部分会翻车
直接拿整段文本给 DeepL,输出往往读起来通顺,但放到 D-PDU-API 接口定义里会出现三类常见错误。一类是参数名被意译,比如模块名 internalFlag 被翻成“内部标志”而非保留原标识符,导致译文读者无法反向索引原文,在接口文档里你甚至不知道这个 Flag 对应哪个参数位;一类是被动语态结构改变,英文技术标准的被动语态在中文里对应多种表达,机器翻译默认选的形式不一定匹配技术语体;另一类是上下文丢失,同一个词在前文用作数据缓冲区、后文用作参数域名称,分开翻译得到的词不一致,术语表如果不参与每个段落的翻译就无法消解。这些问题的根源在于标准文本的上下文依赖关系比产品说明书强得多。后面章节给出的方案不是让 DeepL 学会思考,而是用预处理和事后校验把这类上下文信息重新注入翻译流程。
3. 搭建 ISO 22900-2 D-PDU-API 的 DeepL 翻译管线
3.1 文档预处理:把 PDF 拆成结构化片段
开始做翻译之前要决定目标格式。我一般会把 Markdown 作为中间格式,每个三级标题对应标准的一节,表格保留为 Markdown 表格,代码和伪代码块保持原样。从 PDF 到 Markdown 用 pdfplumber 抽取文本,脚本按页输出,再把页面合并成章节文件。这一步必须做的是“单元切分”,即把整个标准切成适合单次翻译单元的小片段,DeepL API 对单请求的文本长度有限制,过长的段落容易在翻译过程中丢标点。
import pdfplumber import re def extract_pages(pdf_path, out_dir): with pdfplumber.open(pdf_path) as pdf: for page_no, page in enumerate(pdf.pages, start=1): text = page.extract_text() or "" text = re.sub(r"-\n", "", text) # 合并行尾连字符断行 text = re.sub(r"[ \t]+", " ", text) # 压缩多余空白 with open(f"{out_dir}/page_{page_no:03d}.txt", "w", encoding="utf-8") as fh: fh.write(text) extract_pages("ISO_22900-2_2017.pdf", "pages")这里遇到的坑是表格内容被 PDF 抽取工具变成行内文本。如果发现表格列错位,就不要用 extract_text 直接工作,改用它提供的 extract_tables 方法把单元格数据取出来,再自己拼成 Markdown 表格,这一步在 D-PDU-API 文档里几乎是必做的,因为参数表占了相当篇幅。抽取工具对扫描件无法处理,那就得先做 OCR,但 OCR 对表格结构的识别误差高,建议遇到扫描质量差的情况先解决原始 PDF 的质量再谈翻译。
3.2 DeepL API 调用与参数选择
抽取完成后进入翻译环节,核心动作是调用 DeepL v2 翻译接口。下面的函数用于翻译一个文本块,参数选择对技术文档影响很大。
import requests DEEPL_URL = "https://api-free.deepl.com/v2/translate" AUTH_KEY = "你的密钥" def deepl_translate(text, glossary_id=None): payload = { "text": text, "target_lang": "ZH", "source_lang": "EN", "split_sentences": "0", # 禁止自动断句 "preserve_formatting": "1", # 保留换行与空行 "tag_handling": "xml", # 保护尖括号标签 } if glossary_id: payload["glossary_id"] = glossary_id resp = requests.post( DEEPL_URL, data=payload, headers={"Authorization": f"DeepL-Auth-Key {AUTH_KEY}"}, ) resp.raise_for_status() return resp.json()["translations"][0]["text"] sample = "The server shall transmit at least one response before the timer expires." print(deepl_translate(sample))split_sentences 设为"0"让 DeepL 不要按句号自动切开长句,因为标准条文里大量出现带分号和列表的复合句,自动切分会把限定条件拆到两个翻译单元里,词序会被重排。preserve_formatting 设为"1"保持输入中的换行数量,伪代码和列表的缩进因此不会丢失。tag_handling 设为"xml"是最关键的一项,它让翻译引擎把形如<x id="...">的占位符当作不可译元素保留,后面会用到这个特性来保护章节引用。部分订阅计划还提供 context 参数,用来向翻译引擎提供段落级别的背景文本。可以在调用时把当前章节的标题作为上下文传入,例如"context": "D-PDU-API session configuration",让模型倾向于使用与诊断会话配置一致的术语。这个参数对消除歧义有帮助,但要注意它不参与最终输出,只影响翻译方向,不适合用来注入大段背景知识。
3.3 批量拆分与合并:长文档不断章
单次请求能处理的翻译单元有限,整章一起发会达到请求长度上限,更稳妥的做法是把章节按段落拆成列表,逐条翻译再合并。下面这段脚本同时体现了拆分与合并的逻辑,按空行分组,每个分组调用一次翻译接口,并把翻译结果按顺序写回 Markdown 文件。
def translate_markdown(md_path, output_path, glossary_id=None): with open(md_path, encoding="utf-8") as fh: content = fh.read() blocks = content.split("\n\n") translated = [] for block in blocks: if block.strip().startswith(("|", "```", "#")): translated.append(block) # 表格、代码块、标题原样保留 continue if block.strip(): translated.append(deepl_translate(block.strip(), glossary_id)) else: translated.append("") with open(output_path, "w", encoding="utf-8") as fh: fh.write("\n\n".join(translated))这个简化版的意图是讲清楚流程:首个条件把以竖线、反引号、井号开头的块直接跳过,不做翻译;普通段落逐块翻译,最后按原顺序组装。真实场景里表格不能整块跳过,而是要把表格提取独立处理,上一步预处理里的 extract_tables 输出正好作为表格翻译的输入,翻译完再重新拼成 Markdown 表格,避免 DeepL 重排单元格结构。
3.4 后处理:把译文还原为 Markdown 结构
翻译完成后的文件会在标题层级和列表符号的间距上出现偏差,常见问题有三个:中文与英文之间的空格处理、列表符号后的缩进丢失、代码块内文字被意外替换。这些不属于 DeepL 的翻译范围,而是组装脚本留下的痕迹,所以后处理阶段用一组正则与固定规则来还原。
import re def postprocess(text): # 收紧列表符号和文本之间的多余空白 text = re.sub(r"^(\s*[-*]) \s+", r"\1 ", text, flags=re.M) # 去掉中文与 ASCII 字符之间的多余空格,保留英文单词间空格 text = re.sub(r"([\u4e00-\u9fff]) ([A-Za-z0-9])", r"\1\2", text) return text这里去掉空格时要注意只处理中文与数字字母之间的空格,英文句子内部的空格不能动。所以正则只匹配“中文+空格+ASCII”,如果你本意是保留中英文间距,就把第二个规则改成保留一个半角空格,团队内部统一即可。到此你已经得到一份可用的中英 Markdown 对照文件,下一步是检查术语。
4. 术语一致性是 D-PDU-API 翻译质量的胜负手
4.1 建立标准术语表并挂载到 API 调用
D-PDU-API 相关术语虽然不算特别生僻,但在标准语境下有固定译法。团队内部常见做法是先收集高频词汇形成 TSV,再上传为 DeepL 术语表。术语表不只约束翻译结果,还能让同样一句话在多次翻译中得到同一译文,这是翻译记忆之外的第二层保障。
import requests import uuid entries = ( "D-PDU-API\t诊断协议数据单元应用程序接口\n" "ECU\t电控单元\n" "request\t请求\n" "response\t响应\n" "session\t会话\n" "timeout\t超时\n" ) resp = requests.post( "https://api-free.deepl.com/v2/glossaries", headers={"Authorization": f"DeepL-Auth-Key {AUTH_KEY}"}, data={ "name": f"iso22900-2-{uuid.uuid4().hex[:8]}", "source_lang": "EN", "target_lang": "ZH", "entries_format": "tsv", }, files={"entries": ("glossary.tsv", entries.encode("utf-8"))}, ) print(resp.json()["glossary_id"])上传成功后把返回的 glossary_id 传给第 3.2 节的 deepl_translate 函数。术语表的粒度不需要覆盖所有名词,重点是具有多义性和家族相似性的词,比如 session 在某些上下文里是“会话”,在另一些地方可能指“一次通讯过程”,如果不约束,机器翻译会自由发挥。若订阅计划不支持术语表接口,可以跳过上传,把术语表维护在校验脚本里,用字符串替换统一译文,效果稍弱但流程依然成立。
4.2 用占位符保护章节引用与标准编号
第 2 章提到的跨章节引用问题,这里给出具体的占位符方案。做法是在预处理阶段把“Clause 6.2”“ISO 14229-1”这类内容替换成 XML 标签,让 tag_handling=xml 模式把它们整体保留下来。DeepL 对这类标签的常规行为是原样保留不翻译,完成后只需用反向映射恢复原文。
import re PLACEHOLDER_TEMPLATE = '<x id="{n}"/>' def protect_refs(text): mapping = {} def repl(match): key = match.group(0) if key not in mapping: mapping[key] = PLACEHOLDER_TEMPLATE.format(n=len(mapping) + 1) return mapping[key] protected = re.sub( r"(Clause \d+(?:\.\d+)*|ISO \d+(?:-\d+)?:\d{4})", repl, text ) return protected, mapping def restore_refs(translated, mapping): inv = {v: k for k, v in mapping.items()} for placeholder, original in inv.items(): translated = translated.replace(placeholder, original) return translated两个函数一个做替换一个做恢复,中间的翻译过程保持填入标签的文本即可。占位符的粒度值得注意,只保护最小单元,不要把整个句子替换成占位符。把“The PDU shall be transmitted within the timeout period”整体替换成占位符,翻译引擎没有任何可依据的语义上下文,输出只能是猜测,占位符保护就失去了意义。正确的粒度是只保护编号、标准号、变量名这些实体,句子主干仍保留给 DeepL 处理。
4.3 用术语覆盖率检查翻译质量
翻译完成后做一次自动检查,把术语表里每个中文术语与译文比对,计算覆盖率,标记缺失项。
TERMS_ZH = ["诊断协议数据单元应用程序接口", "电控单元", "请求", "响应", "会话", "超时"] def term_coverage(translated_text, terms=TERMS_ZH): total = len(terms) hit = [t for t in terms if t in translated_text] missing = list(set(terms) - set(hit)) return len(hit) / total, missing with open("translated_zh.md", encoding="utf-8") as fh: translated_doc = fh.read() coverage, missing = term_coverage(translated_doc) print(f"术语覆盖率: {coverage:.1%}, 缺失: {missing}")这里的覆盖率是一个粗筛,不是质量标准。术语表里的词分布在全文各处,只要在几个章节里一致出现就不会被标记,所以要配合抽样人工复核才能暴露局部不一致。实际项目中我会在中间章节选两三处参数密集的段落,把英文原文、初译、人工修订逐一对照,比对重点就是 D-PDU-API 服务名称是否保留、shall 与 should 是否严格区分。
5. 让 ISO 22900-2 翻译资产持续可复用
5.1 保存翻译记忆库,别让相同句子翻两次
ISO 标准发布修订版时,改动范围通常有限,大量条款原样保留。如果重新跑一遍全量翻译,时间成本还能接受,但人工校审的代价就高了。更合理的做法是维护一份翻译记忆库,以“英文段落的规范化文本”为键,把最终确认的中文译文存进一个 JSON 文件。每次翻译前先查库,只对未命中或内容不一致的段落调用 DeepL。
import json import os tm_path = "tm.json" tm = json.load(open(tm_path)) if os.path.exists(tm_path) else {} def translate_with_tm(block, glossary_id=None): if block in tm: return tm[block] result = deepl_translate(block, glossary_id) tm[block] = result return result # 全部完成后写回 json.dump(tm, open(tm_path, "w", encoding="utf-8"), ensure_ascii=False, indent=2)翻译记忆库的反面意义在于它只记录确认过的译文。从 DeepL 直接返回的结果不应自动写入,否则错误的初始翻译会被固化。正确流程是先让术语覆盖率检查通过,再人工校审一次,之后才把校审稿写回记忆库。
5.2 增量更新:修订版只翻译变更部分
当 ISO 22900-2 的后续修订版发布,把新 PDF 的段落哈希与记忆库键做比对,差异集就是需要重新翻译的内容。哈希值可以用 PDF 抽取后的文本块计算,不依赖官方发布说明。常见做法是生成一份 diff 报告,列出新增、删除、修改的条款编号,人工对新段落执行第 3 章的翻译流程即可,原有译文无需返工。
5.3 最小验收清单
留一份验收清单在交付前逐项打勾,把翻译管线里的主观质量评估拆成可执行条目,关键项如下:
- 术语覆盖率不低于预设阈值,缺失项已逐个确认;
- 所有“见 x.x”引用保持原文编号,没有被意译或改写;
- 表格列数在翻译前后一致,单元格顺序未被打乱;
- 代码示例里的变量名没有被修改,标识符大小写保持原样;
- shall 与 should 的译法区分明确,全文统一。
任何一项不通过都要回到对应环节修,而不是在最终文档上手工改动,因为手工改动不会反馈到术语表或记忆库,下一次翻译还会犯同样的错。
本文还有配套的精品资源,点击获取