Umi-OCR 国际化翻译全流程实战:lupdate 提取、Linguist 翻译与 lrelease 编译
本篇指南完整拆解 Umi-OCR 的 Qt/QML 界面本地化(i18n)工作流:从克隆仓库、用 lupdate 提取待翻译字符串、在 linguist 中逐条翻译,到用 lrelease 编译出 .qm 二进制翻译包并放回工程目录,最后验证与提交贡献。读完本文,你可以独立为 Umi-OCR 翻译一门新语言,也能理解翻译文件是如何被程序加载、以及字体缩放系数如何适配不同语言文字长度的。
准备工作:环境、目录与语言标识符体系
环境要求与仓库准备
整个翻译流程依赖 Qt 官方工具(lupdate.exe、linguist.exe、lrelease.exe,均已随仓库放在 dev-tools/i18n 目录中,并附带 Qt5Core.dll 等运行库),因此要求 Windows 系统。
先 fork 或 clone 仓库。官方强烈建议只 clone 主分支,因为某些分支含体积很大的二进制库(如 OCR 引擎模型),全量下载会花费很长时间:
git clone --branch main --single-branch https://gitcode.com/GitHub_Trending/um/Umi-OCR
后文所有命令如无特别说明,都在工作目录 dev-tools/i18n 下执行。例如按 Win+R 输入 cmd 打开命令行后,跳转到工作目录(假设工程放在 D:\Projects\):
cd /d D:\Projects\Umi-OCR\dev-tools\i18n
注:早期文档中的工程目录名为
Umi-OCR_v2,当前仓库中对应的数据目录为UmiOCR-data,下文均以当前仓库实际路径为准。
语言标识符表
本文假设目标语言为英语 en_US,若翻译其他语言,请将下文所有 en_US 替换为对应标识符。翻译流程最初支持的标识符全集如下:
| 标识符 | 语言 |
|---|---|
zh_CN |
简体中文 |
zh_TW |
繁體中文 |
en_US |
English |
es_ES |
Español |
fr_FR |
Français |
de_DE |
Deutsch |
ja_JP |
日本語 |
ko_KR |
한국어 |
ru_RU |
Русский |
pt_BR |
Português |
it_IT |
Italiano |
对于语种相同但地区不同的语言(如 zh_HK、en_GB、en_CA、es_MX、fr_CA、de_AT、de_CH、pt_PT),程序会应用最接近的翻译文件。这一映射关系就定义在 UmiOCR-data/py_src/utils/i18n_configs.py 的 LanguageCodes 字典中(L16-L43):每个语种组里只有第一个语言代码是有效的(对应一个 .qm 翻译文件),其余代码都映射到它,例如 zh_HK → zh_TW、en_CA → en_US。
从源码结构看,当前 LanguageCodes 中已启用的语言为 zh_CN(含 zh)、zh_TW(含 zh_HK/zh_MO/zh_SG)、en_US(含 en/en_GB/en_AU/en_CA)、ja_JP、ru_RU(含 ru)、pt(含 pt_BR/pt_PT)、ta(含 ta_TA);而 ko_KR、fr_FR、it_IT、de_DE、es_ES、nb_NO 等仍处在“暂未启用”的注释块中(L45-L65)。因此,如果想添加一个不属于上述任何语种的翻译,需要在该源码文件中添加对应的标识符映射,或者寻求项目作者的帮助。
总体流程:三步完成一门语言翻译
Qt-Qml 框架的翻译工作流固定为 3 步(以翻译为英语 en_US 为例):
- 提取:从源代码中提取所有待翻译字符串,生成
en_US.ts工程文件; - 翻译:编辑
en_US.ts,把其中的文本逐条翻译成目标语言; - 编译:把写好的
en_US.ts编译为en_US.qm二进制文件。
完成上述工作后,将 en_US.qm 放入 Umi-OCR,即可在全局设置中把语言切换为 English。
翻译文件最终由 Python 侧的 _I18n 类加载:i18n_configs.py 中,init() 会创建 QTranslator 实例并调用 installTranslator 安装;而 _getLangPath()(L107-L143)会扫描 i18n 目录下所有 .qm 文件,以文件名(去掉后缀)作为语言代码建立可选语言列表,默认语言为 zh_CN(源码中 qsTr() 标记的原生语言,无翻译文件);若用户未设置过语言,程序会取系统默认 locale 尝试匹配,匹配失败则回落到简体中文。这也解释了为什么“放对文件名”如此重要——.qm 的文件名前缀就是语言标识符。
第 1 步:用 lupdate 提取待翻译字符串
方法一:生成/刷新单个语言的 ts 工程文件
使用 Qt 工具 lupdate.exe,在 dev-tools/i18n 目录下执行:
lupdate.exe "../../UmiOCR-data/qt_res/qml" -recursive -ts "en_US.ts"
- 第一个参数
../../UmiOCR-data/qt_res/qml是 QML 源代码目录,-recursive表示递归扫描; -ts "en_US.ts"指定输出的翻译工程文件名。
如果提示“无法将‘lupdate.exe’项识别为……”,则在指令最前面加上 ./:
./lupdate.exe "../../UmiOCR-data/qt_res/qml" -recursive -ts "en_US.ts"
执行成功时,应输出类似:
Scanning directory '../../UmiOCR-data/qt_res/qml'...
Updating 'en_US.ts'...
Found 307 source text(s) (140 new and 167 already existing)
Kept 42 obsolete entries
Same-text heuristic provided 21 translation(s)
如果已经开始编辑 ts 文件,重新调用 lupdate.exe 是安全的——它会保留已有的译文,只新增或更新条目(当然,建议多备份)。
方法二:用 lupdate_all.py 刷新所有语言
当你修改了源代码、添加了新文本,需要批量刷新所有语言的 ts 文件时,运行本目录下的 lupdate_all.py。从源码可以看到它的工作方式:
- 脚本内维护一个
LangList语言列表(L9-L25),当前启用en_US、zh_TW、ja_JP、fr_FR、pt、ru_RU、uz、vi、ta共 9 种,另有nb_NO、it_IT、es_ES、de_DE、ko_KR、pt_BR被注释暂不处理; - 对每种语言调用
lupdate.exe扫描UmiOCR-data/qt_res/qml,参数为-no-obsolete -source-language "zh_CN" -target-language "{l}" -ts "release/{l}.ts",即产物统一写入 dev-tools/i18n/release 目录(该目录中现存的ja_JP.ts、en_US.ts等文件即由此生成); - 脚本后半段还预留了“扫描 Python 源文件(
UmiOCR-data/py_src)→ 用pyside2-lupdate.exe与临时.pro工程文件生成*_2.ts→ 再按<context>合并回主 ts 文件”的完整逻辑(L44-L107),不过当前以sys.exit()提前结束(注释标注“Py翻译的部分 待定”),实际只执行 QML 部分。
第 2 步:用 linguist 进行翻译
使用 Qt 工具 linguist.exe 可视化翻译:
linguist.exe "en_US.ts"
或者在文件管理器中直接把 en_US.ts 拖到 linguist.exe 图标上。linguist 会打开一个可视化窗口,在上面进行翻译或检查。
如果是首次打开该 ts 文件,linguist 会弹窗询问源语言和目标语言:源语言 Source language 选择 Chinese (简体中文)(因为 Umi-OCR 的原生语言是中文),目标语言自定,Country 一般选 Any Country 即可。
基础用法四要点:
- 左侧
Context栏表示待翻译的源代码文件及每个文件的文本条数。如BatchOCR 18/19表示源代码BatchOCR一共有 19 条文本,其中 18 条已完成翻译; - 中上
Strings栏表示当前源代码文件的每一条文本。图标?/!表示未翻译或未检查,√表示已翻译。每翻译一条文本,记得点击该图标将它转为√; - 右侧
Sources and Forms栏表示该文本在源代码中的位置,可以结合代码中的注释来翻译; - 中心栏进行翻译:
Source text为原文本,Translation to XXX填写译文,Translator comments for XXXX可以不用写。
翻译中的四条硬性注意事项
进行翻译工作前,务必阅读 翻译注意事项,其核心规则有四条:
(1)换行符用直接回车,不要写 \n。 源代码中以 \n 表示的换行,在 linguist 中会显示为直接换行(行尾符号类似音符)。翻译时也应该直接回车,而不是输入字面量 \n:
这是第一行\n这是第二行 (源码)
错误翻译:
This is the first line\nThis is the second line
正确翻译:
This is the first line
This is the second line
(2)保留 %数字 占位符。 待翻译文本中可能含 %1、%2 等占位符,翻译时必须原样保留:
原端口号%1被占用,\n切换为新端口号%2。
正确翻译:
The original port number %1 is occupied.
Switching to the new port number %2.
(3)保留 Markdown 格式与特殊字符。 部分源文件(如 PagesManager)含 markdown 格式的长字符串,翻译必须遵照原文格式,保留 #、 (1 个全角空格 + 2 个半角空格,用于让 QML 的 md 解析器空出一行)等特殊字符。
(4)调整字体缩放系数。 Umi-OCR 的 UI 组件尺寸与行高绑定(如按钮宽 5 倍行高、高 1.5 倍行高),这些系数以中文为基准。相同内容在不同语言中占地不同(如 截屏 vs Screenshot),因此需要“行高不变、调整文字大小”。具体做法见下文“字体缩放系数”一节。
进阶:转纯文本批量处理 / 机器翻译
如果本地已安装 Python,可以把 ts 文件拖到 convert_ts_txt.py 上,或用命令行:
convert_ts_txt.py en_US.ts
结果:en_US.ts → en_US.txt,每行对应一条原文本。从 convert_ts_txt.py 源码 看,它解析 ts 的 XML 结构、遍历所有 <message> 的 <source> 节点逐行写出,并在此阶段把真实换行暂时转写为 \n。
这样就能用自动化手段(例如调用大语言模型作为翻译器)处理 en_US.txt,提示词中要求“保留原文的换行、% 开头标识符、markdown 等格式”。翻译完成后:
- 将译文覆盖写回
en_US.txt(先备份),用带行号的编辑器逐行核对译文与原文一一对应; - 将
en_US.txt拖入 convert_txt_ts.py,它会以原 ts 为模板、按顺序把 txt 各行写回<translation>节点(同时把\n还原为真实换行,见 convert_txt_ts.py#L22),生成en_US.txt.ts(覆盖前请先备份原 ts); - 用
linguist打开en_US.txt.ts检查、校对,编译为en_US.txt.qm,重命名为en_US.qm即可导入 Umi-OCR 测试。
第 3 步:用 lrelease 编译二进制包
方法一:在 linguist.exe 中,点击菜单 File → Release,即可在当前目录生成 en_US.qm。
方法二:命令行
lrelease.exe "en_US.ts"
如果是批量刷新全部语言,运行 lrelease_all.py:它遍历 release 目录下所有 .ts 文件,逐个调用 lrelease.exe 编译为同名 .qm(与 README 中“开发者维护流程”一致:lrelease_all.py 生成 → 把 release/ 下的 .qm 拷贝到 UmiOCR-data/i18n)。
放置翻译文件与效果验证
将编译好的 en_US.qm 拷贝到:
UmiOCR-data/i18n
当前仓库该目录已随包内置 6 个翻译包(UmiOCR-data/i18n):en_US.qm、ja_JP.qm、pt.qm、ru_RU.qm、ta.qm、zh_TW.qm。启动 Umi-OCR 后,即可在全局设置(语言 / Language 项)中切换语言。请仔细检查翻译文本是否正确、尺寸是否合适。
字体缩放系数 languageScale 的实现
针对“同一行高下不同语言文字长度差异”问题,Umi-OCR 内置了语言级字体缩放机制。在 Size_.qml 中:
// 语言缩放系数
// 在相同的行高内,有些语言经过缩放可以表现更好。如英文可以比汉字的字号更小。
// 通过在翻译文件中定义 languageScale 可以单独修改这种语言的缩放。
property string languageScale: qsTr("1.0")
Component.onCompleted: {
const s = parseFloat(languageScale)
if(!isNaN(s)) {
textScale = s
}
...
}
要点:languageScale 本身是一条可翻译文本(qsTr("1.0"))。也就是说,在你的 .ts 文件里有一个 Context 为 Size_ 的词条,原文是 1.0——把它翻译成比如 0.92,Component.onCompleted 解析后就会让 textScale = 0.92,从而缩小该语言下所有文字尺寸(text、smallText、largeText 均为“行高 × textScale”),而行高保持不变,正好适配英文等横向较长的文字。
调参技巧:先打开 Umi-OCR 全局设置 标签页,勾选 高级,拉到最底下 developer tools → languageScale (textScale)(对应 GlobalConfigs.qml#L286 处的开发者选项)。调整该数字可实时预览字体缩放,确定合适数值后再填入翻译文件。
提交贡献
按 翻译步骤(完整) 的要求:
- 翻译好的
.ts文件放在dev-tools/i18n目录下(批量流程中则位于其release/子目录,与现有ja_JP.ts、en_US.ts等保持一致); .qm文件放在UmiOCR-data/i18n;- 不要包含其它无关文件,然后提交 PR。
也可以前往 README 中提及的 Weblate 在线平台补充、订正现有语言翻译或创建新语言(见 dev-tools/i18n/README.md)。更简化的流程可参考同目录下的 翻译步骤(简易),本文则为完整本地化流程的权威说明。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
