Go validator 默认错误为英文,因其错误模板硬编码且无语言上下文;需初始化UniversalTranslator、获取目标语言translator、注册翻译模板,并显式调用Translate()才能返回中文提示。

Go 的 validator 默认错误消息是硬编码英文,不自动走翻译流程;要显示中文等本地化提示,必须显式注册翻译器并调用 Translate() 方法——缺一不可。
validator 错误为什么默认是英文?
因为 go-playground/validator/v10 内部的错误模板(如 "field validation for '{0}' failed on the '{1}' tag")是纯字符串硬编码,没有语言上下文,也不读取任何配置。你看到的“英文”,只是未翻译时的 fallback 文本,不是设计成英文,而是根本没翻译。
真正触发翻译的是 ValidationErrors.Translate(trans) 这一步:它把 FieldError.Tag()、FieldError.Field()、FieldError.Param() 映射到预注册的语言模板里,再做变量替换(比如把 {0} 替换成字段名,{1} 替换成最小长度值)。
- 不调用
Translate()→ 永远输出英文原样 - 没注册目标语言的 translator(如
zh)→Translate()静默回退到英文 -
translatable这类自定义 tag 不会被 validator 解析 —— 它只认validate标签,其余是你自己反射逻辑的事
如何让 validator 返回中文错误?
核心三步:初始化 UniversalTranslator、获取目标语言 Translator、注册翻译模板。顺序不能错,参数不能漏。
立即学习“go语言免费学习笔记(深入)”;
- 导入中文包:
github.com/go-playground/validator/v10/translations/zh - 创建 translator:
zh := zh.New(); uni := ut.New(zh); trans, _ := uni.GetTranslator("zh") - 注册翻译:
zh_translations.RegisterDefaultTranslations(validate, trans)—— 注意传的是validate *validator.Validate实例,不是trans - 校验后必须显式转换:
errs.Translate(trans),否则还是英文
示例片段:
type User struct {
Email string `json:"email" validate:"required,email"`
}
u := User{}
err := validate.Struct(u)
if err != nil {
if errs, ok := err.(validator.ValidationErrors); ok {
msg := errs.Translate(trans) // trans 是已注册的中文 translator
fmt.Println(msg) // 输出:"Email为必填项;Email格式无效"
}
}
Gin 中按请求头动态切换语言
Validate.Struct() 本身不感知语言,语言选择完全发生在错误生成之后。HTTP 场景下,你要在 handler 里解析 Accept-Language,再动态选 translator。
- 不要全局复用一个
trans实例 —— 不同请求可能需要不同语言 - 推荐在 middleware 或 handler 开头做:
lang := c.GetHeader("Accept-Language"),然后用uni.GetTranslator(lang)获取对应实例 - 若请求头未指定或不支持,应 fallback 到默认语言(如
zh),并确保该语言已注册 - 字段别名(如把
Email显示为“邮箱”)建议用ut.Add("zh", "User.Email", "邮箱")单独注册,而不是依赖结构体 tag
最容易被忽略的是:翻译器注册和错误转换必须成对出现,且 RegisterDefaultTranslations 的第一个参数必须是正在使用的 *validator.Validate 实例 —— 换了 validator 实例却没重新注册翻译,就会静默失效。


















