go-i18n需手动加载符合BCP 47规范的JSON语言文件,通过Accept-Language解析+URL参数校验确定语言,模板中须用带context的Localizer实例调用T函数,缺失翻译时需显式fallback而非依赖自动降级。

如何用 go-i18n 加载多语言 JSON 文件
Go 官方标准库不提供开箱即用的国际化(i18n)支持,社区主流方案是使用 go-i18n(v2 版本,对应模块名 github.com/nicksnyder/go-i18n/v2/i18n)。它依赖结构化的 JSON 文件描述翻译内容,每个语言一个文件,如 active.en-US.json、active.zh-CN.json。
关键点在于:文件必须放在可被 i18n.NewBundle 读取的路径下,且需显式调用 bundle.LoadMessageFile;不能只靠文件名自动加载。
-
LoadMessageFile返回error,但常见错误(如文件不存在、JSON 格式错误)不会 panic,容易被忽略——务必检查返回值 - 文件名中的语言标签必须符合 BCP 47 规范(如
zh-CN而非zh_CN),否则bundle.FindMessage可能静默失败 - JSON 中的
id字段是查找键(不是translation文本本身),例如:{ "id": "welcome_message", "translation": "Hello, {{.Name}}!" }
如何在 HTTP 请求中解析并传递用户语言偏好
浏览器通过 Accept-Language 请求头告知服务端语言偏好,但该字段可能含多个带权重的标签(如 zh-CN,zh;q=0.9,en;q=0.8),不能直接取第一个。
推荐用 golang.org/x/net/webdav/acceptlang(轻量无依赖)或手动解析:提取所有标签 → 过滤出已支持的语言 → 按权重排序 → 取首个匹配项。不要硬编码 strings.Split(r.Header.Get("Accept-Language"), ",")[0]。
立即学习“go语言免费学习笔记(深入)”;
网奇Eshop是一个带有国际化语言支持的系统,可以同时在一个页面上显示全球任何一种语言而没有任何障碍、任何乱码。在本系统中您可以发现,后台可以用任意一种语言对前台进行管理、录入而没有阻碍。而任何一个国家的浏览者也可以用他们的本国语言在你的网站上下订单、留言。用户可以通过后台随意设定软件语言,也就是说你可以用本软件开设简体中文、繁体中文与英文或者其他语言的网上商店。网奇Eshop系统全部版本都使用模
- 若用户未发送
Accept-Language,应 fallback 到默认语言(如en-US),而非空字符串 - 允许 URL 参数覆盖(如
?lang=ja-JP),但需校验该值是否在白名单中,防止目录遍历或无效语言导致 panic - 将解析出的语言标识存入
context.Context,避免在 handler 各处重复解析
如何在模板中安全调用翻译函数
Go 的 html/template 不支持直接传入函数闭包,所以不能把 localizer.Localize 直接塞进 template.FuncMap 并期望它“记住”当前请求语言。必须为每次渲染构造带上下文的 localizer 实例。
典型做法:在 handler 内创建 *i18n.Localizer,绑定当前语言,再将其方法包装为模板函数:
func makeTemplateFuncs(loc *i18n.Localizer) template.FuncMap {
return template.FuncMap{
"T": func(id string, args ...interface{}) template.HTML {
msg, _ := loc.Localize(&i18n.LocalizeConfig{
MessageID: id,
TemplateData: map[string]interface{}{"Args": args},
})
return template.HTML(msg)
},
}
}
-
Localize可能返回空字符串或原始id(当翻译缺失时),前端显示前建议加 fallback 提示(如[missing: {{.ID}}]) - 模板中插值参数(如
{{.Name}})需与TemplateData键名严格一致,大小写敏感 - 避免在模板里做语言切换逻辑——所有语言决策应在 handler 层完成
为什么 Localize 有时返回空字符串而不是默认语言文本
这不是 bug,而是设计行为:Localize 默认只查找当前语言的翻译,不自动 fallback 到 bundle 默认语言(即使你调用了 bundle.SetDefaultLanguage)。要启用 fallback,必须显式设置 LocalizeConfig.DefaultMessage 或启用 bundle.RegisterUnmarshalFunc 配合多级 fallback 策略。
- 最简 fallback 方式:捕获
Localize返回空时,再用默认语言 localizer 重试一次 - 复杂场景(如支持
zh-Hans→zh-CN→en-US多级 fallback)需自定义i18n.LanguageTag解析逻辑,不能依赖bundle.FindMessage自动降级 - 测试时容易漏掉“翻译缺失”分支——建议用
go-i18n自带的i18n.MustT(panic on missing)辅助开发期发现遗漏
语言切换不是加几个 JSON 就完事,真正难的是 fallback 策略的一致性、模板上下文隔离、以及错误路径的可观测性。别让一个没定义的 id 让整页变空白。









