Validator: 错误消息自动转换问题

Created on 30 Sep 2019  ·  8Comments  ·  Source: go-playground/validator

Package version eg. v9:

我想请问一下,如何将下图红框中文字 :
"Email" 自动转成 "邮箱"
"Id" 自动转成 "用户id"

Issue, Question or Enhancement:

image

Code sample, to showcase or reproduce:

package model

import (
    "fmt"
    "github.com/go-playground/locales/zh"
    ut "github.com/go-playground/universal-translator"
    "github.com/sirupsen/logrus"
    "gopkg.in/go-playground/validator.v9"
    zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
)

// 表单验证
// https://github.com/go-playground/validator
var (
    uni      *ut.UniversalTranslator
    Validate *validator.Validate
    ValidateTrans ut.Translator
)

func init()  {
    zh2 := zh.New()
    uni = ut.New(zh2, zh2)

    ValidateTrans, _ = uni.GetTranslator("zh")

    Validate = validator.New()
    if err := zh_translations.RegisterDefaultTranslations(Validate, ValidateTrans); err != nil{
        logrus.Error(err)
    }
}

//  验证表单结构体
func ValidateModelFn(mod interface{}) (b bool, errMsg validator.ValidationErrorsTranslations) {
    err := Validate.Struct(mod)
    if err != nil {
        errs := err.(validator.ValidationErrors)
        errMsg = errs.Translate(ValidateTrans)
    } else {
        b = true
    }
    return
}
question

Most helpful comment

@learnku 你可以通过在结构体中加入标签来实现,我就自定义了一个comment的标签,然后使用标签中的内容替换掉验证器中的字段,这样就可以实现你所需要的那种,翻译器是翻译不了字段的(你想嘛,那么多语言不可能全部进行翻译的),只能翻译出现错误的错误信息。我写在了我的模板里面,希望能帮到你。https://github.com/LinkinStars/golang-web-template/blob/master/src/gwt/base/validator/validator.go



I solve the problem by adding custom tag on struct that need to be validated.

validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
    return fld.Tag.Get("comment")
})
type AddUserReq struct {
    Username string `validate:"required,gt=6,lt=16" comment:"用户名" json:"username"`
    Nickname string `validate:"omitempty,gt=6,lt=16" comment:"昵称" json:"nickname"`
    Age int `validate:"required,min=5,max=99" comment:"年龄" json:"age"`
}

It will read the tag 'comment' and replace the filed name.

All 8 comments

Hey @learnku you should be able to register your own translation like so https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go#L105

Or if this is a more of a one-off you could dissect the errors yourself to build whatever message/response you're looking for like so https://github.com/go-playground/validator/blob/v9/_examples/simple/main.go#L69

please let me know if this helps.

@learnku 你可以通过在结构体中加入标签来实现,我就自定义了一个comment的标签,然后使用标签中的内容替换掉验证器中的字段,这样就可以实现你所需要的那种,翻译器是翻译不了字段的(你想嘛,那么多语言不可能全部进行翻译的),只能翻译出现错误的错误信息。我写在了我的模板里面,希望能帮到你。https://github.com/LinkinStars/golang-web-template/blob/master/src/gwt/base/validator/validator.go



I solve the problem by adding custom tag on struct that need to be validated.

validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
    return fld.Tag.Get("comment")
})
type AddUserReq struct {
    Username string `validate:"required,gt=6,lt=16" comment:"用户名" json:"username"`
    Nickname string `validate:"omitempty,gt=6,lt=16" comment:"昵称" json:"nickname"`
    Age int `validate:"required,min=5,max=99" comment:"年龄" json:"age"`
}

It will read the tag 'comment' and replace the filed name.

@learnku 你可以通过在结构体中加入标签来实现,我就自定义了一个comment的标签,然后使用标签中的内容替换掉验证器中的字段,这样就可以实现你所需要的那种,翻译器是翻译不了字段的(你想嘛,那么多语言不可能全部进行翻译的),只能翻译出现错误的错误信息。我写在了我的模板里面,希望能帮到你。https://github.com/LinkinStars/golang-web-template/blob/master/src/gwt/base/validator/validator.go

