ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Freerouting 国际化翻译指南:LLM 驱动的 i18n 流水线、术语词表与多语言维护实践

Freerouting 国际化翻译指南:LLM 驱动的 i18n 流水线、术语词表与多语言维护实践
  • 硬件开发
  • 桌面应用

【免费下载链接】freerouting

Advanced PCB auto-router

项目地址:https://gitcode.com/gh_mirrors/fr/freerouting
点击查看免费下载

本文是 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 修复错误翻译的三步流程

  1. 先识别 PCB 或 UI 概念(例如 clearance、shove fixed、net class),而不是只盯着一处菜单文案;
  2. 只编辑语言词表:scripts/i18n/glossary/{locale}.json。
    • 词条值必须以用户应看到的本地化术语开头(不要把英文嵌在值里);
    • 当这些词出现在 UI 文本中时,保持拉丁字母书写:DSN、SES、Specctra、Freerouting、Andras Fuchs;
    • 如果术语缺失,先在_default.json中补上同一键,再为每个{locale}.json补上(参见 scripts/i18n/README.md#glossaries);
  3. 提交 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)

角色规范写法不要使用
引擎Autorouterauto-router, Auto-router
动词/按钮Autoroute把 Autorouting 当动词
流水线阶段Auto-routingAutorouting, Post-routing
优化引擎OptimizerPostroute, Post-router
优化阶段Optimizationpost-route pass

3.2 领域术语(Domain terms)

角色规范写法UI 中不要使用
飞线指标Incomplete connectionsUnrouted Connections(作为标签)
状态动词remain unrouted—(仅允许出现在句子里)
内部保存.frb.bin
设计导入 / Save AsSpecctra design file (.dsn)把 .frb 当作开放格式
Specctra 导出Specctra session file (.ses)把 session script 说成 .scr
Fusion 导出Autodesk Fusion Script (.scr)EAGLE session script
放置禁布Component keepoutplace keepout
孤立布线Unconnected traces and viasDangling copper, Unconnected Routes
短线残铜Route stubsDangling copper
铜区模型Conduction areacopper pour(词表 KiCad 别名除外)
已布铜走线Tracetrack(词表 KiCad 别名除外)
飞线图形Air wireair 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_MODELgemini-3.7-flashGemini 模型 ID(用于generateContent)
LLM_BASE_URLhttps://generativelanguage.googleapis.com/v1betaGemini REST 基础地址(仅测试时覆盖)
LLM_GEMINI_THINKING_LEVELminimal仅 Gemini 3.x:minimal/low/medium/high
LLM_GEMINI_THINKING_BUDGET0Gemini 2.5 及更早:思考 token 预算(0=关;-1/default=模型默认)
LLM_BATCH_SIZE15每次 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-icontext 目录(默认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_roletooltip、button_label、dialog_title、error_message等
grammatical_roleverb_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.EnglishPropertiesParityTest

EnglishPropertiesParityTest 是这套纪律的核心测试,产出 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

项目地址:https://gitcode.com/gh_mirrors/fr/freerouting
点击查看免费下载

相关推荐

上一篇:ReClip高清视频怎么选:4K/1080p/720p选择指南与体积对比全解
下一篇:10个终极JavaScript技巧:从入门到精通的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进