做桌面应用的国际化,要是还想着照搬Web那套中间件加context模式,那可就行不通了。毕竟没有HTTP请求生命周期,语言切换属于运行时动态行为,必须手动触发重渲染,而且Localizer实例得复用,而不是像Web那样每次请求新建一个。
加载翻译资源,如何避免静默失败
桌面应用启动时,通常是一次性把所有语言文件都加载进来。但
go-i18n/v2的
bundle.LoadMessageFile有个坑——它不报错不代表没出问题,返回nil错误的情况其实很常见。
- 文件名必须严格遵循BCP 47规范,比如
active.zh-CN.json才行。如果写成
zh.json或
zh_CN.json,系统会直接忽略掉。
- JSON结构外层必须是对象,每个条目都得包含
id和
translation字段。缺了
description不会报错,但某些版本会跳过该条目,翻译就无声无息地丢了。
- 更靠谱的做法是用
embed.FS打包进二进制:先声明
//go:embed locales/*,再传给
bundle.ParseFS(fs, "locales/active.*.json")。这样能避免路径拼错或运行时文件缺失的麻烦。
- 务必检查
LoadMessageFile返回的
error。别用
MustLoadMessageFile,它panic会导致桌面程序直接退出,用户体验极差。
在Qt Go、Fyne或Walk里,怎么安全绑定Localizer
Qt Go用
Tr(),Fyne用
App.Translator().Translate(),但底层还是需要你来维护语言状态。
- 不要搞全局单例的
*i18n.Localizer——它绑定了语言标签,切换语言时必须重建。
- 推荐封装一个
LangManager结构体,持有
*i18n.Bundle和当前
language.Tag,提供
Set(lang language.Tag)方法。
- 每次调用
Set()后,必须触发UI重绘(比如Qt的
QApplication::postEvent或Fyne的
app.Refresh()),否则控件文本不会更新。
- 按钮、菜单等控件初始化时,直接用
manager.T("button.sa ve")获取翻译,而不是在事件回调里临时查——避免重复解析ID。
系统语言随时可能变,怎么办
桌面环境的语言不是“一次协商”,而是随时可能变,比如用户改了系统设置。
- 启动时读取
os.Getenv("LANG"),或者调用C函数获取系统locale(macOS/Linux用
nl_langinfo(CODESET),Windows用
GetUserDefaultUILanguage())。
- 用户点击“切换语言”菜单项时,不要只改内存变量——要调用
LangManager.Set()并广播信号(Qt用
QObject.Signal,Fyne用
widget.NewLabel().SetText()配合全局通知)。
- 避免在Goroutine中异步切换语言:UI更新必须在主线程(Qt的
QMetaObject.InvokeMethod,Fyne的
app.RunOnMainThread())。
- 切换后检查是否所有窗口都已刷新:模态对话框、托盘菜单、右键上下文菜单容易漏掉,需显式调用其
Refresh()或
Rebuild()。
说实话,最容易被忽略的,是语言切换后日期和数字格式器也得重建,并重新注入到业务逻辑中。否则你会发现,时间显示还是旧locale的格式。这和Web场景完全不同,桌面应用没有“每次请求新建”这种天然隔离,状态泄漏的风险更高。
本文转载于:https://www.php.cn/faq/2322099.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。