在上一篇文章 在 Golang 中如何做国际化? 中我提到了 “Go 目前没有一个好的检测运行环境语言的库”,go-locale
就是为了解决这个问题而诞生的。
一些事实
现实的情况是,我们没有一个标准的方法可以获取到当前代码运行环境的语言情况。
对于大部分 Linux 发行版而言,我们可以检查 LANG
或者 LANGUAGE
环境变量,但是不同发行版有不同的习惯,而每个人还有自己的配置,比如我在 Archlinux 上就只有 LANG=en_US.UTF-8
,其他的语言相关环境变量都没有。macOS 上更加复杂,传统上我们将它看作类 Unix 操作系统,沿用环境变量或者直接调用 locale
来检查,但是这也是不一定的。Windows 更不必说了,环境变量这一套不好使,需要检查注册表或者调用 Win32 API。
所以想要解决这些问题,我们需要为不同的平台实现不同的语言检测逻辑,但是现在这些任务可以交给 go-locale
来做了。
介绍
go-locale
的目标是跨平台的语言检测库,它会使用各个平台的不同方式来尽力探测出当前使用的语言,目前已经支持了 Linux
,macOS
和 Windows
三大主流平台。
import (
"github.com/Xuanwo/go-locale"
)
func main() {
tag, err := locale.Detect()
if err != nil {
log.Fatal(err)
}
// Have fun with language.Tag!
}
内部实现
go-locale
使用条件编译机制,对外暴露一个统一的 Detect
,内部按照平台不同实现不一样的 detect
方法,在 detect
内会尝试该平台下已知可用的多种不同方式,所有方式都检测不到的情况下才会返回 ErrNotDetected
。
Linux
在 Linux 平台下首先会检查环境变量,检查顺序如下:
LANGUAGE
兼容gettext
的行为LC_ALL
总是会覆盖其他的所有LC_*
配置LC_MESSAGES
是所有消息的 locale 配置LANG
是所有LC_*
配置的 fallback 值
如果环境变量全部检查失败,会尝试调用 locale
命令来获取语言。
macOS
在 macOS 下首先会进行全部的 Linux 系统兼容的检查,如果没有获取到,则会使用系统提供的 User Defaults System
,通过 defaults read NSGlobalDomain AppleLanguages
来获取语言。
Windows
Windows 下则会使用 Win32 OLE API 来获取。
已知问题
虚高的 Code Coverage
目前项目显示的代码测试覆盖率为 100%,但是这只是在 Linux 平台下测试的结果。目前 Codecov 不支持汇总多个平台下的整体结果,所以选择了只提交最好看的一个平台。
此外,在 Linux 的单元测试中大量的进行了 mock 和 monkey patch 来模拟行为,但是由于我本人 Windows 和 macOS 使用经验较少,并不确定他们的行为是否真的是这样,所以也没有写类似的单元测试。
根据在 Travis CI 上测试的结果,Windows 和 macOS 上的实现是 work 的,但是我不排除在特定版本和配置下会出问题的可能,如果遇到的话欢迎提交 Issue 反馈。
只返回一个语言
设计时的目标是返回最有可能的那个语言,但是很多人会设置多种可选语言,比如 zh_CN:zh_TW:en_US
,如果软件不支持中文的话使用英文也可以。所以这个计划在之后会返回成按照 fallback 顺序来排列的语言数组。