简介:本资源为ISO 22900-2:2017《道路车辆—模块化车辆通信接口(MVCI)—第2部分:诊断协议数据单元(D-PDU API)》标准的中英文对照文档,采用DeePL翻译,面向汽车诊断协议开发、ECU通信测试及MVCI工具链相关工程师与技术人员。标准正文系统规定了D-PDU API的接口规范,涵盖请求转换、错误处理、数据编码、安全性与实时性等关键内容,并给出规范发布版本信息、MVCI用例及术语定义,可帮助读者理解D-Server如何借助ODX运行时数据将应用请求转换为D-PDU并交由MVCI协议模块处理。资源包内含1个docx文件,约760KB,中英对照排版便于逐条比对原文与译文,适合作为协议实现、接口对接与标准查阅的案头参考。目前已有1865人学习下载,对需要快速掌握D-PDU API规范细节的开发者具有较高参考价值。
1. 从一份被翻译“卡住”的 D-PDU-API 文档说起
如果你正在做汽车诊断协议栈开发,大概率绕不开 ISO 22900-2 这个标准。它定义了 D-PDU-API(Diagnostic Protocol Data Unit API),是诊断应用层和底层通信硬件之间的标准接口。而 2017 版相比老版本,在 CAN FD、DoIP 以及多通道并发上做了不少调整。问题在于,这份标准原文是英文,且充斥着大量缩写和协议栈术语,直接读原文效率极低。于是很多人第一反应是:找一份中英文对照版,或者干脆用 DeePL 翻译一遍。
但真动手翻译过的人都知道,D-PDU-API 文档不是普通技术文档。它里面有大量“看起来像英文但其实是标识符”的内容,比如PDU、M-Type、CM_开头的函数名、ISO_15765_2这类协议常量。DeePL 默认会把这些当普通单词翻译,结果就是函数名被拆成中文、参数类型被意译、枚举值被改写。你拿到译文后,反而要花更多时间去对照原文猜它到底在说什么。
这篇笔记就是围绕“怎么把 ISO 22900-2-2017 的 D-PDU-API 文档用 DeePL 翻译成可用的中英文对照版本”来展开。我会从术语保护、分段策略、API 名称白名单、翻译后校验这几个角度,把一套可复现的流程拆开讲。适合正在读这份标准、准备做协议栈对接、或者需要给团队输出中文参考材料的工程师。如果你只是想知道“DeePL 能不能翻译技术文档”,那答案是能,但前提是你得先把它“驯服”成不会乱动标识符的状态。
2. 为什么直接扔给 DeePL 会翻车:D-PDU-API 文档的四个特殊结构
2.1 标识符与自然语言混排,翻译器分不清边界
D-PDU-API 文档里最常见的段落长这样:
The function PDUConstruct shall initialize the PDU structure. The parameter pPDU points to the PDU to be initialized.对 DeePL 来说,PDUConstruct和pPDU就是普通英文单词。它可能会把PDUConstruct翻译成“PDU构造”,把pPDU翻译成“pPDU”(有时保留,有时改成“PDU指针”)。更麻烦的是shall这种情态动词,在标准里表示“必须”,但 DeePL 经常翻成“应该”或“将”,直接改变规范强度。
我一般会先把文档里所有“不能翻译”的内容抽出来,做成保护列表。保护列表分三类:函数名与宏名、参数与变量名、协议常量与枚举值。这三类在文档里通常有固定命名风格,比如函数名是驼峰或下划线大写,参数常带p前缀,协议常量是全大写下划线。用正则先扫一遍,比人工找快得多。
2.2 表格与列表里的 API 定义,翻译后列错位
标准文档里有大量表格,比如“参数说明表”:
| 参数 | 类型 | 说明 |
|---|---|---|
| pPDU | PDU* | 指向待初始化的 PDU 结构 |
| Status | unsigned long | 返回状态码 |
DeePL 对表格的处理是逐单元格翻译,但它不会保留 Markdown 表格的对齐。如果你直接把整个表格贴进去,译文里|的数量可能对不上,或者单元格内容被合并。更稳妥的做法是:先把表格转成“键值对”文本,翻译完再还原成表格。或者只翻译“说明”列,参数和类型列直接保留原文。
2.3 版本差异术语:2017 版新增内容容易被旧译法带偏
ISO 22900-2:2017 相比 2009 版,增加了 CAN FD 相关定义和 DoIP 激活线要求。如果你拿旧版译文做术语库,会把CAN FD翻成“CAN 柔性数据”之类奇怪的东西。DeePL 本身没有版本概念,它只会按当前语料翻译。所以术语表必须针对 2017 版重新整理,尤其是CAN FD、DoIP、Ethernet Activation Line这几个词,必须锁定译法。
2.4 DeePL 的“上下文改写”会破坏规范句式
标准里大量使用shall、shall not、may、should。DeePL 为了语句通顺,经常把shall改成“将”或“应”,把shall not改成“不得”或“不能”。但规范里shall和should的法律含义完全不同。我的做法是:在翻译前把shall替换成MUST,shall not替换成MUST NOT,should替换成SHOULD,翻译完再替换回来。这样 DeePL 会优先保留大写情态动词,减少语义漂移。
3. 用 Python 做预处理:把文档拆成“可翻译块”和“保护块”
3.1 整体流程与依赖
我一般用 Python 做预处理,核心依赖就三个:re做正则、json存保护列表、openpyxl或pandas处理表格。如果你拿到的原文是 Word 或 PDF,先用python-docx或pdfplumber转成纯文本,再按段落切分。下面这段代码是预处理的核心逻辑:把文本按行扫描,识别出“保护行”和“翻译行”。
import re import json # 保护规则:函数名、宏、参数、协议常量 PROTECT_PATTERNS = [ r'\b[A-Z][a-zA-Z0-9]*\(', # 函数名,如 PDUConstruct( r'\b[a-z]+[A-Z][a-zA-Z0-9]*\b', # 驼峰参数,如 pPDU r'\b[A-Z_]{3,}\b', # 全大写常量,如 ISO_15765_2 r'\b0x[0-9A-Fa-f]+\b', # 十六进制 ] def is_protected(token): for pat in PROTECT_PATTERNS: if re.fullmatch(pat, token): return True return False def split_line(line): """把一行拆成 token 列表,标记哪些需要保护""" tokens = re.split(r'(\s+|[(),;])', line) result = [] for t in tokens: if t.strip() and is_protected(t.strip()): result.append(('PROTECT', t)) else: result.append(('TRANSLATE', t)) return result # 示例 line = "The function PDUConstruct shall initialize the PDU structure." for tag, token in split_line(line): print(tag, repr(token))这段代码的输出会把PDUConstruct标记为PROTECT,把The function标记为TRANSLATE。实际使用时,我会把连续TRANSLATE的 token 合并成一个片段,送去 DeePL;PROTECT的 token 直接保留。这样 DeePL 看到的输入是“The function [PROTECT_0] shall initialize the [PROTECT_1] structure.”,翻译完再把占位符换回来。
3.2 占位符设计:别用数字,用带语义的标记
占位符如果只用{0}、{1},DeePL 有时会把它当变量翻译掉。我习惯用[[PROTECT_函数名_0]]这种带语义的格式,DeePL 会倾向于原样保留。但注意,占位符本身不能太长,否则会干扰句子结构。一般控制在 20 个字符以内。
def replace_protected(line): tokens = split_line(line) protected_map = {} output = [] idx = 0 for tag, token in tokens: if tag == 'PROTECT': key = f"[[P{idx}]]" protected_map[key] = token output.append(key) idx += 1 else: output.append(token) return ''.join(output), protected_map line = "The function PDUConstruct shall initialize the PDU structure." masked, pmap = replace_protected(line) print(masked) print(json.dumps(pmap, ensure_ascii=False))输出类似:
The function [[P0]] shall initialize the [[P1]] structure. {"[[P0]]": "PDUConstruct", "[[P1]]": "PDU"}这样送去 DeePL 翻译,回来后再用pmap还原。注意shall我还没处理,下一步会单独替换。
3.3 情态动词预处理:把 shall 换成 MUST
在调用 DeePL 之前,先做一次全局替换:
def normalize_modals(text): text = re.sub(r'\bshall not\b', 'MUST NOT', text, flags=re.IGNORECASE) text = re.sub(r'\bshall\b', 'MUST', text, flags=re.IGNORECASE) text = re.sub(r'\bshould not\b', 'SHOULD NOT', text, flags=re.IGNORECASE) text = re.sub(r'\bshould\b', 'SHOULD', text, flags=re.IGNORECASE) return text翻译完再反向替换:MUST NOT→不得,MUST→必须,SHOULD→应。这样能保证规范强度不丢。注意may我一般保留英文,因为“可以”和“可能”在中文里容易歧义,直接保留may反而更清楚。
3.4 表格处理:只翻译说明列
对于 Markdown 表格,我写了一个简单的解析器,只把第三列(说明列)送去翻译,前两列原样保留。如果是 Word 表格,先用pandas读成 DataFrame,对说明列做同样的占位符处理,再写回。
import pandas as pd def translate_table(df, translate_func): """df 三列:参数、类型、说明""" df['说明'] = df['说明'].apply(lambda x: translate_func(str(x))) return df # 示例 data = { '参数': ['pPDU', 'Status'], '类型': ['PDU*', 'unsigned long'], '说明': ['Points to the PDU to be initialized.', 'Return status code.'] } df = pd.DataFrame(data) # 实际调用 DeePL 的 translate_func 这里省略 print(df)这样表格结构不会乱,参数名也不会被翻译。
4. 调用 DeePL 的工程化细节:批量、限流、术语表
4.1 用官方 API 而不是网页版
网页版 DeePL 有字符限制,而且不能自定义术语表。做标准文档翻译,必须用 DeePL API。免费版每月 50 万字符,付费版按量计费。ISO 22900-2 全文大概 20 万字符左右,免费额度够用一轮。调用时注意target_lang设成ZH,source_lang设成EN,并且开启preserve_formatting。
import requests def deepl_translate(text, api_key): url = "https://api.deepl.com/v2/translate" params = { "auth_key": api_key, "text": text, "source_lang": "EN", "target_lang": "ZH", "preserve_formatting": 1 } resp = requests.post(url, data=params) return resp.json()["translations"][0]["text"]注意:DeePL API 对单次请求有长度限制,一般建议每段不超过 5000 字符。我会把文档按段落切分,每段单独请求,避免超长。
4.2 术语表:把 CAN FD、DoIP 锁死
DeePL Pro 支持术语表(Glossary)。你可以上传一个 CSV,指定CAN FD必须翻译成CAN FD,DoIP必须翻译成DoIP,PDU必须翻译成PDU。这样即使不做占位符,也能减少一部分误译。术语表格式:
en,zh CAN FD,CAN FD DoIP,DoIP PDU,PDU M-Type,M-Type上传后拿到 glossary_id,在请求里带上glossary_id参数。注意免费版 API 不支持术语表,这是很多人踩过的坑。
4.3 限流与重试:别把 API 打挂
DeePL API 有速率限制,免费版每秒 1 次请求,付费版更高。批量翻译时一定要加time.sleep(1)或者用指数退避。我一般写一个带重试的封装:
import time def translate_with_retry(text, api_key, max_retry=3): for i in range(max_retry): try: return deepl_translate(text, api_key) except Exception as e: if i == max_retry - 1: raise time.sleep(2 ** i)如果返回 429,说明触发限流,等 2 秒再试。如果返回 456,说明额度用完,得换 key 或充值。
4.4 翻译后还原:占位符、情态动词、表格
翻译完的文本先做占位符还原:
def restore_protected(text, pmap): for key, val in pmap.items(): text = text.replace(key, val) return text再做情态动词反向替换:
def restore_modals(text): text = text.replace('MUST NOT', '不得') text = text.replace('MUST', '必须') text = text.replace('SHOULD NOT', '不应') text = text.replace('SHOULD', '应') return text最后把表格还原成 Markdown 或 Word。整个流程跑完,你拿到的就是一份中英文对照、标识符未被篡改、规范强度保留的译文。
5. 避坑与排查:翻译 D-PDU-API 文档时最容易踩的五个坑
5.1 现象:函数名被翻译成中文,代码无法编译
原因:DeePL 把PDUConstruct当普通单词,翻译成“PDU构造”。
解决:预处理阶段用正则把所有函数名、宏名加入保护列表。如果已经翻译完,用原文和译文做 diff,把被翻译的标识符找出来,手动替换回去。更稳妥的做法是维护一个“标识符白名单”,每次翻译前先扫描。
5.2 现象:shall被翻成“将”,规范强度丢失
原因:DeePL 优先保证语句通顺,忽略了标准文档的情态动词含义。
解决:翻译前把shall替换成MUST,shall not替换成MUST NOT。翻译后再替换回“必须”和“不得”。注意should也要同样处理,否则“应”和“应该”会混。
5.3 现象:表格列错位,参数和说明对不上
原因:DeePL 逐单元格翻译时,Markdown 表格的|被当成普通字符,导致列数变化。
解决:不要直接翻译整个表格。先把表格转成“参数 | 类型 | 说明”三列,只翻译说明列,翻译完再拼回表格。如果是 Word 表格,用python-docx遍历单元格,只处理说明列。
5.4 现象:术语表不生效,CAN FD还是被翻译
原因:免费版 DeePL API 不支持术语表,或者术语表上传后没有在请求里带glossary_id。
解决:确认你的 API 套餐支持术语表。如果用的是免费版,只能靠占位符把CAN FD保护起来。另外术语表的源语言和目标语言必须匹配,en对zh,不能写en-US。
5.5 现象:翻译到一半额度用完,进度丢失
原因:没有做断点续传,翻译结果只存在内存里。
解决:每翻译完一段,就把原文、译文、占位符映射写进一个 JSON 文件。下次启动时先读进度文件,跳过已翻译的段落。我一般用progress.json记录{段落索引: {原文, 译文, pmap}},这样即使中断也能续上。
6. 进阶技巧:用双语对照 + 术语校验做最终质检
翻译完不代表能用。我一般会做一轮“术语一致性校验”:把原文和译文按段落对齐,提取所有保护列表里的标识符,检查它们在译文里是否原样出现。如果某个标识符在译文里消失了,说明还原失败或者被 DeePL 改写了。下面这段代码就是做这个校验的:
def validate_identifiers(original, translated, protected_tokens): missing = [] for token in protected_tokens: if token not in translated: missing.append(token) return missing # 示例 original = "The function PDUConstruct shall initialize the PDU structure." translated = "函数 PDUConstruct 必须初始化 PDU 结构。" protected = ["PDUConstruct", "PDU"] print(validate_identifiers(original, translated, protected))如果输出为空列表,说明所有标识符都保留了。如果有缺失,就回到对应段落手动修复。
另一个技巧是生成“双语对照 Markdown”:原文一段,译文一段,中间用---分隔。这样读的时候可以左右对照,遇到不确定的地方直接看原文。我一般用pandoc把双语 Markdown 转成 Word 或 PDF,方便团队传阅。
最后说一个我自己的习惯:翻译完的标准文档,我会先放两天再读。刚翻完的时候脑子里有原文印象,读译文会觉得“没问题”。放两天后,原文印象淡了,再读译文,那些拗口、歧义、术语不一致的地方就会自己跳出来。这个“后悔药”习惯帮我省了不少返工时间。希望帮到你。
本文还有配套的精品资源,点击获取