Golang多语言编程实践与技巧
Golang多语言编程实践与技巧
我已经为多语言网站的问题困扰了一段时间。据我了解,实现这个功能有很多种方法。我发现了一种使用 GitHub - leonelquinteros/gotext: Go (Golang) GNU gettext utilities package 的方法。在我看来,这似乎比 golang.org/x/text 更简单。
如果有人能审阅我的代码并告诉我是否走对了方向,我将不胜感激。
Go Playground - The Go Programming Language
实时预览
在 Go 模板内部翻译文本
更多关于Golang多语言编程实践与技巧的实战教程也可以访问 https://www.itying.com/category-94-b0.html
整体看起来不错,我有几点建议:移除 init() 函数,或许可以考虑使用 GitHub - nicksnyder/go-i18n: Translate your Go program into multiple languages.,但这很大程度上是个人偏好。过去我处理国际化(i18n)时只使用过 Hugo(它是最简单的选择)。
我看到一个可以改进的地方:你可以使用 go:embed 指令配合 embed.FS 来嵌入你的公共静态资源/模板文件。这样,最终生成的二进制文件就可以独立运行,并包含 locale/ 目录下的文件。
另外,如果你只是从映射(map)中读取数据,那么就不需要互斥锁(mutex)。我不会建议在 HTTP 处理器中使用非线程安全的内存映射并进行读写操作,因为数据量最终可能会增长。你需要的可能是一个类似线程安全的 LRU(最近最少使用)缓存的东西(如果你继续采用这个库和方法,在某个时间点你将需要对映射或缓存进行数据淘汰)。可以参考这个库:GitHub - hashicorp/golang-lru: Golang LRU cache。
// 示例代码:使用 embed.FS
package main
import "embed"
//go:embed locale/*
var localeFS embed.FS
更多关于Golang多语言编程实践与技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢您的建议。
MrWormHole: 我会做的是移除 init(),或许可以考虑使用 [GitHub - nicksnyder/go-i18n。
init{} 函数会在内存中创建一个映射变量,除此之外还有其他作用。所以我真的不知道该如何替换它。从一开始我就对使用哪种解决方案感到困惑。有几种方法可以选择。golang/x 看起来更复杂,而 go-i18n 使用 .toml 文件,这看起来和 .po 文件很接近,但是因为 .po 文件可以编译成 .mo 文件,所以可能更快?与 leonelquinteros/gotext 相比,go-i18n 有什么优势?
我能看到的一个可以改进的方面是,你可以使用
go:embed配合 embed.FS 来处理你的公共静态资源/模板,这样你的最终二进制文件就可以独立包含locale/文件。
我可能会使用 go:embed 来处理本地化翻译文件夹。但是对于 HTML 内容,我仍然犹豫不决。主要是因为将来它可能包含大量文件,并且将无法再在服务器上即时对错误进行细微编辑。
如果你只是从映射中读取数据,那么你也不需要互斥锁。
您的意思是使用映射时不需要加锁/解锁吗?
我不会在内存中使用不安全的映射并在 HTTP 处理程序中读写,因为它最终会增长,你可能需要的是类似线程安全的 LRU(最近最少使用)缓存。
那么 var translations map[string]*gotext.Po 是一个内存中的不安全映射吗?
使用 gotext 包处理多语言翻译是常见且有效的方案。以下是基于你代码的优化示例,展示如何正确配置和使用:
package main
import (
"fmt"
"html/template"
"net/http"
"github.com/leonelquinteros/gotext"
)
func init() {
// 配置本地化目录结构
gotext.Configure("locales", "en_US", "default")
}
func main() {
http.HandleFunc("/", homeHandler)
http.ListenAndServe(":8080", nil)
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
// 从请求中获取语言参数
lang := r.URL.Query().Get("lang")
if lang == "" {
lang = "en_US"
}
// 创建指定语言的locale对象
locale := gotext.NewLocale("locales", lang)
locale.AddDomain("default")
// 模板函数映射
funcMap := template.FuncMap{
"translate": func(s string) string {
return locale.Get(s)
},
}
// 解析模板
tmpl := template.Must(template.New("home").Funcs(funcMap).Parse(`
<!DOCTYPE html>
<html>
<body>
<h1>{{"Welcome" | translate}}</h1>
<p>{{"Hello, world!" | translate}}</p>
<p>{{translate "Current language"}}: {{.Language}}</p>
</body>
</html>
`))
// 执行模板
data := struct {
Language string
}{
Language: lang,
}
tmpl.Execute(w, data)
}
目录结构示例:
project/
├── main.go
└── locales/
├── en_US/
│ └── default.po
├── es_ES/
│ └── default.po
└── zh_CN/
└── default.po
PO文件内容示例(locales/en_US/default.po):
msgid "Welcome"
msgstr "Welcome"
msgid "Hello, world!"
msgstr "Hello, world!"
msgid "Current language"
msgstr "Current language"
关键改进点:
- 使用
gotext.NewLocale动态创建locale实例 - 通过模板函数
translate在模板内直接调用翻译 - 支持通过URL参数动态切换语言
- 符合标准的gettext目录结构
访问示例:
- 英文:
http://localhost:8080/?lang=en_US - 中文:
http://localhost:8080/?lang=zh_CN
这种方法比 golang.org/x/text 更轻量,特别适合Web应用的多语言需求。

