
简介这份PDF面向《魔兽争霸》地图编辑器WE的入门与进阶制作者尤其适合使用中文版冰封王座、但在触发器编辑中仍被英文事件与动作选项困扰的玩家。内容以中英对照方式梳理触发器的三大组成事件Events、条件Conditions与动作Actions并逐项解释常见条目如地图初始化、可破坏物体被摧毁、对话按钮点击、时间变化、聊天信息、单位进入或离开区域等事件布尔值、技能、物品、玩家、种族、实数、字符串与单位类型等条件判断以及AI、动画、镜头、电影、计时器、漂浮文字、任务、声音、特效等动作分类。读者可借此快速定位英文选项含义理解触发器执行逻辑减少查词与试错成本为编写自定义地图和游戏模式打基础。压缩包内共1个PDF文件约38KB轻量便于随时查阅目前已有150人学习适合边做图边对照检索。1. 魔兽触发器的英文翻译卡在哪儿地图编辑器里点开触发器编辑器事件、条件、动作三栏全是中文条目用起来很顺。可一旦要去看英文教程、读 JASS 源码、或者在英文社区里描述一个 bug问题就来了你嘴里的「触发单位」「匹配单位」「转换到自定义文本」对面叫 Triggering Unit、Matching Unit、Convert to Custom Text一个都对不上。更麻烦的是很多人手里拿到的是一份 pdf 格式的术语表或者触发器截图文档想查一个词得翻半天想把它变成能搜索、能批量替换的电子表格又无从下手。这篇要解决的就是这条链路先把魔兽触发器Warcraft III Trigger的术语体系拆清楚搞明白中文界面条目和英文关键字、JASS 原生函数之间的映射关系再写脚本把中文触发器配置批量转成英文然后用 pdf 解析把已有的 pdf 文档扒成结构化条目最后重新生成一份中英双向可检索的 pdf 术语表。适合三类人做自定义地图的触发器作者、需要把中文脚本文档交付给英文协作方的人、以及手上有一堆中文 pdf 要转成对照表的工程人员。术语和 JASS 语法部分按魔兽争霸III 世界编辑器World Editor的通行做法讲剩下的解析和生成环节是通用的 Python 工具链。2. 魔兽触发器术语体系与中英对照表的建立翻译触发器名称不是查词典而是做映射。中文界面里的每一条菜单项背后都对应一个英文标识符或者常量找到那个标识符翻译才算落地。2.1 事件、条件、动作三要素的中英对照触发器编辑器把一条触发器拆成三块事件Event负责「什么时候触发」条件Condition负责「要不要执行」动作Action负责「执行什么」。中文界面把这三块翻译得很直白但英文侧还多出一层每个图形化条目在底层都有对应的函数或常量名这一层才是写代码、搜资料时真正用得到的。中文界面条目英文原文JASS 侧对应事件EventTriggerRegister* 系列函数条件Conditionconditionfunc / 条件函数体动作Actionfunction …_Actions takes nothing returns nothing触发单位Triggering UnitGetTriggerUnit()触发玩家Triggering PlayerGetTriggerPlayer()匹配单位Matching UnitGetFilterUnit()选取的单位Picked UnitGetEnumUnit()触发触发器Triggering TriggerGetTriggeringTrigger()计时器TimerCreateTimer()单位组Unit GroupCreateGroup()区域RegionCreateRegion()点PointLocation自定义脚本Custom Scriptcall 开头的裸语句转换到自定义文本Convert to Custom Text无编辑器操作「匹配单位」和「选取的单位」最容易混前者出现在单位组的条件里过滤每个候选单位后者出现在遍历单位组的动作里指当前这一轮迭代到的那个单位。两者在英文界面里就是 Matching Unit 和 Picked Unit中文翻译只差两个字英文侧对应的是完全不同的函数。2.2 JASS 原生函数才是英文翻译的标准答案一份触发器导出成自定义文本之后长这样function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing // 事件的英文常量EVENT_PLAYER_UNIT_DEATH 对应「任意单位死亡」 // GetTriggerUnit() 对应中文界面里的「触发单位」 call KillUnit(GetTriggerUnit()) endfunction function InitTrig_Untitled_Trigger_001 takes nothing returns nothing set gg_trg_Untitled_Trigger_001 CreateTrigger() // TriggerRegisterAnyUnitEventBJ 对应「事件 - 单位 - 任意单位事件」 call TriggerRegisterAnyUnitEventBJ(gg_trg_Untitled_Trigger_001, EVENT_PLAYER_UNIT_DEATH) call TriggerAddCondition(gg_trg_Untitled_Trigger_001, Condition(function Trig_Untitled_Trigger_001_Conditions)) call TriggerAddAction(gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions) endfunction函数名用 PascalCase事件常量用全大写下划线参数名用 camelCase这套命名在 common.j 和 Blizzard.j 里高度一致。做术语表的时候与其对着中文菜单一个个猜英文不如直接把一份导出脚本里的标识符抓出来当基准准确率最高。GUI 变量的命名前缀udg_user-defined global也是硬规则翻译变量名时不能丢。2.3 术语表的字段设计与去重规则术语表用 CSV 存最省事Excel、脚本、pdf 生成工具都能直接吃。字段建议固定成下面这几个别随意加列否则后面的脚本要跟着改。字段含义示例中文界面条目原文触发单位英文英文界面原文Triggering Unit标识符JASS 侧函数或常量GetTriggerUnit类别事件/条件/动作/类型/变量动作-单位可作标识符是否适合直接当变量名否备注易混点与「匹配单位」区分去重按「英文 类别」做唯一键不要按中文去重。中文汉化版本之间存在差异同一个「选取单位」在不同版本里可能对应 Picked Unit 或 Selected Unit只按中文去重会把后面的条目吞掉。同义的中文别名单独放到一列用分号隔开查询时先展开别名再匹配。提示术语表里凡是会出现在 JASS 标识符位置的条目都要额外过一遍关键字检查loop、unit、trigger这些词直接拿来当变量名会出问题。3. 用 Python 批量把中文触发器配置翻成英文有了术语表接下来就是让它跑起来。触发器数据并不是存在单个文本文件里而是散在地图包的 war3map.wtg触发器结构和 war3map.wct自定义文本中直接改这些二进制结构风险很大。3.1 为什么别在触发器编辑器里逐条手改手工改的代价不在改而在复核。一条中型地图的触发器动辄几百条变量上百个逐条点开下拉框改名字改到一半自己都记不住哪些改过。更麻烦的是图形化触发器改完之后再导出函数名会被编辑器按触发器名重新生成一遍之前手动修的英文名可能被覆盖。常见的做法是反过来走先在编辑器里把触发器统一「转换到自定义文本」导出成纯 JASS再在文本层面做替换和翻译。文本层面可版本管理、可 diff、可回滚出问题一眼能看出来。翻译完的脚本如果还要回编辑器就用「导入自定义文本」的方式挂回去或者干脆全程只维护脚本。3.2 术语表驱动的批量替换脚本替换顺序是这套脚本唯一的坑点「单位」如果先被替换成 Unit「单位组」就永远匹配不上了。所以载入术语表时必须按中文长度降序排。import csv import re from pathlib import Path def load_glossary(path): 读取术语表 CSV返回按中文长度降序排列的字典 rows {} # utf-8-sig 用来吃掉 Excel 导出时带的 BOM否则第一列列名会带乱码 with open(path, encodingutf-8-sig, newline) as f: for row in csv.DictReader(f): zh (row.get(中文) or ).strip() en (row.get(英文) or ).strip() if not zh or not en: continue rows[zh] en # 长词优先避免「单位」先命中把「单位组」切碎 return dict(sorted(rows.items(), keylambda kv: -len(kv[0]))) def translate_fragment(text, glossary): for zh, en in glossary.items(): if zh in text: text text.replace(zh, en) return text if __name__ __main__: glossary load_glossary(glossary.csv) src_path Path(trigger_zh.j) src src_path.read_text(encodingutf-8) # 只翻注释行函数体和标识符交给术语表单独维护 out re.sub(r//[^\n]*, lambda m: translate_fragment(m.group(0), glossary), src) Path(trigger_en.j).write_text(out, encodingutf-8) print(替换条目数, sum(1 for k in glossary if k in src))csv.DictReader按列名取值列顺序变了也不影响sorted(..., keylambda kv: -len(kv[0]))是把中文键从长到短排保证「触发单位」先于「单位」被替换re.sub的回调写法让每条注释单独走一遍术语表避免整篇文本一次性替换后无法定位改了什么。最后的计数打印是给自己看的条目数明显偏少说明术语表覆盖不全或者编码没读对。3.3 翻译后的语法校验与命名冲突排查脚本替换只解决文字不解决合法性。JASS 的标识符大小写在多数工具链里不敏感但 vJass 编译器和一些第三方编辑器插件对大小写是有要求的统一成小驼峰最省心。中文直译直接当变量名的风险建议写法触发与类型名 trigger 冲突trg_ / TriggerRef单位与类型名 unit 冲突u / UnitRef条件与 conditionfunc 语义重叠cond_ / CondRef循环loop 是语言关键字loopIdx / i玩家player 是类型名p / PlayerRefGUI 自动生成的变量带udg_前缀自定义变量建议换成自己的前缀比如mt_map trigger这样一眼能区分哪些是编辑器托管的、哪些是自己写的。替换完跑一遍语法检查最直接的办法是丢回世界编辑器的自定义文本里试导入导入报错会带行号照着行号看基本就是某个词被替成了关键字。4. 从触发器术语 pdf 里把中英条目捞干净不少人手上是一份别人整理好的 pdf 术语表或者 pdf 文档里夹着触发器对照表。想复用就得先做 pdf 解析把像素和字形还原成一行行文本。4.1 中文 pdf 抽出来的文本为什么是散的复制粘贴一个中文 pdf 的表格常见三种翻车英文单词中间被插入空格Trig ger Unit、中英文顺序错乱、跨页表格第一行跑到页尾。根因是 pdf 里存的不是「段落」而是一堆带坐标的字形绘制指令阅读顺序得靠工具去猜。中文 pdf 还多一层麻烦——字形子集如果没有正确的 Unicode 映射抽出来就是空白或者方框。所以判断一份 pdf 能不能解析第一步不是写代码是先手动复制两行看结果。复制出来是散的但有字说明有文本层可以解析复制出来是空的说明是扫描件得先走 OCR。这一步能省掉后面一半的调试时间。4.2 pdfplumber 提取表格与文本行import pdfplumber def extract_rows(pdf_path, use_text_strategyFalse): 逐页提取表格行返回 [页码, 列1, 列2, ...] 的列表 rows [] # 没有可见表格线时靠文字位置聚类成列比按线切更稳 settings { vertical_strategy: text, horizontal_strategy: text, snap_tolerance: 3, # 坐标差 3 点以内算同一列/行 join_tolerance: 3, intersection_tolerance: 5, } if use_text_strategy else {} with pdfplumber.open(pdf_path) as pdf: for page_no, page in enumerate(pdf.pages, start1): tables page.extract_tables(table_settingssettings) if not tables: # 退化路径整页按文本行切用 x 坐标差聚类成两列 words page.extract_words(use_text_flowFalse, keep_blank_charsFalse) tables [[[w[text] for w in words]]] for table in tables: for row in table: cells [(c or ).replace(\n, ).strip() for c in row] if any(cells): rows.append([str(page_no)] cells) return rowsvertical_strategy和horizontal_strategy是这套参数里最关键的两个文档里表格有框线就用默认的lines只有浅色底纹或者干脆没线就用text。snap_tolerance控制「差多少个点算同一行」中文 pdf 里同一行的中英文字基线经常差一两个点调大到 3 到 5 才拉得齐调太大会把相邻两行粘在一起。extract_words那条退化路径是兜底用的遇到那种整页通栏排版、根本没有表格结构的文档就按词切出来自己拼。4.3 跨页表格合并与页码噪声清理抽出来的原始行里通常混着页码、页眉、目录点线跨页表格还会把表头重复一遍。清理分三步去噪声、并跨页、去重。import re PAGE_NO re.compile(r^\s*[-—]?\s*\d\s*[-—]?\s*$) DOTS re.compile(r[.·]{3,}) def clean_rows(rows, header_keywords(中文, 英文, 术语)): cleaned [] for row in rows: cells [] for c in row[1:]: # row[0] 是页码不参与判定 c DOTS.sub(, c).strip() if not c or PAGE_NO.match(c): continue cells.append(c) if len(cells) 2: continue # 只有一列的多半是页眉页脚 # 表头行按关键词识别识别到就丢掉避免跨页时重复出现 if any(k in .join(cells) for k in header_keywords): continue cleaned.append(cells) # 依据前两列去重保留第一次出现的顺序 seen, out set(), [] for cells in cleaned: key tuple(cells[:2]) if key in seen: continue seen.add(key) out.append(cells) return outPAGE_NO用fullmatch语义匹配整格内容避免把正常的数字条目比如某个 ID误删DOTS专门收拾目录那一串点去重只按前两列是因为有些术语表第三列是备注同一个中英对可能有多条备注全列去重会把有效信息删掉。清理完把行数打出来和手动数的对比一下差得太多就回去看snap_tolerance是不是设歪了。注意术语表这类文档经常中英分栏排布左栏中文、右栏英文如果解析出来中英混在同一行先用page.crop()按 x 坐标把页面切成左右两半再分别提取比事后拆分省事得多。5. 生成可检索的双语触发器 pdf字体、排版与回读校验条目捞干净了最后一步是把它变成一份能搜索、能复制、中英混排不出豆腐块的 pdf。5.1 中文 pdf 生成前必须做的字体注册用 reportlab 生成中文 pdf第一件事是注册字体不注册出来的全是黑方块。CJK 字体很多是.ttc集合文件直接传给 TTFont 会报错得指定subfontIndex。from fontTools.ttLib import TTCollection # 先列出 ttc 里每个子字体找到简体中文那一个的序号 ttc TTCollection(/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc) for i, font in enumerate(ttc.fonts): print(i, font[name].getDebugName(4)) # 4 号 name 记录是完整字体名拿到序号之后再注册subfontIndex填错的表现是汉字能出来但字形是日文或韩文变体肉眼能看出来别忽略。from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont pdfmetrics.registerFont( TTFont(NotoSC, /usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc, subfontIndex2) )5.2 双语对照表的表格排版参数表格里如果直接塞长字符串reportlab 不会自动折行会直接溢出页面。单元格内容用 Paragraph 包一层再把字体通过 TableStyle 的FONTNAME指定成刚注册的中文字体repeatRows1让表头在每页重复出现。参数建议值作用colWidths按 A4 可用宽度 500pt 分配中文列 160、英文列 160、备注 180repeatRows1每页重复表头FONTNAME (0,0),(-1,-1)NotoSC全表统一中文字体避免替换字形VALIGNMIDDLE中英行高不一致时上下居中生成之后还要设文档元数据setTitle、setSubject、setKeywords里把「魔兽触发器 中英对照 术语表」写进去这样在系统的 pdf 阅读器里按关键词搜索文件名时也能命中。字体如果做子集化要注意子集是按用到的字符生成的后期如果用 pdf 编辑器追加文字追加部分可能缺字形。5.3 用 pdftotext 回读校验条目完整性生成完别急着交付抽回来比一遍是最省事的验证。文本层完整的 pdfpdftotext抽出来的条目数应该和源数据一致。# 抽回文本并统计英文侧特征词的出现次数 pdftotext -enc UTF-8 -layout glossary.pdf - | grep -c Trigger # 抓出被拆断的英文单词中间带空格的驼峰词这类基本都是排版折行导致 pdftotext -enc UTF-8 -layout glossary.pdf - | grep -nE [A-Za-z] [a-z][A-Z][a-z]第一条命令的数如果明显小于源数据条数多半是某些页走了图片或者字体子集缺字形第二条命中的行如果是正常的「Trigger Editor」这类词组可以忽略如果是Trig ger Unit这种被硬拆开的回去看是不是列宽太窄触发了强制换行。把这两条命令串进生成脚本的末尾当自检比每次人工翻页靠谱得多。本文还有配套的精品资源点击获取