Spaces:
Configuration error
Configuration error
| 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 | |
| } | |