Spaces:
Configuration error
Configuration error
File size: 4,640 Bytes
b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 602f6ba b0f0dc1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | package validation
import (
"errors"
"fmt"
"strings"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/id"
ut "github.com/go-playground/universal-translator"
v10 "github.com/go-playground/validator/v10"
entranslations "github.com/go-playground/validator/v10/translations/en"
idtranslations "github.com/go-playground/validator/v10/translations/id"
)
// Constants for supported locales
const (
LocaleID = "id"
LocaleEN = "en"
)
// ErrorMessage represents a validation error message
type ErrorMessage struct {
Field string `json:"field"`
Message string `json:"-"`
}
type validator struct {
validate *v10.Validate
translator ut.Translator
}
// validatorInstance adalah instance global dari validator.
var validatorInstance *validator
// New creates a new validation instance with the specified locale
// dan menginisialisasi instance global validatorInstance.
func New(locale string) error {
v := &validator{}
parsedLocale := parseLocale(locale)
uni := ut.New(en.New(), id.New(), en.New())
translator, found := uni.GetTranslator(parsedLocale)
if !found {
return fmt.Errorf("translator not found for locale: %s", parsedLocale)
}
validate := v10.New()
if err := setupValidations(validate); err != nil {
return fmt.Errorf("failed to setup validations: %w", err)
}
if err := setupTranslations(validate, translator, parsedLocale); err != nil {
return fmt.Errorf("failed to setup translations for locale %s: %w", parsedLocale, err)
}
v.validate = validate
v.translator = translator
validatorInstance = v // Inisialisasi instance global
return nil
}
func parseLocale(locale string) string {
switch strings.ToLower(locale) {
case "id":
return LocaleID
case "en":
return LocaleEN
default:
return LocaleID // Default to Indonesian
}
}
// setupValidations configures custom validation rules.
func setupValidations(validate *v10.Validate) error {
rules := NewValidatorRules(&InMemoryOptionSource{})
if err := rules.RegisterAllCustomRules(validate); err != nil {
return err
}
return nil
}
// setupTranslations configures translations for validation messages.
func setupTranslations(validate *v10.Validate, translator ut.Translator, locale string) error {
// Register default translations based on locale
if err := registerDefaultTranslations(validate, translator, locale); err != nil {
return fmt.Errorf("failed to register default translations for locale %s: %w", locale, err)
}
// Register custom password validation translation
err := validate.RegisterTranslation("password", translator,
func(ut ut.Translator) error {
return ut.Add("password", "harus mengandung minimal 8 karakter, huruf besar, huruf kecil, dan angka.", true)
},
func(ut ut.Translator, fe v10.FieldError) string {
translated, err := ut.T(fe.Tag(), fe.Field())
if err != nil {
return fe.Field() + " is invalid"
}
return translated
},
)
if err != nil {
return fmt.Errorf("failed to register password translation: %w", err)
}
return nil
}
// registerDefaultTranslations sets up default translations for the specified locale.
func registerDefaultTranslations(validate *v10.Validate, translator ut.Translator, locale string) error {
switch locale {
case LocaleID:
return idtranslations.RegisterDefaultTranslations(validate, translator)
case LocaleEN:
return entranslations.RegisterDefaultTranslations(validate, translator)
default:
// Fallback to English if the locale is not supported
return entranslations.RegisterDefaultTranslations(validate, translator)
}
}
// Validate validates a struct using the global validator instance
// and returns a slice of ErrorMessage.
func Validate(s any) []ErrorMessage {
if validatorInstance == nil {
return []ErrorMessage{{Field: "", Message: "Validator belum diinisialisasi. Panggil validation.New() terlebih dahulu."}}
}
err := validatorInstance.validate.Struct(s)
if err != nil {
return TranslateError(err)
}
return nil
}
// TranslateError takes a validation error and translates it using the global translator.
func TranslateError(err error) []ErrorMessage {
if validatorInstance == nil {
return nil
}
var validationErrors v10.ValidationErrors
if !errors.As(err, &validationErrors) {
return nil
}
errorMessages := make([]ErrorMessage, 0, len(validationErrors))
for _, e := range validationErrors {
fieldLabel := e.Field()
msg, err := validatorInstance.translator.T(e.Tag(), fieldLabel)
if err != nil {
msg = fieldLabel + " is Invalid"
}
errorMessages = append(errorMessages, ErrorMessage{
Field: e.Tag(),
Message: msg,
})
}
return errorMessages
}
|