package validator import ( "encoding/json" "errors" "fmt" "sync" "github.com/gin-gonic/gin/binding" "github.com/go-playground/locales/zh" uTrans "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" ) const ( local = "zh" ) func NewValidator() binding.StructValidator { return &customValidator{} } type customValidator struct { once sync.Once validate *validator.Validate translator uTrans.Translator } func (c *customValidator) ValidateStruct(obj interface{}) error { c.lazyinit() if err := c.validate.Struct(obj); err != nil { return c.translate(err) } return nil } func (c *customValidator) Engine() any { c.lazyinit() return c.validate } func (c *customValidator) lazyinit() { c.once.Do(func() { c.validate = validator.New() c.validate.SetTagName("binding") if err := c.setTrans(); err != nil { fmt.Printf("setTrans fail %s", err.Error()) } if err := c.registerValidation(); err != nil { fmt.Printf("registervalidation fail:%s", err.Error()) } }) } // 暂时写死英文翻译中文,todo 根据IP或者根据请求头语言决定翻译 func (c *customValidator) setTrans() error { zh := zh.New() uni := uTrans.New(zh, zh) trans, exist := uni.GetTranslator(local) if !exist { return fmt.Errorf("uni.GetTranslator %s fail", local) } c.translator = trans switch local { case "en": if err := enTranslations.RegisterDefaultTranslations(c.validate, c.translator); err != nil { return fmt.Errorf("enTranslations fail:%s", err.Error()) } case "zh": if err := zhTranslations.RegisterDefaultTranslations(c.validate, c.translator); err != nil { return fmt.Errorf("zhTranslations fail:%s", err.Error()) } default: if err := zhTranslations.RegisterDefaultTranslations(c.validate, c.translator); err != nil { return fmt.Errorf("zhTranslations fail:%s", err.Error()) } } return nil } func (c *customValidator) registerValidation() error { if err := c.validate.RegisterValidation("tableName", tableName); err != nil { return err } return nil } func (c *customValidator) translate(err error) error { if errs, ok := err.(validator.ValidationErrors); ok { tErrMap := errs.Translate(c.translator) if tErrMap != nil { if errMsg, errTmp := json.Marshal(tErrMap); errTmp == nil { return errors.New(string(errMsg)) } else { return fmt.Errorf("validator translate json marshal fail:%s", errTmp) } } // todo 根据定制tag,输出定制的msg // todo 翻译后的错误消息按另外的规则输出(当前json) } return err }