- 硬件开发
- 桌面应用
【免费下载链接】freerouting
Advanced PCB auto-router
本文是 Freerouting 开源自动布线器的官方翻译工作流指南,完整讲解其基于 LLM(Gemini)的国际化翻译流水线:为什么*_{locale}.properties是构建产物而非修改对象、如何通过编辑术语词表(glossary)修正错误翻译、如何维护英文源术语标准,以及维护者如何执行整语言重译。读完本文,你将能够以合规的方式提交翻译修复、运行上下文提取/增量翻译/校验命令,并理解底层源码(scripts/i18n/ 目录与 i18n 测试用例)的实现原理。
一、翻译工作流概览:为什么.properties是构建产物
Freerouting 的 UI 字符串以 Java.properties资源包的形式存放在src/main/resources/app/freerouting/下,包括顶层公共包Common_*.properties、Freerouting_*.properties、drc/AirLine_*.properties,以及gui/下按菜单、窗口、交互状态划分的 40 余个 bundle(如gui/menus/BoardMenuFile_*.properties、gui/windows/routing/WindowNetClasses_*.properties)。
这些字符串并非手工翻译维护,而是由 scripts/i18n/ 下的 Python 流水线调用 LLM 从英文源生成:
- 英文源字符串(
*_en.properties)由开发者维护(文案审校、新增键、占位符修复); - 各语言 locale 文件(
*_{locale}.properties)是流水线构建输出,不是修词的首选位置。
流水线的代码布局(见 scripts/i18n/README.md)按"三层"组织:
| 脚本 | 职责 |
|---|---|
extract-context.py | 第 1 层:扫描英文.properties与 Java 源码,生成context/元数据 |
translate.py | 第 2 层:基于上下文增强提示词的 LLM 批量/增量翻译 |
validate.py | 第 3 层:键覆盖(parity)、占位符、HTML、转义校验 |
prune-unused-keys.py | 清理所有 locale 中已不被 Java 引用的键 |
properties_io.py/context_store.py/java_scanner.py/llm_client.py/prompt_builder.py/i18n_output.py | 共享的.properties读写、上下文存取、TextManager.getText()扫描、LLM 调用(重试/退避)、提示词构建、Windows 安全输出等支撑模块 |
参与角色分工明确:译者/审校者负责修词表并申请整语言重译;维护者负责运行流水线命令、提交再生成的 locale 文件。
二、译者和审校者:修词的正确姿势
2.1 禁止直接编辑 locale.properties文件
请勿手工修改诸如Common_de.properties、gui/BoardMenuFile_ar.properties等src/main/resources/app/freerouting/下的*_{locale}.properties文件。直接编辑被明确反对,原因有四:
- 下一次该语言运行流水线时会被整体覆盖;
- 修好一个字符串,但同一 PCB 术语在别处仍是错的(例如只修了某个对话框里的 clearance,工具栏、Common 键、错误消息里依然是旧译法);
- 绕过词表一致性检查(glossary consistency checks);
- 让维护者难以判断哪些键仍需重新生成。
唯一例外:英文源字符串*_en.properties由开发者维护(文案审校、新增键、占位符修复)。译者通常不编辑英文,除非他们同时也在改进源文案。
2.2 修复错误翻译的三步流程
- 先识别 PCB 或 UI 概念(例如 clearance、shove fixed、net class),而不是只盯着一处菜单文案;
- 只编辑语言词表:
scripts/i18n/glossary/{locale}.json。- 词条值必须以用户应看到的本地化术语开头(不要把英文嵌在值里);
- 当这些词出现在 UI 文本中时,保持拉丁字母书写:DSN、SES、Specctra、Freerouting、Andras Fuchs;
- 如果术语缺失,先在
_default.json中补上同一键,再为每个{locale}.json补上(参见 scripts/i18n/README.md#glossaries);
- 提交 Pull Request 或 Issue,内容必须包含:
- 词表修改(必需);
- 针对整个语言的重译请求(该语言所有
*_{locale}.properties); - 示例 Issue 标题:
i18n: re-translate de after glossary fix (clearance terms); - 简要说明哪里错了、词表中改了什么。
除非维护者明确要求热修复,否则不要提交只修补个别*_{locale}.properties行的 PR。
2.3 为什么必须整语言重译?
词表条目驱动每一个提及该术语的字符串。如果在某个对话框里修好clearance,而工具栏、Common 键、错误消息里仍是旧译,界面就会变成"新旧混排"。重新生成整个语言,才能让词表一致地应用到全部字符串上。
从实现看,词表是通过 scripts/i18n/glossary.py 注入 LLM 提示词的:glossary_prompt_lines(locale)把_default.json与{locale}.json合并后,逐行生成'term' → 本地化释义的约束文本,由 prompt_builder.py 追加到单条、批量与分段三种提示词模板中,并要求"英文键只是查找标签,必须使用右侧的本地化形式、在本批所有字符串中保持一致"。这就是词表能够"驱动一切字符串"的底层机制。
三、英文源术语标准(source language)
英文 UI 文案与词表遵循单一规范术语标准。修改英文字符串的译者与贡献者必须遵守以下约定(表格中左侧为唯一允许形式,右侧为禁止形式):
3.1 功能名称(Feature names)
| 角色 | 规范写法 | 不要使用 |
|---|---|---|
| 引擎 | Autorouter | auto-router, Auto-router |
| 动词/按钮 | Autoroute | 把 Autorouting 当动词 |
| 流水线阶段 | Auto-routing | Autorouting, Post-routing |
| 优化引擎 | Optimizer | Postroute, Post-router |
| 优化阶段 | Optimization | post-route pass |
3.2 领域术语(Domain terms)
| 角色 | 规范写法 | UI 中不要使用 |
|---|---|---|
| 飞线指标 | Incomplete connections | Unrouted Connections(作为标签) |
| 状态动词 | remain unrouted | —(仅允许出现在句子里) |
| 内部保存 | .frb | .bin |
| 设计导入 / Save As | Specctra design file (.dsn) | 把 .frb 当作开放格式 |
| Specctra 导出 | Specctra session file (.ses) | 把 session script 说成 .scr |
| Fusion 导出 | Autodesk Fusion Script (.scr) | EAGLE session script |
| 放置禁布 | Component keepout | place keepout |
| 孤立布线 | Unconnected traces and vias | Dangling copper, Unconnected Routes |
| 短线残铜 | Route stubs | Dangling copper |
| 铜区模型 | Conduction area | copper pour(词表 KiCad 别名除外) |
| 已布铜走线 | Trace | track(词表 KiCad 别名除外) |
| 飞线图形 | Air wire | air line(实现名AirLine保持不变) |
3.3 核心术语规则
- Autorouter / Auto-routing / Autoroute:批量引擎用Autorouter,动作/动词用Autoroute,流水线阶段用Auto-routing。窗口标题使用 Title Case(如
Auto-routing Completed)。在句中,Autorouter与Optimizer作为正式功能名保持大写; - Incomplete connections vs remain unrouted:标签、指标和评分汇总用incomplete connections;动词形式remain unrouted仅允许出现在描述性句子中(例如
Autoroute completed; X connections remain unrouted.); - 文件格式:Freerouting 内部板图快照用.frb(绝不用
.bin);Specctra 交换设计文件用.dsn;会话文件用.ses;Autodesk Fusion 脚本用.scr。绝不要把.scr称为 EAGLE 脚本或 session script; - 禁布区:面向用户的 UI 元素必须用Component keepout(绝不用
place keepout);place keepout仅保留为词表和文件解析器中的 Specctra 文法别名(scripts/i18n/glossary/_default.json 中即有该别名说明); - 风格与拼写:统一美式英语;产品名恒为大写Freerouting;普通 UI 标签使用push-and-shove、rip-up与 sentence case。
词表术语正是从*_en.properties和 Java UI 字符串中挖掘出来的(autorouter、net class、conduction area、push/shove、Specctra DSN/SES 等),_default.json目前收录约 90 个 Freerouting/Specctra 术语。以 scripts/i18n/glossary/zh.json 为例,词条采用"本地化术语在前、英文说明在后"的风格:
"component keepout": "元件禁布区(禁止放置元件的区域;界面用语。Specctra 文法称 place keepout)", "trace": "走线(单层铜导体。Freerouting 界面用语;KiCad 别名为 track)", "clearance": "间距(铜或机械特征之间的最小距离)"词表校验逻辑位于 scripts/i18n/glossary.py:validate_glossaries()会检查GLOSSARY_LOCALES列表中的每个{locale}.json是否存在、且覆盖_default.json的全部术语键,缺失即报错;validate.py会调用该函数。
四、维护者:运行整语言重译
当贡献者更新了scripts/i18n/glossary/{locale}.json并请求刷新该语言时,维护者执行如下命令序列(仓库根目录下,Windows PowerShell):
# Navigate to the repository root pip install -r scripts/i18n/requirements.txt $env:GEMINI_API_KEY = "AQ...." # API key for the translation model $env:LLM_MODEL = "gemini-3.6-flash" # optional; default is gemini-3.6-flash $locale = "de" # target locale # Full overwrite for that locale Get-ChildItem -Path "src/main/resources/app/freerouting" -Recurse -Filter "*_$locale.properties" | Remove-Item python scripts/i18n/extract-context.py python scripts/i18n/translate.py --locale $locale python scripts/i18n/extract-context.py --sync-translated --locale $locale python scripts/i18n/validate.py --locale $locale -v ./gradlew test --tests app.freerouting.i18n.*提交时需包含:再生成的*_{locale}.properties、更新的词表,以及(如有变化)scripts/i18n/context/。
不做全量删除的增量刷新(仅当键被标记为 stale 时):
python scripts/i18n/translate.py --locale $locale --missing-only注意:仅改词表不会自动标记键为 stale,因此优先采用上面的整语言再生成流程。
4.1 模型与环境变量配置
LLM 翻译依赖 Gemini REST 端点,当前完整配置项(见 scripts/i18n/README.md):
| 变量 | 默认值 | 说明 |
|---|---|---|
GEMINI_API_KEY | (必填) | Google AI Studio API 密钥(AQ.…或旧版AIza…);GOOGLE_API_KEY是别名 |
LLM_MODEL | gemini-3.7-flash | Gemini 模型 ID(用于generateContent) |
LLM_BASE_URL | https://generativelanguage.googleapis.com/v1beta | Gemini REST 基础地址(仅测试时覆盖) |
LLM_GEMINI_THINKING_LEVEL | minimal | 仅 Gemini 3.x:minimal/low/medium/high |
LLM_GEMINI_THINKING_BUDGET | 0 | Gemini 2.5 及更早:思考 token 预算(0=关;-1/default=模型默认) |
LLM_BATCH_SIZE | 15 | 每次 Gemini 请求的键数(1–25) |
说明:翻译指南正文中的示例以
gemini-3.6-flash为默认模型,而 scripts/i18n/README.md 的当前默认值已更新为gemini-3.7-flash;两处均正确反映了各自文档撰写时的配置,运行前请以 README 为准。
Google AI Studio 现已签发带AQ.前缀的 auth key(取代旧版AIza…密钥),通过GEMINI_API_KEY传入;客户端在原生 Gemini REST 端点的x-goog-api-key头中发送该密钥。设置环境变量后需重启终端(或 Cursor),Python 子进程才能继承它。
4.2translate.py命令行参数(源码级)
从 scripts/i18n/translate.py 的argparse定义可见:
| 参数 | 简写 | 作用 |
|---|---|---|
--locale | -l | 目标语言代码(如de、fr) |
--all | -a | 翻译所有支持的语言 |
--input | -i | context 目录(默认scripts/i18n/context) |
--dry-run | -n | 预览模式,不调用 LLM、不写文件 |
--missing-only | -m | 只翻译缺失或 stale 的键(推荐) |
--bundle | -b | 限定一个或多个 bundle(如gui.BoardMenuFile,可重复) |
--exclude-locale | -x | 配合--all跳过某些语言(可重复) |
典型用法(bash):
pip install -r scripts/i18n/requirements.txt export GEMINI_API_KEY=... python scripts/i18n/extract-context.py python scripts/i18n/translate.py --locale de --missing-only python scripts/i18n/validate.py --locale de ./gradlew test --tests app.freerouting.i18n.EnglishPropertiesParityTest其他常用变体:单 bundle 开发调试--locale de --bundle gui.BoardMenuFile --missing-only;新语言一次性全量引导--locale pt;批量除某语言外全译--all --exclude-locale ar;全量翻译后同步标志extract-context.py --sync-translated --all。
五、流水线三层架构:上下文提取、翻译、校验
5.1 第 1 层:extract-context.py
对每个 bundle 生成一份 JSON(scripts/i18n/context/ 下约 44 个文件,如Common.json、gui.menus.BoardMenuFile.json、gui.windows.routing.WindowNetClasses.json),字段含义:
| 字段 | 用途 |
|---|---|
english_hash | 英文值的 SHA-256(变更检测) |
needs_retranslation | 英文自上次提交后变化时为true |
ui_role | tooltip、button_label、dialog_title、error_message等 |
grammatical_role | verb_phrase、noun_phrase、full_sentence、fragment |
placeholders/has_placeholders | %s、{{name}}等占位符 |
is_html | 是否必须保留 HTML |
related_keys | 同前缀键(如cancel_and_exit与cancel_and_exit_tooltip) |
code_references | 引用该键的 Java 类(来自源码扫描) |
java_class/bundle_desc/max_length_hint | 所属类、bundle 描述与长度提示(实际 JSON 中可见) |
它同时扫描 Java 源码中的TextManager.getText("key")调用(scripts/i18n/java_scanner.py 负责)。context JSON 以确定性顺序写入(属性键排序、列表字段排序、sort_keys稳定元数据顺序),保证 git diff 只显示真正变化的行;且不存储英文值本身,只存变更标志。CI 中通过python scripts/i18n/extract-context.py --check校验已提交的 context 与英文源一致(无需 API 密钥)。
5.2 第 2 层:translate.py
- 批量模式:键按批次发给 Gemini(默认每批 15 个,设
LLM_BATCH_SIZE=1可强制逐键);批解析失败会回退为单键调用并带重试/退避(scripts/i18n/llm_client.py); - stale 键:当
needs_retranslation置位时,旧译文会作为"过时提示"加入提示词; - 图标键:
{{icon:…}}形式的键永不翻译; - 成功清标:翻译成功后清除
needs_retranslation标志;LLM/校验失败时进程以非零退出码结束,便于 CI 或脚本捕获。
5.3 第 3 层:validate.py
针对每个 locale 逐 bundle 检查(scripts/i18n/validate.py):
- 键覆盖:locale 缺失英文键时报
missing; - 占位符:比对英文与译文的占位符集合,缺/多均告警(
PLACEHOLDER_RE匹配%s、{{name}}等); - HTML 保持:
trace_hover_info、pin_hover_info、via_hover_info、net_hover_info等键必须保留 HTML; - 转义校验:检查
.properties的 Java 转义序列(validate_property_escapes); - LLM 包装残留:检测模型输出中的包装痕迹(
find_llm_wrapper_artifacts); - 词表校验:调用
validate_glossaries()保证每个GLOSSARY_LOCALES文件齐全且覆盖_default.json全部术语; - 内置
text_manager_fallback_class_probe/text_manager_fallback_common_probe探针键参与校验,但用于运行时回退测试(见下文),不计入缺失。
5.4 清理未用键:prune-unused-keys.py 与 parity 测试
当 Java 重构删除了 UI 字符串(菜单调整、窗口移除等)时,需从所有locale 文件与 context 元数据中清理失效键:
# 1. 检测未用键(写 build/reports/i18n/EnglishBundlesContainUnusedKeysReport.*) ./gradlew test --tests app.freerouting.i18n.EnglishPropertiesParityTest.englishBundlesDoNotContainUnusedKeys # 2. 预览将删除的键 python scripts/i18n/prune-unused-keys.py # 3. 执行删除 + 刷新 context python scripts/i18n/prune-unused-keys.py --apply python scripts/i18n/extract-context.py ./gradlew test --tests app.freerouting.i18n.EnglishPropertiesParityTestEnglishPropertiesParityTest 是这套纪律的核心测试,产出 4 份报告:源码键缺失于英文包、locale 包未覆盖英文键、locale 中存在但英文缺失的键、英文包中未被 Java 引用的键。它通过正则扫描new TextManager(...)、tm.getText("...")、setText、SegmentedButtons、动态枚举键(.values())等用法来建立"bundle → 使用键"映射,并含 bundle 别名与子类继承映射(如WindowNets继承WindowObjectList)。注意:未用键测试不会让 CI 失败,只是写报告并告警——因为扫描器会漏掉继承 bundle 与动态枚举键,盲目--apply可能误删仍在使用的字符串,请先人工审阅报告。
六、运行时回退机制与测试佐证
Locale 文件缺失时,UI 不会崩:Freerouting 的TextManager(app.freerouting.util)实现了多级回退。测试 TextManagerFallbackTest 验证了:
- 类 bundle 缺键时回退到English 类 bundle(
InteractiveState的text_manager_fallback_class_probe); - 子类缺键时回退到父类 locale bundle(阿拉伯语
WindowClearanceViolations的filter解析为تصفية:); - 类 bundle 缺键时回退到English Common bundle(
text_manager_fallback_common_probe); - locale 键存在时确实返回译文(
autorouter_started中英文不同); - camelCase 键可从 snake_case 属性条目解析(如
listEmptyMessage→No clearance violations found.); - 意大利语
it-IT可解析Annulla (Esc)。
仓库还包含 HungarianResourceParityCheckTest 等其他 i18n 测试,共同构成"翻译质量 + 运行时回退"的双重保障。
七、推荐执行时机与 CI 纪律
| 触发场景 | 应执行的操作 |
|---|---|
英文*_en.properties变化 | extract-context.py→ 提交context/ |
| Java 重构删除了 UI 字符串 | parity 测试 →prune-unused-keys.py --apply→extract-context.py |
| 补语言缺口 | translate.py --locale xx --missing-only |
| 合并翻译 PR 前 | validate.py --locale xx |
| 新语言(一次性) | 全量translate.py --locale xx,之后用--missing-only |
| 发版卫生 | validate.py --all |
| 词表术语修复(译者) | 编辑glossary/{locale}.json→ 申请整语言重跑 |
| 每个 PR(CI) | extract-context.py --check(无需 LLM、无需 API 密钥) |
增量保证:
--missing-only跳过已有 locale 值且未被标记needs_retranslation的键;extract-context.py通过与已提交context/快照比对来设置needs_retranslation;translate.py翻译成功后清除该标志,LLM/校验失败时非零退出;- 图标键
{{icon:…}}永不翻译。
不要做:
- 没有英文变更时按计划任务跑
translate.py --all --missing-only; - 编辑英文后跳过
extract-context.py; - 在 CI 里跑 LLM 翻译(CI 只用
--check与validate.py); - 手工编辑
*_{locale}.properties修翻译(参见本文第二节)。
八、支持的语言与词表文件
源语言(source):en
目标语言(targets):ar,bn,ca,cs,da,de,el,es,fi,fr,he,hi,hr,hu,id,it,ja,ko,lt,nb,nl,pl,pt,pt_br,ro,ru,sk,sl,sv,th,tr,uk,vi,zh,zh_tw(共 35 个,另有英文en词表用于回退与规范化)。
词表目录 scripts/i18n/glossary/ 中每个语言一个 JSON(_default.json之外的ar.json、de.json、zh.json、zh_tw.json等)。其中部分语言仅有词表(为即将开展的新翻译做准备),validate.py会校验GLOSSARY_LOCALES中列出的每个文件都存在且覆盖_default.json的全部术语。引入新的 PCB 术语时,同样遵循"先扩展_default.json,再给每个{locale}.json补同一键"的规则。
词表值风格:每个 locale 词条应以本地化 UI 术语开头(即用户应看到的文本);英文词表键只是查找标签。当DSN、SES、Specctra、Freerouting、Andras Fuchs出现在 UI 文本中时要保持拉丁字母;不要在非英文词表值里嵌入英文 UI 词(如clearance、shove fixed),否则会导致 LLM 原样照抄而不翻译。
九、相关文档
| 文档 | 受众 |
|---|---|
| scripts/i18n/README.md | 流水线安装、LLM 配置、校验 |
| docs/developer.md#translations-i18n | 英文文案修改后的开发者工作流 |
开发者侧的工作流与本文互补:docs/developer.md 给出了编辑英文后的典型命令序列(extract-context.py→translate.py --locale de --missing-only→validate.py→EnglishPropertiesParityTest),并同样强调"译者见 docs/translations.md、不要手工改 locale 文件、修词表并申请整语言重译";CI 在 PR 上运行extract-context.py --check以保证已提交的 context 元数据与英文源一致。将本文的修词流程、术语标准与 scripts/i18n/README.md 的流水线细节配合使用,即可完整覆盖 Freerouting 从英文源到 35 种目标语言的全部翻译生命周期。
- 硬件开发
- 桌面应用
【免费下载链接】freerouting
Advanced PCB auto-router
相关推荐
OpenCode 泰语(th)翻译词汇表:LLM 驱动国际化流水线中的术语治理规范
OpenCode 泰语(th)翻译词汇表:LLM 驱动国际化流水线中的术语治理规范 本文以 OpenCode 仓库中的泰语 locale 词汇表 th.md h
人工智能AI 应用AI Agent代码智能体CLI开发者工具QuickRecorder 快速上手:macOS 轻量录屏工具,三步录出系统声音
QuickRecorder 快速上手:macOS 轻量录屏工具,三步录出系统声音 QuickRecorder 是基于系统 ScreenCapture Kit 的
桌面应用音视频屏幕录制SparkyFitness 多语言翻译架构指南:Weblate 驱动的五组件 i18n 流水线
SparkyFitness 多语言翻译架构指南:Weblate 驱动的五组件 i18n 流水线 本文是 SparkyFitness 项目(Web 前端、Reac
后端前端移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考