我们提供安全,免费的手游软件下载!

安卓手机游戏下载_安卓手机软件下载_安卓手机应用免费下载-先锋下载

当前位置: 主页 > 软件教程 > 软件教程

Go 实现多语言本地化

来源:网络 更新时间:2024-06-12 09:30:41

对于 Go 用户而言,在开源的学习仓库中可以找到针对多种往期归档文章的学习资料。此外,B站上的白泽talk,以及公众号【白泽talk】中,回复"电子书",即可获取包含《100个Go经典错误场景》在内的纯净 Golang 电子书大全。

现在我们来谈一谈 i18n。无论是 ToB 还是 ToC 的业务,多语言需求非常常见,因为用户来自不同国家和地区,所以在页面展示内容或响应结果中需要进行多语言适配。

例如:hello world! -> 你好世界! err: "user not find" -> err: "用户不存在"

翻译错误可能会给用户带来困扰,就像鸣潮最近的一个类似事故:

鸣潮日文客户端将本次up角色忌炎的专武效果翻译错误,将R技能翻译成了E技能。

在前端实现国际化:

  1. 准备多语言资源文件,含有不同语言版本的字符串。
  2. 集成国际化插件:使用前端框架提供的国际化插件,如 React-intl、Vue-i18n 等,或者手动实现国际化逻辑。
  3. 根据用户选择的语言加载资源:在应用加载时,根据用户选择的语言加载对应的资源文件,将界面展示的文本内容替换为对应语言的字符串。

在后端实现国际化:

  1. 准备多语言内容,将不同语言版本的文本或内容保存在后端,可以是数据库中、文件中或其他形式。
  2. 处理国际化逻辑:在后端代码中编写逻辑,根据用户的语言选择加载相应的内容。这可以通过模板引擎、多语言资源文件或者接口返回不同语言的数据来实现。
  3. 提供接口或服务:如果后端需要提供国际化服务,可以设计接口或服务来根据用户需求返回对应语言的内容。

Go 实现消息本地化:

一个热门的项目是:https://github.com/nicksnyder/go-i18n

关于本地化消息的定义与翻译流程,可参考 go-i18n 的 readme 更加详细。

  1. 命令行工具下载(用于从 Go 代码中提取需要本地化的 Message)
go install -v github.com/nicksnyder/go-i18n/v2/goi18n@latest
  1. 创建两个文件存放翻译结果:active.en.toml 和 active.zh.toml
  1. 在 Go 代码中,显示声明一个 Message 结构,然后执行 CMD 命令将 Message 信息提取到 active.en.toml 文件中。

我们还可以基于 go-i18n 进一步封装实现一个 HTTP 服务:

具体的 demo 可见:https://github.com/BaiZe1998/go-learning/tree/main/kit/i18n

效果是:从 HTTP 头部中获取 lang,得到“zh”,响应中文的错误消息。

举例一个简单的 HTTP 服务:创建一个具备本地化能力的 error,从请求头提取语言,然后选择对应语言的 error 信息响应。

func helloHandler(w http.ResponseWriter, r *http.Request) {
    err := NewUserNotFoundErr(123)
    fmt.Fprintf(w, FormatErr(err))
}

在服务启动前初始化:默认语言选择中文,选择将 active.zh.toml 在服务启动前加载进入内存。

var (
    bundle = i18n.NewBundle(language.English)
)

func init() {
    bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
    bundle.LoadMessageFile("active.zh.toml")
}

以下的封装确保每次新增一个本地化的 error,只需要组合 BaseError 即可继承通用的本地化能力。

// 本地化方法声明
type LocalizedError interface {
    error
    LocalizedID() string
    TemplateData() map[string]interface{}
}

// 基础错误类,实现对应本地化方法
type BaseError struct {
    ID             string
    DefaultMessage string
    TempData       map[string]interface{}
}

func (b BaseError) Error() string {
    return b.DefaultMessage
}

func (b BaseError) LocalizedID() string {
    return b.ID
}

func (b BaseError) TemplateData() map[string]interface{} {
    return b.TempData
}

// 新增一个自定义错误
type UserNotFoundErr struct {
    BaseError
}

func NewUserNotFoundErr(userID int) LocalizedError {
    msg := i18n.Message{
        ID:    "user_not_found",
        Other: "User not found {{.UserID}}",
    }
    e := UserNotFoundErr{}
    e.ID = msg.ID
    e.DefaultMessage = msg.Other
    e.TempData = map[string]interface{}{
        "UserID": userID,
    }
    return e
}

由于所有具备本地化能力的 error 都实现了 LocalizedError 接口,因此可以定义如下方法统一在 Handler 层提取本地化之后的错误内容。

// 这里就不从 HTTP 请求头获取了,假设提取到了 zh
func GetLang(_ context.Context) string {
    return "zh"
}

func FormatErr(err error) string {
    lang := GetLang(context.Background())
    loc := i18n.NewLocalizer(bundle, lang)
    var i18nErr LocalizedError
    if errors.As(err, &i18nErr) {
        msg, _ := loc.Localize(&i18n.LocalizeConfig{
            DefaultMessage: &i18n.Message{
                ID:    i18nErr.LocalizedID(),
                Other: i18nErr.Error(),
            },
            TemplateData: i18nErr.TemplateData(),
        })
        return msg
    }
    return err.Error()
}

学习资料:

  • Xuanwo's Blog
  • 掘金:Go语言国际化 i18n
  • Go Web 编程
  • https://www.ituring.com.cn/article/508191?published=true

开源仓库:

  • https://github.com/nicksnyder/go-i18n
  • https://github.com/gin-contrib/i18n
  • https://github.com/hertz-contrib/i18n
  • https://github.com/gofiber/contrib/tree/main/fiberi18n
  • https://github.com/beego/i18n