传统的解决方案
i18n
是软件开发中常见的一个需求, 很多流行的开发框架如 ruby on rails
, springboot
对它有内置的支持。
rails 的 i18n 是其中的佼佼者, 我们看看它解决了哪些问题,是如何解决的。
i18n 资源文件
通常开发者需要按照框架的约定创建资源文件,一般会在目录或文件名中包含如 es
, en
等 locale
信息,方便框架按需加载。
|---books
|-----es.yml
|-----en.yml
|---users
|-----es.yml
|-----en.yml
key 的定义和查找优先级
通常每个翻译文本会对应一个有意义的key
,通过 key
+ locale
的组合得到当前 locale
下的翻译文本.
I18n.t 'activerecord.models.user' # => 'Customer'
I18n.t 'activerecord.models.user' # => '客户'
en:
activerecord:
models:
user: "Customer"
attributes:
user:
login: "Login"
zh:
activerecord:
models:
user: "客户"
attributes:
user:
login: "登陆"
当项目到一定规模, key 的数量很多时,key 的命名就显得格外重要,否则重用 key 时很难查找。 而且除了用户自定义的 key, 框架一些内置的 key 如日期, 错误消息等, 也需要用户提供翻译。 所以 key 的命名 rails 也做了约定,如下
activerecord.errors.models.[model_name].attributes.[attribute_name]
activerecord.errors.models.[model_name]
activerecord.errors.messages
errors.attributes.[attribute_name]
errors.messages
总结下来,需要关注的点主要有:
- 翻译文本的获取; 定义 key 并与文本建立映射关系
- 归类创建资源文件
- 对资源文件进行翻译
- 显示翻译文本
其中,需要开发人员处理的,主要是 1, 2, 4, 第 3 步可能需要专门的翻译或者借助第三方平台。
golang 的 i18n 方式
golang 处理 i18n 的包主要是 go get -u golang.org/x/text
, 它对第 1, 2 步有较大的改进。
该包中提供了一个工具 gotext,
可以分析源码, 将待翻译文本抽取出来(如fmt.Println),直接将它作为 key, 并归类创建好资源文件。
package main
//go:generate gotext -srclang=en update -out=catalog.go -lang=en,zh
import (
"fmt"
"golang.org/x/text/language"
"golang.org/x/text/message"
_ "golang.org/x/text/message/catalog"
)
func main() {
p(language.English)
p(language.Chinese)
}
func p(t language.Tag) {
p := message.NewPrinter(t)
p.Printf("Hello, %s", "world")
fmt.Println()
p.Printf("I want %d apple", 1)
fmt.Println()
}
以上面的代码为例, 运行 go generate
, 会自动为你创建如下的资源文件,
locales
|--en
|-----out.gotext.json
|--zh
|-----out.gotext.json
|-----message.gotext.json
你将 out.gotext.json
重命名为 message.gotext.json
, 做好翻译, 再运行 go generate
更新翻译后的资源到 catalog.go
,
go build
后运行,即可看到翻译:
Hello, world
I want 1 apple
你好, world
我想要 1 个苹果
你可以在 https://github.com/feitian124/i9n.git
的 gotext 分支找到一个可以工作的例子.
目前该包 gotext
还在开发状态, 文档也比较缺乏, 但上述命令基本可以用, 可能会随着 go 1.17 或 1.18 正式发布。