go实现i18n的几种方法

哔哔叨

去年上班时候也去想过实现i18n,但是由于进度要求就没有去查看别的库什么的,而是通过定义const枚举常量返回给前端,再让前端根据常量从json文件中找到对应的文本输出.

这种方法导致的就是耦合性较强,同样带来的还有前端首屏加载负担大.好处是给后端减少了在内存中加载大量文本的问题.因此现在看到相关视频来看看go实现i18n的几个方法

官方非标准库实现

官方有实现golang.org/x/text包,但由于是非go的标准库,所以用例和注释可能会缺少,导致有使用成本

# 先安装包
go get golang.org/x/text/language
go get golang.org/x/text/message

# 安装cli
go install golang.org/x/text/cmd/gotext@latest

project/main.go

package main

import (
    "golang.org/x/text/language"
    "golang.org/x/text/message"
    "strings"
)

//go:generate gotext -srclang=zh -dir=./i18n/locales/ update -out=./i18n/catalog.go -lang=zh,en

func main() {
    temp := &strings.Builder{}

    p := message.NewPrinter(language.MustParse("zh"))
    p.Print("test")
    p.Println("this is test string")
    p.Printf("this is test string1")

    p.Sprint("this is test string2")
    p.Sprintf("this is test string3")
    p.Sprintln("this is test string4")

    p.Fprint(temp, "this is test string5")
    p.Fprintln(temp, "this is test string6")
    p.Fprintf(temp, "this is test string7")
}
项目根目录执行 gotext -srclang=zh -dir=./i18n/locales extract -lang=zh,en .

-srclang代表项目原始语言
-dir要把生成的文件放在哪
-lang代表要生成的语言有哪些

现在目录结构如下
project
│  go.mod
│  go.sum
│  main.go
│
└─i18n
    └─locales
        ├─en
        │      out.gotext.json
        │
        └─zh
                out.gotext.json

可以看到生成了/i18n/locales/en /i18n/locales/zh文件夹和两个out.gotext.json文件.

我们将两个out.gotext.json文件复制为messages.gotext.json, 然后随便打开一个可以看到只有1,3,7的文本被提取出来, 即Printf Sprintf Fprintf函数的文本会被提取.

我们现在在json文件中把translation字段填上对应文本

然后执行命令 gotext -srclang=zh -dir=./i18n/locales/ update -out=./i18n/catalog.go -lang=zh,engo generate

这时候生成了 i18n/catalog.go 文件,我们需要手动修改package为i18n

然后在main中新增引用 _ "alitracing/i18n" 再次运行代码

输出:
testthis is test string // 忽略此行
这是测试字符串1

我们忽略输出的第一行,这时候发现文本已经被替换了.

要在项目中运用思路如下:

  1. 用gin拦截器获取前端请求头的accept-language
  2. 在拦截器中使用language的matcher自动匹配语言,如果没有就返回t的第一个语言

    t := []language.Tag{
        language.English, // en
        language.Chinese, // zh
    }
    
    matcher := language.NewMatcher(t)
    tag, _ := language.MatchStrings(matcher, "zh-CN")
    t1, _ := tag.Base()
    fmt.Println(t1.String()) // zh
  3. 将tag放进gin上下文中传递,在需要的地方实例化printer然后用xxxxf函数打印

go-i18n

待写...

我来吐槽

*