Fiber框架本身不内置i18n支持,必须依赖go-playground/universal-translator(ut)配合自定义中间件实现:优先从Accept-Language头解析语言,其次查URL参数或cookie;需显式注册各语言翻译模板、复数/性别规则,并将translator实例安全绑定到ctx.Locals供handler和validator共用。

Fiber 框架本身不内置 i18n 支持,必须依赖第三方库组合实现 —— 最常用、最可靠的方式是用 go-playground/universal-translator(简称 ut)配合自定义中间件和请求上下文传递语言标识。
为什么不用 fiber-i18n 这类封装库
社区里确实存在几个叫 fiber-i18n 的小众封装,但它们大多:
- 不维护(最新 commit 超过 2 年)
- 硬编码依赖旧版 universal-translator(如 v0.17.x),而当前主流是 v0.24+
- 缺少对复数规则(plural)、性别(gender)、嵌套键(user.profile.name)的完整支持
- 把翻译器实例挂到 ctx.Locals,但没处理并发安全或 locale fallback 链路
直接集成 ut 原生 API,控制力更强,出问题时能快速定位。
如何用 universal-translator 实现多语言切换
核心是三步:加载语言包 → 创建 translator 实例 → 绑定到 HTTP 请求。关键点在于语言标识(lang)从哪来、怎么 fallback:
- 优先从请求头
Accept-Language解析,用ut.New()自动匹配最接近的已注册语言 - 其次检查 URL 查询参数(如
?lang=zh-CN)或 cookie(lang=ja),显式调用t.ResetLang(lang) - 必须设置 fallback:比如用户传
zh-TW,但你只注册了zh-CN,就要靠ut.WithFallback(自动降级) - 翻译函数不能全局复用:每个请求需调用
t.T(r.Context(), "login.failed"),其中t是从 context 取出的 *ut.Translator 实例
示例片段(非完整初始化):
// 加载简体中文和英文
zh := ut.New(zhLang, enLang)
trans, _ := zh.GetTranslator("zh-CN")
<p>// 在中间件中绑定到 ctx
app.Use(func(c *fiber.Ctx) error {
lang := c.Query("lang", c.Get("Accept-Language", "en-US"))
t, _ := zh.GetTranslator(lang)
c.Locals("translator", t)
return c.Next()
})</p><p>// 在 handler 中使用
app.Get("/login", func(c <em>fiber.Ctx) error {
t := c.Locals("translator").(</em>ut.Translator)
msg := t.T(c.Context(), "login.failed", "username", "admin")
return c.JSON(fiber.Map{"message": msg})
})
</p>
validator 错误消息怎么同步国际化
如果你用 go-playground/validator 做参数校验,它的错误翻译完全依赖 universal-translator —— 关键是把同一个 *ut.Translator 实例传给 validator 的 RegisterTranslation 和 Translations 方法:
- 每种语言都要单独调用
RegisterTranslation注册错误模板,比如"required"对应"{{.FieldName}} 是必填项" - validator 的
StructLevel或字段级Validation错误,会自动走t.T()流程,无需额外包装 - 注意:validator v10+ 的
Validate.StructCtx接收context.Context,要确保该 context 包含 locale 信息(比如用context.WithValue注入)
漏掉 RegisterTranslation 就会导致 validator 返回英文原错,即使你已经绑定了中文 translator。
容易被忽略的细节:复数和上下文敏感翻译
真实项目里,像 “删除了 1 个用户” 和 “删除了 5 个用户” 必须用不同文案,universal-translator 支持但默认不启用:
- 注册语言时必须传
ut.WithFuncs(...)启用复数函数,例如ut.PluralRuleChinese或ut.PluralRuleEnglish - 翻译键需带复数后缀,如
user.deleted.one/user.deleted.other,调用时传入 count:t.T(ctx, "user.deleted", 5) - 性别相关文案(如 “他已登录” / “她已登录”)需要在 key 中显式声明
gender=male,并注册对应规则函数 - 所有语言包 JSON 文件必须 UTF-8 编码且无 BOM,否则
ut.LoadJSON会静默失败
这些能力不是开箱即用的,必须手动配置函数和键命名规范,否则 fallback 到默认语言时可能返回空字符串或原始 key。











