go-playground / validator

:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
MIT License
16.14k stars 1.29k forks source link

There's no translation for rule "startswith" #1167

Open filbertmangiri opened 10 months ago

filbertmangiri commented 10 months ago

Package version eg. v9, v10: v10

Issue, Question or Enhancement:

There's no translation for rule "startswith". I don't know if there are other rules that don't have their own translation, but what i found for now is "startswith".

Is there a way to make my own translation so that the validator firstly look if I have custom translation, and if a rule is not registered in there, then find it in default "en" translation?

Code sample, to showcase or reproduce:

type CreateUserValidation struct {
    Username    string  `json:"username"    validate:"required,min=5,max=50,username,unique=users"`
    Phone       *string `json:"phone"       validate:"omitempty,numeric,startswith=08,unique=users"`
}

Response:

{
    "errors": {
        "phone": "Key: 'CreateUserValidation.phone' Error:Field validation for 'phone' failed on the 'startswith' tag",
        "username": "username is a required field"
    }
}

Validation helper code:

package helper

import (
    "reflect"
    "strings"

    "github.com/filbertmangiri/intecs-api/app/rules"
    "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 validation struct{}

var Validation = &validation{}

var validate *validator.Validate
var uni *ut.UniversalTranslator
var trans ut.Translator

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

    trans, _ = uni.GetTranslator("en")

    validate = validator.New()

    en_translations.RegisterDefaultTranslations(validate, trans)

    for _, rule := range rules.CustomRules {
        validate.RegisterValidation(rule.Tag, rule.Function)
    }

    validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]

        if name == "-" {
            return ""
        }

        return name
    })
}

type ValidationErrors map[string]any

func (*validation) ValidateStruct(s interface{}) ValidationErrors {
    if err := validate.Struct(s); err != nil {
        validationErrors := make(ValidationErrors)

        for _, validationError := range err.(validator.ValidationErrors) {
            validationErrors[validationError.Field()] = validationError.Translate(trans)
        }

        return validationErrors
    }

    return nil
}