star 最多的 Go 语言本地化库|GitHub 2.8K

🌟 如果你是一位 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)
shell 复制代码
go install -v github.com/nicksnyder/go-i18n/v2/goi18n@latest
  1. 创建两个文件存放翻译结果
shell 复制代码
active.en.toml
active.zh.toml
  1. 在 Go 代码中,显示声明一个 Message 结构
go 复制代码
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 文件中
shell 复制代码
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 文件中(这个文件是工具创建的)
shell 复制代码
goi18n merge active.*.toml

# translate.zh.toml
[HelloPerson]
hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
other = "Hello {{.Name}}"
  1. 将 translate.zh.toml 翻译成中文
shell 复制代码
# translate.zh.toml
[HelloPerson]
hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
other = "你好 {{.Name}}"
  1. 执行 CMD 命令将 translate.zh.toml 内的翻译好的内容,自动增量合并进入 active.zh.toml 文件中
shell 复制代码
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信息响应。

go 复制代码
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 在服务启动前加载进入内存。

go 复制代码
var (
	bundle = i18n.NewBundle(language.English)
)

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

高效封装

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

go 复制代码
// 本地化方法声明
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 层提取本地化之后的错误内容。

go 复制代码
// 这里就不从 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()
}

五、学习资料

参考文献:

开源仓库:

相关推荐
檀越剑指大厂1 小时前
开源AI大模型工作流神器Flowise本地部署与远程访问
人工智能·开源
weixin_446260851 小时前
开源vs闭源:你更看好哪一方?
开源
技术仔QAQ2 小时前
【tokenization分词】WordPiece, Byte-Pair Encoding(BPE), Byte-level BPE(BBPE)的原理和代码
人工智能·python·gpt·语言模型·自然语言处理·开源·nlp
tumu_C3 小时前
C++模板特化实战:在使用开源库boost::geometry::index::rtree时,用特化来让其支持自己的数据类型
c++·开源
AI服务老曹3 小时前
不仅能够实现前后场的简单互动,而且能够实现人机结合,最终实现整个巡检流程的标准化的智慧园区开源了
大数据·人工智能·深度学习·物联网·开源
william8233 小时前
Information Server 中共享开源服务中 kafka 的__consumer_offsets目录过大清理
分布式·kafka·开源
MicrosoftReactor3 小时前
技术速递|.NET MAUI 欢迎 Syncfusion 开源贡献
开源·.net
_xaboy6 小时前
开源项目低代码表单设计器FcDesigner扩展自定义的容器组件.例如col
vue.js·低代码·开源·动态表单·formcreate·低代码表单·可视化表单设计器
_xaboy6 小时前
开源项目低代码表单设计器FcDesigner扩展自定义组件
vue.js·低代码·开源·动态表单·formcreate·可视化表单设计器
SafePloy安策16 小时前
ES信息防泄漏:策略与实践
大数据·elasticsearch·开源