自制工业控制系统:国际化实战——UTF-8内码、多语言字库与locale区域设置
Contents
起因
系统要卖到国外,第一屏就体现产品气质:操作工看到的是母语还是一门外语,决定他对这台机床的第一印象,也决定报警文本他能不能读懂——读不懂的报警等于没有报警。
编码这个地基是行业踩了三十多年坑才踩明白的:1980 年 GB2312 发布,解决的是七位 ASCII 装不下汉字的问题;1991 年 Unicode 1.0 想用一个码位空间装下全世界的文字,第二年 Ken Thompson 和 Rob Pike 在 Plan 9 上捣鼓出 UTF-8——变长、ASCII 兼容、没有字节序问题,成了联网世界的赢家,今天的网页、协议、文件名默认都是它。国际化不是"把中文翻译一遍"的后期工作,它影响编码、字库、参数、界面布局四个地基决策,要在基础篇里定下来。
一、编码这关在图形篇已经过了
图形篇建字库时就没有走 GB2312 区位码那条老路:字模直接按 Unicode 码位组织(两级稀疏索引),字符串侧全系统 UTF-8——源码字符串、参数、文件名、日志、网络协议里的人读字段,一个口径。所以国际化这篇不用"改造"什么,编码的地基是现成的,剩下的都是语言资源、locale、键盘布局这些真正的国际化问题。
唯一要反复守的纪律:UTF-8 变长(1–4 字节),“取第 N 个字符"是"扫描第 N 个字符”,不能按字节切片下标——中文 3 字节、西里尔 2 字节、越南语 3 字节都是真实存在的长度。图形篇 draw_text 按 chars() 迭代的写法就是这条纪律的样板,其他碰文本的代码照此检查。
二、字符串表:代码里不允许出现给人看的句子
key → 多语言资源:
|
|
资源文件格式用最笨的"逐行 key=UTF-8 文本",加载进定长哈希表常驻内存;编译进内核一份兜底副本(中文+英文),语言包丢了系统照样起。查询的 miss 链也定死:语言包查不到 → 查内置副本 → 还不行就直接显示 key 本身(LBL_START)——开发期一眼看出漏翻,比满屏问号强。控件持有的是 key 不是译文,绘制时查表(哈希 O(1),每帧几十次无所谓);切语言 = 重载表 + 全控件标脏,图形篇的脏矩形机制天然支持,不用重启。
坑:带参数的字符串(“坐标超出限位:X={0}")各语言语序不同,不能拼接 key——资源格式支持 {0}{1} 占位符,翻译者可以调整占位符顺序,德语俄语会把动词丢到最后。
界面布局配套:外文平均比中文长 30%,控件宽度按"最长翻译+余量"设计,落成布局常量(图形系统没做通用布局引擎,宽度就是坐标常量,改宽度 = 改常量重编);编辑框这类动态控件才按文本实测宽度算。
三、字库:分级覆盖
| 级别 | 范围 | 字形量 | 策略 |
|---|---|---|---|
| 一级 | ASCII + Latin-1 补充 | ~200 | 8×16 内置,永远在 |
| 二级 | CJK 统一表意基本区 | ~7000(16×16) | 内置(图形篇的生成式字库) |
| 三级 | 西里尔/希腊/扩展拉丁 | 按市场 | 语言包携带,可加载 |
体积账:7000 字 × 32B ≈ 224KB,三级全上也压不垮 1MB——点阵方案在国际化的量级下依然成立,这是工控 UI 字符集有限的红利。字体渲染高度统一(没有混合字体),排版规则简单。
三级字库的挂载跟着语言包走:扩展字库沿用图形篇的 UF16 格式,开机从 DATA 区加载进预留缓冲,挂到 font_lookup 的查询链末尾——先查内置、miss 再查扩展包,draw_text 一行不改,只在 font_lookup 里加一条回查。这是当初选两级稀疏索引而不是连续数组时埋好的回报。
坑:RTL 语言(阿拉伯/希伯来)的整段镜像排版是另一个量级的工程——设计上直接声明不支持,写进产品文档,别留"以后再说"的口子。
四、区域设置(locale):挂在参数系统上
参数表加一个 locale 槽:语言、公制/英制、日期格式、小数点符。影响面清单:
- 图形系统:单位换算显示(内部永远 µm/公制存储,只有显示层换算)
- 时间显示:RTC 读出的墙钟按 locale 格式化
- 报警与文档导出:加工报表、程序头的语言;CSV 类导出有个著名的坑——德语区小数点是逗号,分隔符得跟着换成分号,不然客户的 Excel 打开全挤在一列
坑:内部存储永远一套单位(µm、毫度),locale 只存在于显示与导入导出边界——在内核深处做单位换算是浮点误差和撞机事故的温床。
五、报警文本:国际化的最大客户
报警系统是文本量最大的子系统(几百条),也是翻译质量最敏感的地方。每条报警 = 错误码(u32)+ 参数数组 + 各语言模板。错误码在日志、Modbus 寄存器(网络篇)、界面三处共用,语言只在最后一层渲染时介入——机器对话用码,人对话才用语言。码本身按子系统分段(存储、运动、工艺、合规各占一段)——客户电话里报一个码,听头几位就知道转给哪条线的人。帮助系统同构:报警码 → 处理指引(各语言文本)。
六、输入法与键盘布局
英文键盘直接输入;中文输入法在应用篇计划(拼音候选)。物理键盘布局(US/EU 各国)影响键值映射表——HID 键盘给的是 Usage(键鼠篇),到各国布局的字符映射做成可加载表,与语言包同机制。US 布局编译进内核兜底,道理同字符串表的内置副本:布局表丢了键盘照常能用,只是个别符号位置不对。
总结
实战清单:UTF-8 唯一内码 + 码点迭代纪律;key 化字符串 + {0} 占位符 + 内置兜底语言;三级字库覆盖表;locale 挂参数表 + 内部单位不变原则;报警"机器对话用码”;键盘布局可加载。跑通标志:切换 zh/en/ru 三语言,界面/报警/导出报表全部跟随且无需重启(或仅重启 UI 状态机);拔掉语言包后系统以内置中英文正常启动;单位切英制后所有显示层换算正确、内部存储值一字不变。
下一篇:合规与安全控制——机器卖出去之后,所有权和合规使用怎么管。
参考链接
- Unicode 与 UTF-8(unicode.org)
- 本系列:图形系统(字库与渲染)、参数系统(locale 槽)、日志系统(报警码)、键鼠驱动(Usage 键值)
Author 软件开发大郭
LastMod 2026-09-11