如果你是一位 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 结构
localizer.Localize(&i18n.LocalizeConfig{
DefaultMessage: &i18n.Message{
ID: "PersonCats",
One: "{{.Name}} has {{.Count}} cat.",
Other: "{{.Name}} has {{.Count}} cats.",
},
TemplateData: map[string]interface{}{
"Name": "Nick",
"Count": 2,
},
PluralCount: 2,
}) // Nick has 2 cats.
  1. 执行 CMD 命令,将 Message 信息提取到 active.en.toml 文件中
goi18n extract

# active.en.toml
[PersonCats]
description = "The number of cats a person has"
one = "{{.Name}} has {{.Count}} cat."
other = "{{.Name}} has {{.Count}} cats."
  1. 执行 CMD 命令,将待翻译成中文的 Message 提取到 translate.zh.toml 文件中(这个文件是工具创建的)
goi18n merge active.*.toml

# translate.zh.toml
[HelloPerson]
hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
other = "Hello {{.Name}}"
  1. 将 translate.zh.toml 翻译成中文
# translate.zh.toml
[HelloPerson]
hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
other = "你好 {{.Name}}"
  1. 执行 CMD 命令将 translate.zh.toml 内的翻译好的内容,自动增量合并进入 active.zh.toml 文件中
goi18n merge active.*.toml translate.*.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)
//err, _ := someFunc()
fmt.Fprintf(w, FormatErr(err))
} func main() {
http.HandleFunc("/", helloHandler) fmt.Println("Starting server on port 8080...")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(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
}

提取本地化的 err 消息

由于所有具备本地化能力的 err 都实现了 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(),
},
//MessageID: i18nErr.LocalizedID(),
TemplateData: i18nErr.TemplateData(),
})
return msg
}
return err.Error()
}

五、学习资料

参考文献:

开源仓库:

star 最多的 Go 语言本地化库|GitHub 2.8K的更多相关文章

  1. 在github上查找star最多的项目

    如何在github上查找star最多的项目 在search中输入stars:>1 就可以查找所有有star的项目,然后右上角根据自己的需要筛选 当我输入stars:>10000的时候,就会 ...

  2. Standard C 语言标准函数库介绍

    全面巩固所知所学,往精通方向迈进! Standard C 语言标准函数库速查 (Cheat Sheet) from:http://ganquan.info/standard-c/function/ C ...

  3. 全网Star最多(近20k)的Spring Boot开源教程 2019 年要继续更新了!

    从2016年1月开始写博客,默默地更新<Spring Boot系列教程>,从无人问津到千万访问,作为一个独立站点(http://blog.didispace.com),相信只有那些跟我一样 ...

  4. Standard C 语言标准函数库速查(彩色的函数列表,十分清楚)

    Standard C 语言标准函数库速查 (Cheat Sheet) wcstombs 函数说明 #include <stdlib.h> size_t mbstowcs(wchar_t * ...

  5. 黄聪:让WordPress主题支持语言本地化(使用poedit软件实现中文翻译功能)

    如果你的WordPress主题要提交到WordPress官方主题库,使用者来自世界各地的多种语言,那么,你就要让你的WordPress主题支持语言本地化,方便使用者进行语言翻译和制作语言包. 让Wor ...

  6. [Abp 源码分析]十三、多语言(本地化)处理

    0.简介 如果你所开发的需要走向世界的话,那么肯定需要针对每一个用户进行不同的本地化处理,有可能你的客户在日本,需要使用日语作为显示文本,也有可能你的客户在美国,需要使用英语作为显示文本.如果你还是一 ...

  7. Redis学习之路(008)- Redis C语言客户端库hiredis文档翻译

    Hiredis是Redis数据库一个轻量的C语言客户端库. 之所以轻量是由于它只是简单的提供了对redis操作语句支持的接口,并没有实现具体的操作语句的功能.但正是由于这种设计使我们只要熟悉了通用的r ...

  8. C语言函数库

    C语言函数库 分类函数目录函数进程函数诊断函数接口子程序输入输出 str字符串操作函数mem操作存贮数组 数学函数 时间日期函数 转换函数 分类函数,所在函数库为ctype.h[top] int is ...

  9. unity多语言本地化

    简介 嗯...一般来说做游戏啥的都不会只发一个国家,但是每个国家语言不同,就存在多语言本地化的问题,然后直接用过一个通过xml完成本地化的东东,然后策划反馈不会修改xml,扔给我一个excel让我自己 ...

  10. 造!又有新的生产力语言了「GitHub 热点速览 v.22.30」

    作者:HelloGitHub-小鱼干 你还记得那些 PHP 开发都去哪了吗?转 Golang 了!移动端现在流行什么?Flutter 编程.现在谷歌带着新的生产力语言来了,Carbon,代号:C++ ...

随机推荐

  1. 揭秘 RocketMQ 新特性以及在金融场景下的实践

    2019 年末, RocketMQ 正式发布了 4.6.0 版本,增加了" Request-Reply "的同步调用的新特性." Request-Reply " ...

  2. 基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台

    简介: 本文将对 RocketMQ-Exporter 的设计实现做一个简单的介绍,读者可通过本文了解到 RocketMQ-Exporter 的实现过程,以及通过 RocketMQ-Exporter 来 ...

  3. 企业上云如何对SLS日志审计服务进行权限控制

    简介: 日志审计是信息安全审计功能的核心部分,是企业信息系统安全风险管控的重要组成部分.SLS的日志审计服务针对阿里云的多种云产品(Actiontrail.OSS.SLB.RDS.PolarDB.SA ...

  4. 如何用Netty写一个高性能的分布式服务框架?

    简介: Netty 是一个致力于创建高性能网络应用程序的成熟的 IO 框架.相比较与直接使用底层的 Java IO API,不需要先成为网络专家就可以基于 Netty 去构建复杂的网络应用.业界常见的 ...

  5. MySQL 深潜 - 一文详解 MySQL Data Dictionary

    ​简介: 在 MySQL 8.0 之前,Server 层和存储引擎(比如 InnoDB)会各自保留一份元数据(schema name, table definition 等),不仅在信息存储上有着重复 ...

  6. 万字长文总结与剖析C语言关键字 -- <<C语言深度解剖>>

    C总结与剖析:关键字篇 -- <<C语言深度解剖>> 目录 C总结与剖析:关键字篇 -- <<C语言深度解剖>> 程序的本质:二进制文件 变量 1.变量 ...

  7. 14、web 中间件加固-Tomcat 加固

    1.用户配置 如果不需要控制台管理,请更改控制台用户文件注销账号信息:如果需要,请更改账户信息 修改 tomcat/conf/tomcat-user.xml 文件 注释或修改如下信息 <role ...

  8. 虚拟机中安装mysql 完整教程( CentOS7 版本)

    一.检查是否安装了Mysql Yum检查 yum list installed | grep mysql 安装则直接删除 yum remove mysql-community-client.x86_6 ...

  9. ios系统的css兼容问题处理和iOS上网页滑动不流畅问题

    1.H5网页touch滑动的时候在苹果手机上出现不流畅的问题 -webkit-overflow-scrolling 用来控制元素在移动设备上是否使用滚动回弹效果. 解决办法:给所有网页添加如下样式 b ...

  10. WordPress函数小结

    1.body_class()函数 为了区分不同的页面,可以用WordPress的body_class()函数 可以在head.php中给body添加:<body <?php body_cl ...