跳到主要内容

在 Gin 中使用 Validator 进行多语言验证

安装必要的依赖包

为了在 Gin 框架中实现多语言的验证,需要安装以下依赖包:

go get -u github.com/go-playground/locales
go get -u github.com/go-playground/universal-translator

这些包提供了本地化和翻译功能,配合 validator 使用,可以实现错误信息的多语言支持。

创建和使用翻译器与验证器

使用翻译器和验证器可以帮助我快速完成代码逻辑,提升开发效率。下面是具体的实现步骤。

编写示例代码

以下是一个完整的示例代码,演示如何在 Gin 中集成 validator 和翻译器,实现多语言的错误信息提示:

package main

import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
entranslations "github.com/go-playground/validator/v10/translations/en"
zhtranslations "github.com/go-playground/validator/v10/translations/zh"
"net/http"
"reflect"
)

var trans ut.Translator

type Register struct {
Username string `json:"username" binding:"required,max=10,min=5"`
Password string `json:"password" binding:"required,max=10,min=5"`
}

func main() {
r := gin.Default()

if err := initTrans("zh"); err != nil {
fmt.Println("无法创建翻译器")
return
}

r.POST("/register", func(c *gin.Context) {
var reg Register

if err := c.ShouldBindJSON(&reg); err != nil {
errs, ok := err.(validator.ValidationErrors)
if !ok {
c.JSON(http.StatusOK, gin.H{
"code": 1,
"msg": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"code": 1001,
"msg": errs.Translate(trans),
})
return
}

c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "success",
"data": reg,
})
})

r.Run()
}

func initTrans(locale string) error {
validate, ok := binding.Validator.Engine().(*validator.Validate)
if !ok {
fmt.Println("Validator类型断言失败")
return fmt.Errorf("Validator类型断言失败")
}

// 注册一个获取 json 标签作为字段名的方法
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := fld.Tag.Get("json")
if name == "" {
return fld.Name
}
return name
})

zhT := zh.New()
enT := en.New()
uni := ut.New(enT, zhT, enT)

var found bool
trans, found = uni.GetTranslator(locale)
if !found {
fmt.Printf("找不到语言%s的翻译器\n", locale)
return fmt.Errorf("找不到语言%s的翻译器", locale)
}

switch locale {
case "zh":
err := zhtranslations.RegisterDefaultTranslations(validate, trans)
if err != nil {
return err
}
case "en":
err := entranslations.RegisterDefaultTranslations(validate, trans)
if err != nil {
return err
}
default:
fmt.Printf("不支持的语言类型%s\n", locale)
return fmt.Errorf("不支持的语言类型%s", locale)
}

return nil
}

代码解析

  • 结构体定义

    定义了一个 Register 结构体,用于接收注册信息,并在结构体标签中使用了验证规则 requiredmax=10min=5

  • 初始化翻译器

    main 函数中,调用了 initTrans("zh") 函数,初始化中文翻译器。

  • 路由处理

    在路由处理函数中,使用 ShouldBindJSON 将请求体绑定到 reg 结构体。如果发生错误,检查是否是验证错误类型,如果是,则使用 errs.Translate(trans) 将错误信息翻译成中文并返回给客户端。

  • 翻译器初始化函数

    initTrans 函数用于初始化翻译器。首先,断言 binding.Validator.Engine() 是否为 *validator.Validate 类型。然后,注册了一个 RegisterTagNameFunc,使验证器在返回错误时使用 json 标签作为字段名。

    接下来,创建了中文和英文的翻译器,并使用 ut.New 创建了一个通用翻译器 uni。根据传入的语言参数 locale,获取对应的翻译器,并注册相应语言的默认翻译。

最佳实践

  • 全面的错误处理

    在绑定和验证时,都要处理可能出现的错误,确保程序的健壮性。

  • 友好的错误信息

    使用 json 标签作为字段名,可以使返回的错误信息更加友好,直接显示前端传递的字段名。

  • 多语言支持

    通过传入不同的 locale,可以支持多种语言的错误信息,提升用户体验。

  • 易读的变量名

    使用简洁易懂的变量名,例如将 register 简化为 reg,提高代码的可读性。

注意事项

  • 在使用 validator 和翻译器时,要确保版本兼容,不要随意更改包的版本。

  • 变量名应尽量简洁明了,避免使用难以理解的缩写。

  • 避免在代码和注释中使用冒号,提升代码规范性。

  • 在实际应用中,可以根据需求动态设置 locale,实现客户端自行选择语言的功能。

相关链接

go-playground/validator Translations 示例