Umi-OCR 多语言翻译实战:换行、占位符、Markdown 格式与 languageScale 字体缩放系数详解
本文为 Umi-OCR 开源 OCR 软件的本地化(i18n)译者指南。它完整覆盖了官方《翻译注意事项》中的全部核心规范——\n 换行规则、%1 占位符保留规则、Markdown 长字符串格式规则、languageScale 字体缩放系数的设定方法,以及“ts 转 txt → 机器翻译 → txt 转回 ts”的自动化翻译工作流;同时结合仓库中 Size_.qml 的源码实现与 convert_ts_txt.py、convert_txt_ts.py 两个转换脚本的实现细节,说明每条规则背后的技术原因,帮助你在完成一套 UI 翻译并导入 Umi-OCR 测试时做到一次通过。
1. Umi-OCR 的翻译体系:ts 工程文件与 qm 二进制包
Umi-OCR 的界面基于 Qt-Qml 框架,其翻译流程分为三步(假设目标语言为英语 en_US):
- 从源代码中提取所有待翻译字符串,生成
en_US.ts工程文件; - 编辑
en_US.ts,将其中文本翻译为目标语言; - 将翻译完成的
en_US.ts编译为en_US.qm二进制文件,放入 UmiOCR-data/i18n/ 目录后即可被软件加载。
仓库中的对应产物可以佐证这一链路:
- dev-tools/i18n/release/ 目录下存放各语言的
.ts工程文件,如 en_US.ts、ja_JP.ts、ru_RU.ts 等; - UmiOCR-data/i18n/ 目录下存放供软件直接加载的
.qm二进制翻译包,当前仓库内含 en_US.qm、ja_JP.qm、zh_TW.qm 等 6 个语言包; - 完整的提取、编辑、编译、提交操作见同目录的 翻译步骤(完整).md,本文聚焦其中的翻译内容规范与高效工作流。
下面 4 条注意事项,就是翻译 en_US.ts 这类文件时必须遵守的内容规范。
2. 关于换行符 \n:在 linguist 中必须用真实回车
源代码中以 \n 表示的换行符,在翻译工具 linguist 中会被转换为一行直接换行(编辑器中看起来像结尾带音符的断行)。因此翻译时也应使用回车键输入真实换行,而不是把字符串 \n 写进译文。
举例说明。源代码文本为:
这是第一行\n这是第二行
错误的翻译(把 \n 当纯文本写进去):
This is the first line\nThis is the second line
正确的翻译格式(用真实换行分隔两行):
This is the first line
This is the second line
这条规则的底层原因可以从 QML 字符串机制理解:qsTr() 捕获的原文本中包含的是转义序列 \n,Qt 在运行时将其解释为换行;而 linguist 的编辑器面向的是解析后的文本,其换行即真实换行符。若译者写入字面 \n,运行时界面就会显示出一个原样的 \n 字符,造成显示错误。
3. 关于占位符 %1:必须原样保留
待翻译文本中可能含有 %数字 格式的占位符(Qt 的 QString::arg() 风格参数),翻译时必须保留所有占位符,且编号不能改动,否则运行时参数替换会失败或缺失。例:
源代码文本:
原端口号%1被占用,\n切换为新端口号%2。
正确的翻译格式:
The original port number %1 is occupied.
Switching to the new port number %2.
注意此例同时体现了第 2 节的换行规则:原文的 \n 在译文中也应处理为真实换行。
4. 关于 Markdown 格式 #:保留特殊字符与全角空格
有一些源文件(如 PagesManager)中包含 Markdown 格式的长字符串,这些文本会被渲染进界面。翻译时务必遵照原文本格式,保留如 #、 这样的特殊字符。
特别地, (1 个全角空格 + 2 个半角空格)是用于让 QML 中 Markdown 解析器空出一行的技巧,直接复制这一串字符即可,不要自行删改。例:
源代码:
# 截图OCR
屏幕截图,快捷转文字。也支持粘贴图片。
正确的翻译格式(标题层级、空行数量、全角空格串均原样保留):
# Screenshot OCR
Screenshot, quick text conversion. Also supports pasting images.
5. 关于字体缩放系数 languageScale
5.1 为什么需要语言级缩放
在 Umi-OCR 的界面设计中,很多 UI 组件的尺寸与行高绑定,例如按钮宽度定义为 5 倍行高、高度为 1.5 倍行高,这些宽高系数以中文为基准设定。相同含义的文字,不同语言的占地并不相同——截屏 与 Screenshot 相比,英文明显更长。因此当 UI 语言为英文等长文本语言时,应适当缩小文字尺寸来适应 UI:行高不变,只调整文字大小。
5.2 源码实现:Size_.qml
这一机制的实现位于 UmiOCR-data/qt_res/qml/MainWindow/Size_.qml。该文件是全局尺寸组件,核心逻辑为(Size_.qml#L13-L30):
// 行高
property int line: 16 * scale // 主要文字
property int smallLine: 13 * scale // 较小的文字
property int largeLine: 20 * scale // 较大的文字
// 文字缩放值
property real textScale: 1 // 由下列 languageScale 控制
property int text: line * textScale // 行高 × 缩放 = 实际字号
property int smallText: smallLine * textScale
property int largeText: largeLine * textScale
而缩放系数的入口正是待翻译文本 1.0(Size_.qml#L47-L60):
// 语言缩放系数
// 在相同的行高内,有些语言经过缩放可以表现更好。如英文可以比汉字的字号更小。
// 通过在翻译文件中定义 languageScale 可以单独修改这种语言的缩放。
property string languageScale: qsTr("1.0")
Component.onCompleted: {
const s = parseFloat(languageScale)
if(!isNaN(s)) {
textScale = s
}
else {
console.warn("语言缩放系数无法应用:", languageScale)
}
}
从源码结构看:languageScale 本身也是一个 qsTr() 字符串,因此它会出现在翻译文件中;组件加载完成后 parseFloat 解析该译文——若译文是 0.92,则 textScale = 0.92,所有文字尺寸按 0.92 倍收缩,而 line/smallLine/largeLine 等行高保持不变;若译文不是合法数字,则打印警告并保持 textScale = 1。这就是“在翻译文件里改一个数字即可调整该语言字体缩放”的原理。
5.3 实操:先实时预览,再回填翻译文件
为方便测试,可以按以下步骤操作(引自 翻译注意事项):
- 打开 Umi-OCR 的
全局设置标签页,勾选高级; - 拉到最底下,找到
developer tools→languageScale (textScale); - 调整该数字,实时预览字体缩放效果;
- 确定数值后,将同样的数字填入翻译文件(
.ts)中对应1.0的译文位置。
该开发者选项对应 GlobalConfigs.qml 中 developer tools 分组下的 "languageScale (textScale)" 配置项(GlobalConfigs.qml#L286),它直接修改全局 Size_ 的缩放值,与翻译文件中写入的 languageScale 译文作用于同一参数,因此预览所见即最终所得。
6. 机器翻译工作流:ts → txt → 自动翻译 → ts → qm
当本地已安装 Python 时,可以借助 dev-tools/i18n 目录下的两个转换脚本,把 .ts 文件变成纯文本供机器翻译处理,再写回 .ts。
6.1 第一步:ts 转 txt
将 en_US.ts 直接拖动到 convert_ts_txt.py 图标上,或命令行调用:
convert_ts_txt.py en_US.ts
结果:en_US.ts → en_US.txt,txt 中每行对应一条原文本。此步骤中所有换行暂时以 \n 字符串表示,后续将 txt 转回 ts 时脚本会自动处理还原(与第 2 节的规则互为配合:linguist 里用真实换行,txt 里用 \n 占位)。
从源码看,convert_ts_txt.py 用 xml.etree.ElementTree 解析 ts 的 XML 结构,遍历每个 <message> 的 <source> 节点,输出时执行 source.replace("\n", r"\n"),把真实换行统一转成字面 \n,再逐条追加换行写入:
for item in message:
if item.tag == "source":
source = item.text
data[-1].append({"source": source})
...
s += d["source"].replace("\n", r"\n") + "\n" # 换行转\n
6.2 第二步:机器翻译 txt
得到 en_US.txt 后,可以用任意自动化手段批量翻译。例如将提示词与文本一起交给大模型:
请你充当翻译器,协助完成一个软件的UI翻译工作。
下面将输入多行文本。每行是一个原文。请你将其翻译为译文。
请保持原文的特殊格式,原文中的换行、%开头的标识符、mardown等格式予以保留。
首先,将简体中文翻译为英语。
【放文本】
提示词中“保留换行、% 开头标识符、Markdown 格式”的要求,正对应本文第 2、3、4 节的三条规范——这也是机器翻译结果需要人工校对的焦点所在。
6.3 第三步:txt 写回并转回 ts
- 将翻译好的文本逐行覆盖写回
en_US.txt(写之前先备份 txt)。务必使用带行号的文本编辑器,逐行核对每条译文与原文一一对应,没有错位、缺行; - 将写好的
en_US.txt拖入 convert_txt_ts.py,脚本会覆盖写入en_US.txt.ts(先备份现有 ts); - 用
linguist打开en_US.txt.ts,检查、校对翻译,编译为en_US.txt.qm; - 重命名为
en_US.qm,放入 UmiOCR-data/i18n/ 目录,即可导入 Umi-OCR 测试。
convert_txt_ts.py 的实现与上一步严格对称:它先解析原 ts 文件得到 XML 骨架,再按行读取 txt,对每个 <translation> 节点执行 txt[tranIndex].replace(r"\n", "\n") 把字面 \n 还原为真实换行后写回,最后 tree.write() 输出新 ts。也就是说,txt 的行序必须与 ts 中消息条目的顺序严格一致——这正是第 6.3 步要求“逐行核对”的原因。
7. 交付与检查清单
翻译完成、en_US.qm 导入后,建议在 Umi-OCR 中做一轮完整走查,对照本文各节确认:
| 检查项 | 对应规范 |
|---|---|
界面中是否出现原样的 \n 字符 |
第 2 节:linguist 内使用真实换行 |
| 带数字参数的句子(如端口提示)中参数是否正常替换 | 第 3 节:%1/%2 占位符原样保留 |
| 帮助类长文本的 Markdown 标题、空行渲染是否正常 | 第 4 节:保留 # 与全角空格串 |
| 长单词语言(如英文)是否撑破按钮/面板 | 第 5 节:通过 languageScale 微调字号,行高不变 |
.ts 文件提交至 dev-tools/i18n/release/,.qm 文件提交至 UmiOCR-data/i18n/,完整的提交与 PR 流程参见 翻译步骤(完整).md。掌握本文的格式规范、languageScale 缩放原理与 txt 转换工作流后,即可独立完成一套高质量的语言翻译并闭环验证。
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 StartedRust0624
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