I solve the problem by adding custom tag on struct that need to be validated.

validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
  return fld.Tag.Get("comment")
})
type AddUserReq struct {
  Username string `validate:"required,gt=6,lt=16" comment:"用户名" json:"username"`
  Nickname string `validate:"omitempty,gt=6,lt=16" comment:"昵称" json:"nickname"`
  Age int `validate:"required,min=5,max=99" comment:"年龄" json:"age"`
}

It will read the tag 'comment' and replace the filed name.

但是eqfield的时候,A eqfield B,A可以获得自定义的tag,B无法,就会出现,密码必须等于ConfirmPassword

@Eternity-SXH 这个就木有办法了,你只能自己写方法去验证了,因为翻译的时候也只是将错误信息进行处理,而错误信息里面给到的第二个参数就是字段英文的名称,而且这个入参是有意义的,其他地方也用到了,错误信息里面也没有保存第二个参数的其他信息。注意下方zh.go的fe.Param()),可能还有很多跨字段验证的翻译也是一样的,所以还是得自己写。

{
    tag:         "eqfield",
    translation: "{0}必须等于{1}",
    override:    false,
    customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {

        t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
        if err != nil {
            log.Printf("警告: 翻译字段错误: %#v", fe)
            return fe.(error).Error()
        }

        return t
    },
},

Hey deankarn, what Eternity-SXH's said means when using 'eqfield' tag the second field name is the StructName without Translate. In my opinion maybe do 'eqfield' validate by self is the only way to solve. Because fe.Param() return the StructName only.

@LinkinStars @leafduo 其实用RegisterTagNameFunc方法注册个tag时, 内容部分是对了. 不过把json的key也给改了.. @learnku 最初列子就变成:

msg: {
  "User.邮箱": "邮箱必须为有效的邮箱",
  "User.用户id": "用户id为必填字段"
}

json 的key可以改吗? 最终显示方式如下是最佳的:

msg: {
  "email": "邮箱必须为有效的邮箱",
  "id": "用户id为必填字段"
}

@LinkinStars @leafduo 其实用RegisterTagNameFunc方法注册个tag时, 内容部分是对了. 不过把json的key也给改了.. @learnku 最初列子就变成:

msg: {
  "User.邮箱": "邮箱必须为有效的邮箱",
  "User.用户id": "用户id为必填字段"
}

json 的key可以改吗? 最终显示方式如下是最佳的:

msg: {
  "email": "邮箱必须为有效的邮箱",
  "id": "用户id为必填字段"
}

没遇到这样的问题,可能是哪里设置错了,show me your code.

@LinkinStars @leafduo 其实用RegisterTagNameFunc方法注册个tag时, 内容部分是对了. 不过把json的key也给改了.. @learnku 最初列子就变成:

msg: {
  "User.邮箱": "邮箱必须为有效的邮箱",
  "User.用户id": "用户id为必填字段"
}

json 的key可以改吗? 最终显示方式如下是最佳的:

msg: {
  "email": "邮箱必须为有效的邮箱",
  "id": "用户id为必填字段"
}

https://github.com/go-playground/validator/issues/633#issuecomment-654382345 maybe help

func ResponseValidateError(ctx *gin.Context, errs validator.ValidationErrors, request interface{}) {

    var errList = make(map[string]string, len(errs))

    for _, err := range errs {
        // 获取原来的标签 - json
        fieldName := err.StructField()
        t := reflect.TypeOf(request)
        field, _ := t.FieldByName(fieldName)
        j := field.Tag.Get("json")

        // 修改
        errList[j] = err.Translate(Trans)
    }

    fmt.Println(errList)

    ctx.JSON(http.StatusUnprocessableEntity, gin.H{
        "errorCode":    100422,
        "errorMessage": errList,
    })
}
Was this page helpful?
0 / 5 - 0 ratings