package main import ( "errors" "fmt" "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" en_translations "github.com/go-playground/validator/v10/translations/en" ) type Validator struct { validate *validator.Validate trans ut.Translator } type Translation struct { format string params func(fe validator.FieldError) []any } var translations = map[string]Translation{ "oneof": { "{0} must be one of [{1}], got '{2}'", func(fe validator.FieldError) []any { return []any{fe.Field(), fe.Param(), fe.Value()} }, }, } func NewValidator() (*Validator, error) { validate := validator.New(validator.WithRequiredStructEnabled()) language := en.New() translator := ut.New(language, language) trans, ok := translator.GetTranslator("en") if !ok { return nil, fmt.Errorf("Could not find translator to print error meesage") } en_translations.RegisterDefaultTranslations(validate, trans) for validation, translation := range translations { validate.RegisterTranslation(validation, trans, func(ut ut.Translator) error { return ut.Add(validation, translation.format, true) }, func(ut ut.Translator, fe validator.FieldError) string { params := translation.params(fe) stringParams := make([]string, len(params)) for i, param := range params { stringParams[i] = fmt.Sprintf("%s", param) } t, _ := ut.T(validation, stringParams...) return t }) } return &Validator{ validate: validate, trans: trans, }, nil } func (v Validator) ValidateStruct(s interface{}) error { err := v.validate.Struct(s) return v.Translate(err) } func (v Validator) Translate(err error) error { if err == nil { return err } errs, ok := err.(validator.ValidationErrors) if !ok { return err } errorList := make([]error, 0) for _, e := range errs { errorList = append(errorList, fmt.Errorf("%s", e.Translate(v.trans))) } return errors.Join(errorList...) }