diff --git a/translations/id/id.go b/translations/id/id.go index 96cd8fc16..eda1c6670 100644 --- a/translations/id/id.go +++ b/translations/id/id.go @@ -16,7 +16,6 @@ import ( // RegisterDefaultTranslations registers a set of default translations // for all built in tag's in validator; you may add your own as desired. func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { - translations := []struct { tag string translation string @@ -24,355 +23,715 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er customRegisFunc validator.RegisterTranslationsFunc customTransFunc validator.TranslationFunc }{ + // Field Tags { - tag: "required", - translation: "{0} wajib diisi", - override: false, + tag: "eqcsfield", + translation: "{0} harus sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "len", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("len-string", "panjang {0} harus {1}", false); err != nil { - return - } - - // if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("len-number", "{0} harus sama dengan {1}", false); err != nil { - return - } - - if err = ut.Add("len-items", "{0} harus berisi {1}", false); err != nil { - return - } - // if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("len-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("len-items", fe.Field(), c) - - default: - t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, + tag: "eqfield", + translation: "{0} harus sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "min", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("min-string", "panjang minimal {0} adalah {1}", false); err != nil { - return - } - - // if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("min-number", "{0} harus {1} atau lebih besar", false); err != nil { - return - } - - if err = ut.Add("min-items", "panjang minimal {0} adalah {1}", false); err != nil { - return - } - // if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { - return - } - - return + tag: "fieldcontains", + translation: "{0} harus berisi nilai dari field {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "fieldexcludes", + translation: "{0} tidak boleh berisi nilai dari field {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "gtcsfield", + translation: "{0} harus lebih besar dari {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "gtecsfield", + translation: "{0} harus lebih besar dari atau sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "gtefield", + translation: "{0} harus lebih besar dari atau sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "gtfield", + translation: "{0} harus lebih besar dari {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "ltcsfield", + translation: "{0} harus kurang dari {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "ltecsfield", + translation: "{0} harus kurang dari atau sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "ltefield", + translation: "{0} harus kurang dari atau sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "ltfield", + translation: "{0} harus kurang dari {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "necsfield", + translation: "{0} tidak sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + { + tag: "nefield", + translation: "{0} tidak sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, - var err error - var t string + // Network Tags + { + tag: "cidr", + translation: "{0} harus berupa notasi CIDR yang valid", + override: false, + }, + { + tag: "cidrv4", + translation: "{0} harus berupa notasi CIDR IPv4 yang valid", + override: false, + }, + { + tag: "cidrv6", + translation: "{0} harus berupa notasi CIDR IPv6 yang valid", + override: false, + }, + { + tag: "datauri", + translation: "{0} harus berisi URI Data yang valid", + override: false, + }, + { + tag: "fqdn", + translation: "{0} harus berupa FQDN yang valid", + override: false, + }, + { + tag: "hostname", + translation: "{0} harus berupa hostname sesuai RFC 952 yang valid", + override: false, + }, + { + tag: "hostname_port", + translation: "{0} harus berupa hostname dan port yang valid", + override: false, + }, + { + tag: "hostname_rfc1123", + translation: "{0} harus berupa hostname sesuai RFC 1123 yang valid", + override: false, + }, + { + tag: "ip", + translation: "{0} harus berupa alamat IP yang valid", + override: false, + }, + { + tag: "ip4_addr", + translation: "{0} harus berupa alamat IPv4 yang valid", + override: false, + }, + { + tag: "ip6_addr", + translation: "{0} harus berupa alamat IPv6 yang valid", + override: false, + }, + { + tag: "ip_addr", + translation: "{0} harus berupa alamat IP yang valid", + override: false, + }, + { + tag: "ipv4", + translation: "{0} harus berupa alamat IPv4 yang valid", + override: false, + }, + { + tag: "ipv6", + translation: "{0} harus berupa alamat IPv6 yang valid", + override: false, + }, + { + tag: "mac", + translation: "{0} harus berisi alamat MAC yang valid", + override: false, + }, + { + tag: "tcp4_addr", + translation: "{0} harus berupa alamat TCP IPv4 yang valid", + override: false, + }, + { + tag: "tcp6_addr", + translation: "{0} harus berupa alamat TCP IPv6 yang valid", + override: false, + }, + { + tag: "tcp_addr", + translation: "{0} harus berupa alamat TCP yang valid", + override: false, + }, + { + tag: "udp4_addr", + translation: "{0} harus berupa alamat IPv4 UDP yang valid", + override: false, + }, + { + tag: "udp6_addr", + translation: "{0} harus berupa alamat IPv6 UDP yang valid", + override: false, + }, + { + tag: "udp_addr", + translation: "{0} harus berupa alamat UDP yang valid", + override: false, + }, + { + tag: "unix_addr", + translation: "{0} harus berupa alamat UNIX yang valid", + override: false, + }, + { + tag: "uri", + translation: "{0} harus berupa URI yang valid", + override: false, + }, + { + tag: "url", + translation: "{0} harus berupa URL yang valid", + override: false, + }, + { + tag: "http_url", + translation: "{0} harus berupa URL HTTP/HTTPS yang valid", + override: false, + }, + { + tag: "url_encoded", + translation: "{0} harus berupa string URL yang terenkode", + override: false, + }, + { + tag: "urn_rfc2141", + translation: "{0} harus berupa URN sesuai RFC 2141 yang valid", + override: false, + }, - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("min-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("min-items", fe.Field(), c) - - default: - t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } + // Strings Tags + { + tag: "alpha", + translation: "{0} hanya dapat berisi karakter alfanumerik", + override: false, + }, + { + tag: "alphanum", + translation: "{0} hanya dapat berisi karakter alfanumerik", + override: false, + }, + { + tag: "alphanumunicode", + translation: "{0} hanya boleh berisi karakter alfanumerik unicode", + override: false, + }, + { + tag: "alphaunicode", + translation: "{0} hanya boleh berisi karakter alfanumerik unicode", + override: false, + }, + { + tag: "ascii", + translation: "{0} hanya boleh berisi karakter ASCII", + override: false, + }, + { + tag: "boolean", + translation: "{0} harus berupa nilai boolean yang valid", + override: false, + }, + { + tag: "contains", + translation: "{0} harus berisi teks '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "containsany", + translation: "{0} harus berisi setidaknya salah satu karakter berikut '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "containsrune", + translation: "{0} harus berisi setidaknya salah satu karakter berikut '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "endsnotwith", + translation: "{0} tidak boleh diakhiri dengan '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "endswith", + translation: "{0} harus diakhiri dengan '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "excludes", + translation: "{0} tidak boleh berisi teks '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "excludesall", + translation: "{0} tidak boleh berisi salah satu karakter berikut '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "excludesrune", + translation: "{0} tidak boleh berisi '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "lowercase", + translation: "{0} harus berupa string huruf kecil", + override: false, + }, + { + tag: "multibyte", + translation: "{0} harus berisi karakter multibyte", + override: false, + }, + { + tag: "number", + translation: "{0} harus berupa angka yang valid", + override: false, + }, + { + tag: "numeric", + translation: "{0} harus berupa nilai numerik yang valid", + override: false, + }, + { + tag: "printascii", + translation: "{0} hanya boleh berisi karakter ASCII yang dapat dicetak", + override: false, + }, + { + tag: "startsnotwith", + translation: "{0} tidak boleh diawali dengan '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "startswith", + translation: "{0} harus diawali dengan '{1}'", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "uppercase", + translation: "{0} harus berupa string huruf besar", + override: false, + }, - return t - }, + // Format Tags + { + tag: "hexadecimal", + translation: "{0} harus berupa heksadesimal yang valid", + override: false, + }, + { + tag: "base64", + translation: "{0} harus berupa string Base64 yang valid", + override: false, + }, + { + tag: "base64url", + translation: "{0} harus berupa string Base64 URL yang valid", + override: false, + }, + { + tag: "base64rawurl", + translation: "{0} harus berupa string Base64 Raw URL yang valid", + override: false, + }, + { + tag: "bic", + translation: "{0} harus berupa kode BIC (SWIFT) yang valid sesuai ISO 9362", + override: false, + }, + { + tag: "bcp47_language_tag", + translation: "{0} harus berupa tag bahasa BCP 47 yang valid", + override: false, + }, + { + tag: "btc_addr", + translation: "{0} harus berupa alamat Bitcoin yang valid", + override: false, + }, + { + tag: "btc_addr_bech32", + translation: "{0} harus berupa alamat Bitcoin Bech32 yang valid", + override: false, + }, + { + tag: "credit_card", + translation: "{0} harus berupa nomor kartu kredit yang valid", + override: false, + }, + { + tag: "mongodb", + translation: "{0} harus berupa ObjectID MongoDB yang valid", + override: false, + }, + { + tag: "mongodb_connection_string", + translation: "{0} harus berupa string koneksi MongoDB yang valid", + override: false, + }, + { + tag: "cron", + translation: "{0} harus berupa ekspresi cron yang valid", + override: false, + }, + { + tag: "spicedb", + translation: "{0} harus berupa format SpiceDB yang valid", + override: false, + }, + { + tag: "datetime", + translation: "{0} tidak sesuai dengan format {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "e164", + translation: "{0} harus berupa nomor telepon format E.164 yang valid", + override: false, + }, + { + tag: "email", + translation: "{0} harus berupa alamat email yang valid", + override: false, + }, + { + tag: "eth_addr", + translation: "{0} harus berupa alamat Ethereum yang valid", + override: false, + }, + { + tag: "hexcolor", + translation: "{0} harus berupa warna HEX yang valid", + override: false, + }, + { + tag: "hsl", + translation: "{0} harus berupa warna HSL yang valid", + override: false, + }, + { + tag: "hsla", + translation: "{0} harus berupa warna HSLA yang valid", + override: false, + }, + { + tag: "html", + translation: "{0} harus berupa HTML yang valid", + override: false, + }, + { + tag: "html_encoded", + translation: "{0} harus berupa HTML terenkode yang valid", + override: false, + }, + { + tag: "isbn", + translation: "{0} harus berupa nomor ISBN yang valid", + override: false, + }, + { + tag: "isbn10", + translation: "{0} harus berupa nomor ISBN-10 yang valid", + override: false, + }, + { + tag: "isbn13", + translation: "{0} harus berupa nomor ISBN-13 yang valid", + override: false, + }, + { + tag: "issn", + translation: "{0} harus berupa nomor ISSN yang valid", + override: false, + }, + { + tag: "iso3166_1_alpha2", + translation: "{0} harus berupa kode negara ISO 3166-1 alpha-2 yang valid", + override: false, + }, + { + tag: "iso3166_1_alpha3", + translation: "{0} harus berupa kode negara ISO 3166-1 alpha-3 yang valid", + override: false, + }, + { + tag: "iso3166_1_alpha_numeric", + translation: "{0} harus berupa kode negara numerik ISO 3166-1 yang valid", + override: false, + }, + { + tag: "iso3166_2", + translation: "{0} harus berupa kode subdivisi negara ISO 3166-2 yang valid", + override: false, + }, + { + tag: "iso4217", + translation: "{0} harus berupa kode mata uang ISO 4217 yang valid", + override: false, + }, + { + tag: "json", + translation: "{0} harus berupa string JSON yang valid", + override: false, + }, + { + tag: "jwt", + translation: "{0} harus berupa JSON Web Token (JWT) yang valid", + override: false, + }, + { + tag: "latitude", + translation: "{0} harus berisi koordinat lintang yang valid", + override: false, + }, + { + tag: "longitude", + translation: "{0} harus berisi koordinat bujur yang valid", + override: false, + }, + { + tag: "luhn_checksum", + translation: "{0} harus memiliki checksum Luhn yang valid", + override: false, + }, + { + tag: "postcode_iso3166_alpha2", + translation: "{0} tidak sesuai dengan format kode pos negara {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "postcode_iso3166_alpha2_field", + translation: "{0} tidak sesuai dengan format kode pos negara dalam field {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "rgb", + translation: "{0} harus berupa warna RGB yang valid", + override: false, + }, + { + tag: "rgba", + translation: "{0} harus berupa warna RGBA yang valid", + override: false, + }, + { + tag: "ssn", + translation: "{0} harus berupa nomor SSN (Social Security Number) yang valid", + override: false, + }, + { + tag: "timezone", + translation: "{0} harus berupa zona waktu yang valid", + override: false, + }, + { + tag: "uuid", + translation: "{0} harus berupa UUID yang valid", + override: false, + }, + { + tag: "uuid3", + translation: "{0} harus berupa UUID versi 3 yang valid", + override: false, + }, + { + tag: "uuid3_rfc4122", + translation: "{0} harus berupa UUID versi 3 RFC4122 yang valid", + override: false, + }, + { + tag: "uuid4", + translation: "{0} harus berupa UUID versi 4 yang valid", + override: false, + }, + { + tag: "uuid4_rfc4122", + translation: "{0} harus berupa UUID versi 4 RFC4122 yang valid", + override: false, + }, + { + tag: "uuid5", + translation: "{0} harus berupa UUID versi 5 yang valid", + override: false, }, { - tag: "max", - customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("max-string", "panjang maksimal {0} adalah {1}", false); err != nil { - return - } - - // if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { - return - } - - if err = ut.Add("max-number", "{0} harus {1} atau kurang", false); err != nil { - return - } - - if err = ut.Add("max-items", "{0} harus berisi maksimal {1}", false); err != nil { - return - } - // if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { - return - } - - return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - var err error - var t string - - var digits uint64 - var kind reflect.Kind - - if idx := strings.Index(fe.Param(), "."); idx != -1 { - digits = uint64(len(fe.Param()[idx+1:])) - } - - f64, err := strconv.ParseFloat(fe.Param(), 64) - if err != nil { - goto END - } - - kind = fe.Kind() - if kind == reflect.Ptr { - kind = fe.Type().Elem().Kind() - } - - switch kind { - case reflect.String: - - var c string - - c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("max-string", fe.Field(), c) - - case reflect.Slice, reflect.Map, reflect.Array: - var c string - - c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) - if err != nil { - goto END - } - - t, err = ut.T("max-items", fe.Field(), c) - - default: - t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) - } - - END: - if err != nil { - fmt.Printf("warning: error translating FieldError: %s", err) - return fe.(error).Error() - } - - return t - }, + tag: "uuid5_rfc4122", + translation: "{0} harus berupa UUID versi 5 RFC4122 yang valid", + override: false, }, { - tag: "eq", - translation: "{0} tidak sama dengan {1}", + tag: "uuid_rfc4122", + translation: "{0} harus berupa UUID RFC4122 yang valid", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - fmt.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, }, { - tag: "ne", - translation: "{0} tidak sama dengan {1}", + tag: "md4", + translation: "{0} harus berupa hash MD4 yang valid", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - fmt.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } + }, + { + tag: "md5", + translation: "{0} harus berupa hash MD5 yang valid", + override: false, + }, + { + tag: "sha256", + translation: "{0} harus berupa hash SHA256 yang valid", + override: false, + }, + { + tag: "sha384", + translation: "{0} harus berupa hash SHA384 yang valid", + override: false, + }, + { + tag: "sha512", + translation: "{0} harus berupa hash SHA512 yang valid", + override: false, + }, + { + tag: "ripemd128", + translation: "{0} harus berupa hash RIPEMD128 yang valid", + override: false, + }, + { + tag: "ripemd160", + translation: "{0} harus berupa hash RIPEMD160 yang valid", + override: false, + }, + { + tag: "tiger128", + translation: "{0} harus berupa hash TIGER128 yang valid", + override: false, + }, + { + tag: "tiger160", + translation: "{0} harus berupa hash TIGER160 yang valid", + override: false, + }, + { + tag: "tiger192", + translation: "{0} harus berupa hash TIGER192 yang valid", + override: false, + }, + { + tag: "semver", + translation: "{0} harus berupa nomor versi semantik yang valid", + override: false, + }, + { + tag: "ulid", + translation: "{0} harus berupa ULID yang valid", + override: false, + }, + { + tag: "cve", + translation: "{0} harus berupa identifikasi CVE yang valid", + override: false, + }, - return t - }, + // Comparisons Tags + { + tag: "eq", + translation: "{0} tidak sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "lt", + tag: "eq_ignore_case", + translation: "{0} harus sama dengan {1} (tidak case-sensitive)", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("lt-string", "panjang {0} harus kurang dari {1}", false); err != nil { + if err = ut.Add("gt-string", "panjang {0} harus lebih dari {1}", false); err != nil { return } - // if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("lt-number", "{0} harus kurang dari {1}", false); err != nil { + if err = ut.Add("gt-number", "{0} harus lebih besar dari {1}", false); err != nil { return } - if err = ut.Add("lt-items", "{0} harus berisi kurang dari {1}", false); err != nil { + if err = ut.Add("gt-items", "{0} harus berisi lebih dari {1}", false); err != nil { return } - // if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("lt-datetime", "{0} harus kurang dari tanggal & waktu saat ini", false); err != nil { + if err = ut.Add("gt-datetime", "{0} harus lebih besar dari tanggal & waktu saat ini", false); err != nil { return } return - }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -405,12 +764,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("lt-string", fe.Field(), c) + t, err = ut.T("gt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string @@ -420,12 +779,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("lt-items", fe.Field(), c) + t, err = ut.T("gt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { @@ -433,7 +792,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("lt-datetime", fe.Field()) + t, err = ut.T("gt-datetime", fe.Field()) default: err = fn() @@ -441,7 +800,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) + t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: @@ -454,45 +813,35 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "lte", + tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("lte-string", "panjang maksimal {0} adalah {1}", false); err != nil { + if err = ut.Add("gte-string", "panjang minimal {0} adalah {1}", false); err != nil { return } - // if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("lte-number", "{0} harus {1} atau kurang", false); err != nil { + if err = ut.Add("gte-number", "{0} harus {1} atau lebih besar", false); err != nil { return } - if err = ut.Add("lte-items", "{0} harus berisi maksimal {1}", false); err != nil { + if err = ut.Add("gte-items", "{0} harus berisi setidaknya {1}", false); err != nil { return } - // if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("lte-datetime", "{0} harus kurang dari atau sama dengan tanggal & waktu saat ini", false); err != nil { + if err = ut.Add("gte-datetime", "{0} harus lebih besar dari atau sama dengan tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -525,12 +874,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("lte-string", fe.Field(), c) + t, err = ut.T("gte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string @@ -540,12 +889,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("lte-items", fe.Field(), c) + t, err = ut.T("gte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { @@ -553,7 +902,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("lte-datetime", fe.Field()) + t, err = ut.T("gte-datetime", fe.Field()) default: err = fn() @@ -561,7 +910,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) + t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: @@ -574,45 +923,35 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "gt", + tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("gt-string", "panjang {0} harus lebih dari {1}", false); err != nil { + if err = ut.Add("lt-string", "panjang {0} harus kurang dari {1}", false); err != nil { return } - // if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("gt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("lt-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("gt-number", "{0} harus lebih besar dari {1}", false); err != nil { + if err = ut.Add("lt-number", "{0} harus kurang dari {1}", false); err != nil { return } - if err = ut.Add("gt-items", "{0} harus berisi lebih dari {1}", false); err != nil { + if err = ut.Add("lt-items", "{0} harus berisi kurang dari {1}", false); err != nil { return } - // if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("gt-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("lt-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("gt-datetime", "{0} harus lebih besar dari tanggal & waktu saat ini", false); err != nil { + if err = ut.Add("lt-datetime", "{0} harus kurang dari tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -645,12 +984,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("gt-string", fe.Field(), c) + t, err = ut.T("lt-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string @@ -660,12 +999,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("gt-items", fe.Field(), c) + t, err = ut.T("lt-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { @@ -673,7 +1012,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("gt-datetime", fe.Field()) + t, err = ut.T("lt-datetime", fe.Field()) default: err = fn() @@ -681,7 +1020,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) + t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: @@ -694,45 +1033,35 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "gte", + tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { - - if err = ut.Add("gte-string", "panjang minimal {0} adalah {1}", false); err != nil { + if err = ut.Add("lte-string", "panjang maksimal {0} adalah {1}", false); err != nil { return } - // if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("gte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("lte-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("gte-number", "{0} harus {1} atau lebih besar", false); err != nil { + if err = ut.Add("lte-number", "{0} harus {1} atau kurang", false); err != nil { return } - if err = ut.Add("gte-items", "{0} harus berisi setidaknya {1}", false); err != nil { + if err = ut.Add("lte-items", "{0} harus berisi maksimal {1}", false); err != nil { return } - // if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOne, false); err != nil { - // return - // } - - if err = ut.AddCardinal("gte-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + if err = ut.AddCardinal("lte-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { return } - if err = ut.Add("gte-datetime", "{0} harus lebih besar dari atau sama dengan tanggal & waktu saat ini", false); err != nil { + if err = ut.Add("lte-datetime", "{0} harus kurang dari atau sama dengan tanggal & waktu saat ini", false); err != nil { return } return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -765,12 +1094,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("gte-string", fe.Field(), c) + t, err = ut.T("lte-string", fe.Field(), c) case reflect.Slice, reflect.Map, reflect.Array: var c string @@ -780,12 +1109,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) + c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) if err != nil { goto END } - t, err = ut.T("gte-items", fe.Field(), c) + t, err = ut.T("lte-items", fe.Field(), c) case reflect.Struct: if fe.Type() != reflect.TypeOf(time.Time{}) { @@ -793,7 +1122,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("gte-datetime", fe.Field()) + t, err = ut.T("lte-datetime", fe.Field()) default: err = fn() @@ -801,7 +1130,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er goto END } - t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) + t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) } END: @@ -814,134 +1143,118 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "eqfield", - translation: "{0} harus sama dengan {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } + tag: "ne", + translation: "{0} tidak sama dengan {1}", + override: false, + customTransFunc: translateFuncWithParam, + }, + { + tag: "ne_ignore_case", + translation: "{0} tidak sama dengan {1} (tidak case-sensitive)", + override: false, + customTransFunc: translateFuncWithParam, + }, - return t - }, + // Other Tags + { + tag: "dir", + translation: "{0} harus berupa direktori yang ada", + override: false, }, { - tag: "eqcsfield", - translation: "{0} harus sama dengan {1}", + tag: "dirpath", + translation: "{0} harus berupa path direktori yang valid", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, }, { - tag: "necsfield", - translation: "{0} tidak sama dengan {1}", + tag: "file", + translation: "{0} harus berupa file yang valid", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, }, { - tag: "gtcsfield", - translation: "{0} harus lebih besar dari {1}", + tag: "filepath", + translation: "{0} harus berupa path file yang valid", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, }, { - tag: "gtecsfield", - translation: "{0} harus lebih besar dari atau sama dengan {1}", + tag: "image", + translation: "{0} harus berupa gambar yang valid", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - - return t - }, }, { - tag: "ltcsfield", - translation: "{0} harus kurang dari {1}", + tag: "isdefault", + translation: "{0} harus berupa nilai default", override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + }, + { + tag: "len", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("len-string", "panjang {0} harus {1}", false); err != nil { + return + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + if err = ut.AddCardinal("len-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + return } - return t - }, - }, - { - tag: "ltecsfield", - translation: "{0} harus kurang dari atau sama dengan {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + if err = ut.Add("len-number", "{0} harus sama dengan {1}", false); err != nil { + return + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + if err = ut.Add("len-items", "{0} harus berisi {1}", false); err != nil { + return } - return t + if err = ut.AddCardinal("len-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + return + } + + return }, - }, - { - tag: "nefield", - translation: "{0} tidak sama dengan {1}", - override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var digits uint64 + var kind reflect.Kind + + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + goto END } - return t - }, - }, - { - tag: "gtfield", - translation: "{0} harus lebih besar dari {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + var c string + c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + t, err = ut.T("len-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + t, err = ut.T("len-items", fe.Field(), c) - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + default: + t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) + fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } @@ -949,129 +1262,74 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "gtefield", - translation: "{0} harus lebih besar dari atau sama dengan {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + tag: "max", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("max-string", "panjang maksimal {0} adalah {1}", false); err != nil { + return + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + if err = ut.AddCardinal("max-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + return } - return t - }, - }, - { - tag: "ltfield", - translation: "{0} harus kurang dari {1}", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + if err = ut.Add("max-number", "{0} harus {1} atau kurang", false); err != nil { + return + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + if err = ut.Add("max-items", "{0} harus berisi maksimal {1}", false); err != nil { + return } - return t + if err = ut.AddCardinal("max-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + return + } + + return }, - }, - { - tag: "ltefield", - translation: "{0} harus kurang dari atau sama dengan {1}", - override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var digits uint64 + var kind reflect.Kind + + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + goto END } - return t - }, - }, - { - tag: "alpha", - translation: "{0} hanya dapat berisi karakter abjad", - override: false, - }, - { - tag: "alphanum", - translation: "{0} hanya dapat berisi karakter alfanumerik", - override: false, - }, - { - tag: "numeric", - translation: "{0} harus berupa nilai numerik yang valid", - override: false, - }, - { - tag: "number", - translation: "{0} harus berupa angka yang valid", - override: false, - }, - { - tag: "hexadecimal", - translation: "{0} harus berupa heksadesimal yang valid", - override: false, - }, - { - tag: "hexcolor", - translation: "{0} harus berupa warna HEX yang valid", - override: false, - }, - { - tag: "rgb", - translation: "{0} harus berupa warna RGB yang valid", - override: false, - }, - { - tag: "rgba", - translation: "{0} harus berupa warna RGBA yang valid", - override: false, - }, - { - tag: "hsl", - translation: "{0} harus berupa warna HSL yang valid", - override: false, - }, - { - tag: "hsla", - translation: "{0} harus berupa warna HSLA yang valid", - override: false, - }, - { - tag: "email", - translation: "{0} harus berupa alamat email yang valid", - override: false, - }, - { - tag: "url", - translation: "{0} harus berupa URL yang valid", - override: false, - }, - { - tag: "uri", - translation: "{0} harus berupa URI yang valid", - override: false, - }, - { - tag: "base64", - translation: "{0} harus berupa string Base64 yang valid", - override: false, - }, - { - tag: "contains", - translation: "{0} harus berisi teks '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + var c string + c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + t, err = ut.T("max-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + t, err = ut.T("max-items", fe.Field(), c) + + default: + t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + END: if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) + fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } @@ -1079,59 +1337,74 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "containsany", - translation: "{0} harus berisi setidaknya salah satu karakter berikut '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + tag: "min", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("min-string", "panjang minimal {0} adalah {1}", false); err != nil { + return + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + if err = ut.AddCardinal("min-string-character", "{0} karakter", locales.PluralRuleOther, false); err != nil { + return } - return t - }, - }, - { - tag: "excludes", - translation: "{0} tidak boleh berisi teks '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + if err = ut.Add("min-number", "{0} harus {1} atau lebih besar", false); err != nil { + return + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + if err = ut.Add("min-items", "{0} harus berisi minimal {1}", false); err != nil { + return } - return t + if err = ut.AddCardinal("min-items-item", "{0} item", locales.PluralRuleOther, false); err != nil { + return + } + + return }, - }, - { - tag: "excludesall", - translation: "{0} tidak boleh berisi salah satu karakter berikut '{1}'", - override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var digits uint64 + var kind reflect.Kind + + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + f64, err := strconv.ParseFloat(fe.Param(), 64) if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() + goto END } - return t - }, - }, - { - tag: "excludesrune", - translation: "{0} tidak boleh berisi '{1}'", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + var c string + c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + t, err = ut.T("min-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + t, err = ut.T("min-items", fe.Field(), c) + + default: + t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) + } - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + END: if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) + fmt.Printf("warning: error translating FieldError: %s", err) return fe.(error).Error() } @@ -1139,209 +1412,115 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er }, }, { - tag: "isbn", - translation: "{0} harus berupa nomor ISBN yang valid", - override: false, - }, - { - tag: "isbn10", - translation: "{0} harus berupa nomor ISBN-10 yang valid", - override: false, - }, - { - tag: "isbn13", - translation: "{0} harus berupa nomor ISBN-13 yang valid", - override: false, - }, - { - tag: "issn", - translation: "{0} harus berupa nomor ISSN yang valid", - override: false, - }, - { - tag: "uuid", - translation: "{0} harus berupa UUID yang valid", - override: false, - }, - { - tag: "uuid3", - translation: "{0} harus berupa UUID versi 3 yang valid", - override: false, - }, - { - tag: "uuid4", - translation: "{0} harus berupa UUID versi 4 yang valid", - override: false, - }, - { - tag: "uuid5", - translation: "{0} harus berupa UUID versi 5 yang valid", - override: false, - }, - { - tag: "ulid", - translation: "{0} harus berupa ULID yang valid", - override: false, - }, - { - tag: "ascii", - translation: "{0} hanya boleh berisi karakter ascii", - override: false, - }, - { - tag: "printascii", - translation: "{0} hanya boleh berisi karakter ascii yang dapat dicetak", - override: false, - }, - { - tag: "multibyte", - translation: "{0} harus berisi karakter multibyte", - override: false, - }, - { - tag: "datauri", - translation: "{0} harus berisi URI Data yang valid", - override: false, - }, - { - tag: "latitude", - translation: "{0} harus berisi koordinat lintang yang valid", - override: false, - }, - { - tag: "longitude", - translation: "{0} harus berisi koordinat bujur yang valid", - override: false, - }, - { - tag: "ssn", - translation: "{0} harus berupa nomor SSN yang valid", - override: false, - }, - { - tag: "ipv4", - translation: "{0} harus berupa alamat IPv4 yang valid", - override: false, - }, - { - tag: "ipv6", - translation: "{0} harus berupa alamat IPv6 yang valid", - override: false, - }, - { - tag: "ip", - translation: "{0} harus berupa alamat IP yang valid", - override: false, + tag: "oneof", + translation: "{0} harus berupa salah satu dari [{1}]", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "cidr", - translation: "{0} harus berisi notasi CIDR yang valid", + tag: "required", + translation: "{0} wajib diisi", override: false, }, { - tag: "cidrv4", - translation: "{0} harus berisi notasi CIDR yang valid untuk alamat IPv4", - override: false, + tag: "required_if", + translation: "{0} wajib diisi jika {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "cidrv6", - translation: "{0} harus berisi notasi CIDR yang valid untuk alamat IPv6", - override: false, + tag: "required_unless", + translation: "{0} wajib diisi kecuali {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "tcp_addr", - translation: "{0} harus berupa alamat TCP yang valid", - override: false, + tag: "required_with", + translation: "{0} wajib diisi jika {1} telah diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "tcp4_addr", - translation: "{0} harus berupa alamat TCP IPv4 yang valid", - override: false, + tag: "required_with_all", + translation: "{0} wajib diisi jika {1} telah diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "tcp6_addr", - translation: "{0} harus berupa alamat TCP IPv6 yang valid", - override: false, + tag: "required_without", + translation: "{0} wajib diisi jika {1} tidak diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "udp_addr", - translation: "{0} harus berupa alamat UDP yang valid", - override: false, + tag: "required_without_all", + translation: "{0} wajib diisi jika {1} tidak diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "udp4_addr", - translation: "{0} harus berupa alamat IPv4 UDP yang valid", - override: false, + tag: "excluded_if", + translation: "{0} tidak boleh diisi jika {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "udp6_addr", - translation: "{0} harus berupa alamat IPv6 UDP yang valid", - override: false, + tag: "excluded_unless", + translation: "{0} tidak boleh diisi kecuali {1}", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "ip_addr", - translation: "{0} harus berupa alamat IP yang dapat dipecahkan", - override: false, + tag: "excluded_with", + translation: "{0} tidak boleh diisi jika {1} telah diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "ip4_addr", - translation: "{0} harus berupa alamat IPv4 yang dapat diatasi", - override: false, + tag: "excluded_with_all", + translation: "{0} tidak boleh diisi jika semua {1} telah diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "ip6_addr", - translation: "{0} harus berupa alamat IPv6 yang dapat diatasi", - override: false, + tag: "excluded_without", + translation: "{0} tidak boleh diisi jika {1} tidak diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "unix_addr", - translation: "{0} harus berupa alamat UNIX yang dapat diatasi", - override: false, + tag: "excluded_without_all", + translation: "{0} tidak boleh diisi jika {1} tidak diisi", + override: false, + customTransFunc: translateFuncWithParam, }, { - tag: "mac", - translation: "{0} harus berisi alamat MAC yang valid", + tag: "unique", + translation: "{0} harus berisi nilai yang unik", override: false, }, + + // Aliases Tags { tag: "iscolor", translation: "{0} harus berupa warna yang valid", override: false, }, { - tag: "oneof", - translation: "{0} harus berupa salah satu dari [{1}]", - override: false, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) - if err != nil { - log.Printf("warning: error translating FieldError: %#v", fe) - return fe.(error).Error() - } - return s - }, - }, - { - tag: "image", - translation: "{0} harus berupa gambar yang valid", + tag: "country_code", + translation: "{0} harus berupa kode negara yang valid", override: false, }, } + // register translations for _, t := range translations { - if t.customTransFunc != nil && t.customRegisFunc != nil { - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) - } else if t.customTransFunc != nil && t.customRegisFunc == nil { - err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) - } else if t.customTransFunc == nil && t.customRegisFunc != nil { - err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) - } else { err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) } @@ -1354,27 +1533,33 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er return } +// registrationFunc returns a function that can be used for registering translations func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { - return func(ut ut.Translator) (err error) { - if err = ut.Add(tag, translation, override); err != nil { return } - return - } - } +// translateFunc is the default translation function func translateFunc(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) return fe.(error).Error() } + return t +} + +// translateFuncWithParam is the default translation function with parameter +func translateFuncWithParam(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } return t } diff --git a/translations/id/id_test.go b/translations/id/id_test.go index 4a5b70f7a..e14db2c9f 100644 --- a/translations/id/id_test.go +++ b/translations/id/id_test.go @@ -10,17 +10,34 @@ import ( "github.com/go-playground/validator/v10" ) -func TestTranslations(t *testing.T) { +// InitValidator initializes a new validator with Indonesian translations +func InitValidator() (*validator.Validate, ut.Translator, error) { + // setup translator idn := indonesia.New() uni := ut.New(idn, idn) trans, _ := uni.GetTranslator("id") - validate := validator.New() + // initialize validator + validate := validator.New(validator.WithRequiredStructEnabled()) + // register translations err := RegisterDefaultTranslations(validate, trans) + if err != nil { + return nil, nil, err + } + + return validate, trans, nil +} + +// TestFieldTagsTranslations tests all field tags registered translations for Indonesian language +func TestFieldTagsTranslations(t *testing.T) { + + // init validator with Indonesian translations + validate, trans, err := InitValidator() Equal(t, err, nil) + // Inner struct for cross-field validations type Inner struct { EqCSFieldString string NeCSFieldString string @@ -28,613 +45,1294 @@ func TestTranslations(t *testing.T) { GteCSFieldString string LtCSFieldString string LteCSFieldString string + FieldContains string + FieldExcludes string } - type Test struct { - Inner Inner - RequiredString string `validate:"required"` - RequiredNumber int `validate:"required"` - RequiredMultiple []string `validate:"required"` - LenString string `validate:"len=1"` - LenNumber float64 `validate:"len=1113.00"` - LenMultiple []string `validate:"len=7"` - MinString string `validate:"min=1"` - MinNumber float64 `validate:"min=1113.00"` - MinMultiple []string `validate:"min=7"` - MaxString string `validate:"max=3"` - MaxNumber float64 `validate:"max=1113.00"` - MaxMultiple []string `validate:"max=7"` - EqString string `validate:"eq=3"` - EqNumber float64 `validate:"eq=2.33"` - EqMultiple []string `validate:"eq=7"` - NeString string `validate:"ne="` - NeNumber float64 `validate:"ne=0.00"` - NeMultiple []string `validate:"ne=0"` - LtString string `validate:"lt=3"` - LtNumber float64 `validate:"lt=5.56"` - LtMultiple []string `validate:"lt=2"` - LtTime time.Time `validate:"lt"` - LteString string `validate:"lte=3"` - LteNumber float64 `validate:"lte=5.56"` - LteMultiple []string `validate:"lte=2"` - LteTime time.Time `validate:"lte"` - GtString string `validate:"gt=3"` - GtNumber float64 `validate:"gt=5.56"` - GtMultiple []string `validate:"gt=2"` - GtTime time.Time `validate:"gt"` - GteString string `validate:"gte=3"` - GteNumber float64 `validate:"gte=5.56"` - GteMultiple []string `validate:"gte=2"` - GteTime time.Time `validate:"gte"` - EqFieldString string `validate:"eqfield=MaxString"` - EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` - NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` - GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` - GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` - LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` - LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` - NeFieldString string `validate:"nefield=EqFieldString"` - GtFieldString string `validate:"gtfield=MaxString"` - GteFieldString string `validate:"gtefield=MaxString"` - LtFieldString string `validate:"ltfield=MaxString"` - LteFieldString string `validate:"ltefield=MaxString"` - AlphaString string `validate:"alpha"` - AlphanumString string `validate:"alphanum"` - NumericString string `validate:"numeric"` - NumberString string `validate:"number"` - HexadecimalString string `validate:"hexadecimal"` - HexColorString string `validate:"hexcolor"` - RGBColorString string `validate:"rgb"` - RGBAColorString string `validate:"rgba"` - HSLColorString string `validate:"hsl"` - HSLAColorString string `validate:"hsla"` - Email string `validate:"email"` - URL string `validate:"url"` - URI string `validate:"uri"` - Base64 string `validate:"base64"` - Contains string `validate:"contains=tujuan"` - ContainsAny string `validate:"containsany=!@#$"` - Excludes string `validate:"excludes=text"` - ExcludesAll string `validate:"excludesall=!@#$"` - ExcludesRune string `validate:"excludesrune=☻"` - ISBN string `validate:"isbn"` - ISBN10 string `validate:"isbn10"` - ISBN13 string `validate:"isbn13"` - ISSN string `validate:"issn"` - UUID string `validate:"uuid"` - UUID3 string `validate:"uuid3"` - UUID4 string `validate:"uuid4"` - UUID5 string `validate:"uuid5"` - ULID string `validate:"ulid"` - ASCII string `validate:"ascii"` - PrintableASCII string `validate:"printascii"` - MultiByte string `validate:"multibyte"` - DataURI string `validate:"datauri"` - Latitude string `validate:"latitude"` - Longitude string `validate:"longitude"` - SSN string `validate:"ssn"` - IP string `validate:"ip"` - IPv4 string `validate:"ipv4"` - IPv6 string `validate:"ipv6"` - CIDR string `validate:"cidr"` - CIDRv4 string `validate:"cidrv4"` - CIDRv6 string `validate:"cidrv6"` - TCPAddr string `validate:"tcp_addr"` - TCPAddrv4 string `validate:"tcp4_addr"` - TCPAddrv6 string `validate:"tcp6_addr"` - UDPAddr string `validate:"udp_addr"` - UDPAddrv4 string `validate:"udp4_addr"` - UDPAddrv6 string `validate:"udp6_addr"` - IPAddr string `validate:"ip_addr"` - IPAddrv4 string `validate:"ip4_addr"` - IPAddrv6 string `validate:"ip6_addr"` - UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future - MAC string `validate:"mac"` - IsColor string `validate:"iscolor"` - StrPtrMinLen *string `validate:"min=10"` - StrPtrMaxLen *string `validate:"max=1"` - StrPtrLen *string `validate:"len=2"` - StrPtrLt *string `validate:"lt=1"` - StrPtrLte *string `validate:"lte=1"` - StrPtrGt *string `validate:"gt=10"` - StrPtrGte *string `validate:"gte=10"` - OneOfString string `validate:"oneof=merah hijau"` - OneOfInt int `validate:"oneof=5 63"` - Image string `validate:"image"` - } + // TestFieldTags for field validations + type TestFieldTags struct { + Inner Inner + + // Equal field validations + EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` + EqFieldString string `validate:"eqfield=EqString"` + EqString string - var test Test + // Not equal field validations + NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` + NeFieldString string `validate:"nefield=NeString"` + NeString string - test.Inner.EqCSFieldString = "1234" - test.Inner.GtCSFieldString = "1234" - test.Inner.GteCSFieldString = "1234" + // Greater than field validations + GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` + GtFieldString string `validate:"gtfield=GtString"` + GtString string - test.MaxString = "1234" - test.MaxNumber = 2000 - test.MaxMultiple = make([]string, 9) + // Greater than or equal field validations + GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` + GteFieldString string `validate:"gtefield=GteString"` + GteString string - test.LtString = "1234" - test.LtNumber = 6 - test.LtMultiple = make([]string, 3) - test.LtTime = time.Now().Add(time.Hour * 24) + // Less than field validations + LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` + LtFieldString string `validate:"ltfield=LtString"` + LtString string - test.LteString = "1234" - test.LteNumber = 6 - test.LteMultiple = make([]string, 3) - test.LteTime = time.Now().Add(time.Hour * 24) + // Less than or equal field validations + LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` + LteFieldString string `validate:"ltefield=LteString"` + LteString string - test.LtFieldString = "12345" - test.LteFieldString = "12345" + // Field contains/excludes validations + ContainsField string `validate:"fieldcontains=Inner.FieldContains"` + ExcludesField string `validate:"fieldexcludes=Inner.FieldExcludes"` + } + + // init test struct with values + test := TestFieldTags{ + Inner: Inner{ + EqCSFieldString: "equal", + NeCSFieldString: "not-equal", + GtCSFieldString: "zzz", + GteCSFieldString: "zzz", + LtCSFieldString: "aaa", + LteCSFieldString: "aaa", + FieldContains: "contains", + FieldExcludes: "excludes", + }, + EqCSFieldString: "not-equal", // should equal Inner.EqCSFieldString + EqFieldString: "not-equal", // should equal EqString + EqString: "equal", - test.LtCSFieldString = "1234" - test.LteCSFieldString = "1234" + NeCSFieldString: "not-equal", // should not equal Inner.NeCSFieldString + NeFieldString: "same", // should not equal NeString + NeString: "same", - test.AlphaString = "abc3" - test.AlphanumString = "abc3!" - test.NumericString = "12E.00" - test.NumberString = "12E" + GtCSFieldString: "aaa", // should be greater than Inner.GtCSFieldString + GtFieldString: "aaa", // should be greater than GtString + GtString: "zzz", - test.Excludes = "this is some test text" - test.ExcludesAll = "This is Great!" - test.ExcludesRune = "Love it ☻" + GteCSFieldString: "aaa", // should be greater than or equal to Inner.GteCSFieldString + GteFieldString: "aaa", // should be greater than or equal to GteString + GteString: "bbbb", // reference value for GteFieldString - test.ASCII = "カタカナ" - test.PrintableASCII = "カタカナ" + LtCSFieldString: "zzz", // should be less than Inner.LtCSFieldString + LtFieldString: "zzz", // should be less than LtString + LtString: "aaa", - test.MultiByte = "1234feerf" + LteCSFieldString: "zzzzz", // should be less than or equal to Inner.LteCSFieldString + LteFieldString: "zzzz", // should be less than or equal to LteString + LteString: "yyy", // reference value for LteFieldString - s := "toolong" - test.StrPtrMaxLen = &s - test.StrPtrLen = &s + ContainsField: "xyz", // should contain Inner.FieldContains + ExcludesField: "has-excludes", // should not contain Inner.FieldExcludes + } + // validate struct err = validate.Struct(test) NotEqual(t, err, nil) - errs, ok := err.(validator.ValidationErrors) - Equal(t, ok, true) + // get validation errors + errs := err.(validator.ValidationErrors) + // verify each expected error message tests := []struct { ns string expected string }{ { - ns: "Test.IsColor", - expected: "IsColor harus berupa warna yang valid", + ns: "TestFieldTags.EqCSFieldString", + expected: "EqCSFieldString harus sama dengan Inner.EqCSFieldString", }, { - ns: "Test.MAC", - expected: "MAC harus berisi alamat MAC yang valid", + ns: "TestFieldTags.EqFieldString", + expected: "EqFieldString harus sama dengan EqString", }, { - ns: "Test.IPAddr", - expected: "IPAddr harus berupa alamat IP yang dapat dipecahkan", + ns: "TestFieldTags.NeCSFieldString", + expected: "NeCSFieldString tidak sama dengan Inner.NeCSFieldString", }, { - ns: "Test.IPAddrv4", - expected: "IPAddrv4 harus berupa alamat IPv4 yang dapat diatasi", + ns: "TestFieldTags.NeFieldString", + expected: "NeFieldString tidak sama dengan NeString", }, { - ns: "Test.IPAddrv6", - expected: "IPAddrv6 harus berupa alamat IPv6 yang dapat diatasi", + ns: "TestFieldTags.GtCSFieldString", + expected: "GtCSFieldString harus lebih besar dari Inner.GtCSFieldString", }, { - ns: "Test.UDPAddr", - expected: "UDPAddr harus berupa alamat UDP yang valid", + ns: "TestFieldTags.GtFieldString", + expected: "GtFieldString harus lebih besar dari GtString", }, { - ns: "Test.UDPAddrv4", - expected: "UDPAddrv4 harus berupa alamat IPv4 UDP yang valid", + ns: "TestFieldTags.GteCSFieldString", + expected: "GteCSFieldString harus lebih besar dari atau sama dengan Inner.GteCSFieldString", }, { - ns: "Test.UDPAddrv6", - expected: "UDPAddrv6 harus berupa alamat IPv6 UDP yang valid", + ns: "TestFieldTags.GteFieldString", + expected: "GteFieldString harus lebih besar dari atau sama dengan GteString", }, { - ns: "Test.TCPAddr", - expected: "TCPAddr harus berupa alamat TCP yang valid", + ns: "TestFieldTags.LtCSFieldString", + expected: "LtCSFieldString harus kurang dari Inner.LtCSFieldString", }, { - ns: "Test.TCPAddrv4", - expected: "TCPAddrv4 harus berupa alamat TCP IPv4 yang valid", + ns: "TestFieldTags.LtFieldString", + expected: "LtFieldString harus kurang dari LtString", }, { - ns: "Test.TCPAddrv6", - expected: "TCPAddrv6 harus berupa alamat TCP IPv6 yang valid", + ns: "TestFieldTags.LteCSFieldString", + expected: "LteCSFieldString harus kurang dari atau sama dengan Inner.LteCSFieldString", }, { - ns: "Test.CIDR", - expected: "CIDR harus berisi notasi CIDR yang valid", + ns: "TestFieldTags.LteFieldString", + expected: "LteFieldString harus kurang dari atau sama dengan LteString", }, { - ns: "Test.CIDRv4", - expected: "CIDRv4 harus berisi notasi CIDR yang valid untuk alamat IPv4", + ns: "TestFieldTags.ContainsField", + expected: "ContainsField harus berisi nilai dari field Inner.FieldContains", }, { - ns: "Test.CIDRv6", - expected: "CIDRv6 harus berisi notasi CIDR yang valid untuk alamat IPv6", + ns: "TestFieldTags.ExcludesField", + expected: "ExcludesField tidak boleh berisi nilai dari field Inner.FieldExcludes", }, + } + + // verify each expected error message + for _, tt := range tests { + var fe validator.FieldError + + // find matching field error + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } +} + +// TestNetworkTagsTranslations tests all network tags registered translations for Indonesian language +func TestNetworkTagsTranslations(t *testing.T) { + // init validator with Indonesian translations + validate, trans, err := InitValidator() + Equal(t, err, nil) + + // TestNetworkTags for network validations + type TestNetworkTags struct { + CIDR string `validate:"cidr"` + CIDRv4 string `validate:"cidrv4"` + CIDRv6 string `validate:"cidrv6"` + DataURI string `validate:"datauri"` + FQDN string `validate:"fqdn"` + Hostname string `validate:"hostname"` + HostnamePort string `validate:"hostname_port"` + HostnameRFC1123 string `validate:"hostname_rfc1123"` + IP string `validate:"ip"` + IP4Addr string `validate:"ip4_addr"` + IP6Addr string `validate:"ip6_addr"` + IPAddr string `validate:"ip_addr"` + IPv4 string `validate:"ipv4"` + IPv6 string `validate:"ipv6"` + MAC string `validate:"mac"` + TCP4Addr string `validate:"tcp4_addr"` + TCP6Addr string `validate:"tcp6_addr"` + TCPAddr string `validate:"tcp_addr"` + UDP4Addr string `validate:"udp4_addr"` + UDP6Addr string `validate:"udp6_addr"` + UDPAddr string `validate:"udp_addr"` + UnixAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future + URI string `validate:"uri"` + URL string `validate:"url"` + HTTPURL string `validate:"http_url"` + URLEncoded string `validate:"url_encoded"` + URN string `validate:"urn_rfc2141"` + } + + // init test struct + test := TestNetworkTags{ + URLEncoded: "<%az", // invalid URL encoded string + } + + // validate struct + err = validate.Struct(test) + NotEqual(t, err, nil) + + // get validation errors + errs := err.(validator.ValidationErrors) + + // verify each expected error message + tests := []struct { + ns string + expected string + }{ { - ns: "Test.SSN", - expected: "SSN harus berupa nomor SSN yang valid", + ns: "TestNetworkTags.CIDR", + expected: "CIDR harus berupa notasi CIDR yang valid", }, { - ns: "Test.IP", + ns: "TestNetworkTags.CIDRv4", + expected: "CIDRv4 harus berupa notasi CIDR IPv4 yang valid", + }, + { + ns: "TestNetworkTags.CIDRv6", + expected: "CIDRv6 harus berupa notasi CIDR IPv6 yang valid", + }, + { + ns: "TestNetworkTags.DataURI", + expected: "DataURI harus berisi URI Data yang valid", + }, + { + ns: "TestNetworkTags.FQDN", + expected: "FQDN harus berupa FQDN yang valid", + }, + { + ns: "TestNetworkTags.Hostname", + expected: "Hostname harus berupa hostname sesuai RFC 952 yang valid", + }, + { + ns: "TestNetworkTags.HostnamePort", + expected: "HostnamePort harus berupa hostname dan port yang valid", + }, + { + ns: "TestNetworkTags.HostnameRFC1123", + expected: "HostnameRFC1123 harus berupa hostname sesuai RFC 1123 yang valid", + }, + { + ns: "TestNetworkTags.IP", expected: "IP harus berupa alamat IP yang valid", }, { - ns: "Test.IPv4", + ns: "TestNetworkTags.IP4Addr", + expected: "IP4Addr harus berupa alamat IPv4 yang valid", + }, + { + ns: "TestNetworkTags.IP6Addr", + expected: "IP6Addr harus berupa alamat IPv6 yang valid", + }, + { + ns: "TestNetworkTags.IPAddr", + expected: "IPAddr harus berupa alamat IP yang valid", + }, + { + ns: "TestNetworkTags.IPv4", expected: "IPv4 harus berupa alamat IPv4 yang valid", }, { - ns: "Test.IPv6", + ns: "TestNetworkTags.IPv6", expected: "IPv6 harus berupa alamat IPv6 yang valid", }, { - ns: "Test.DataURI", - expected: "DataURI harus berisi URI Data yang valid", + ns: "TestNetworkTags.MAC", + expected: "MAC harus berisi alamat MAC yang valid", }, { - ns: "Test.Latitude", - expected: "Latitude harus berisi koordinat lintang yang valid", + ns: "TestNetworkTags.TCP4Addr", + expected: "TCP4Addr harus berupa alamat TCP IPv4 yang valid", }, { - ns: "Test.Longitude", - expected: "Longitude harus berisi koordinat bujur yang valid", + ns: "TestNetworkTags.TCP6Addr", + expected: "TCP6Addr harus berupa alamat TCP IPv6 yang valid", }, { - ns: "Test.MultiByte", - expected: "MultiByte harus berisi karakter multibyte", + ns: "TestNetworkTags.TCPAddr", + expected: "TCPAddr harus berupa alamat TCP yang valid", }, { - ns: "Test.ASCII", - expected: "ASCII hanya boleh berisi karakter ascii", + ns: "TestNetworkTags.UDP4Addr", + expected: "UDP4Addr harus berupa alamat IPv4 UDP yang valid", }, { - ns: "Test.PrintableASCII", - expected: "PrintableASCII hanya boleh berisi karakter ascii yang dapat dicetak", + ns: "TestNetworkTags.UDP6Addr", + expected: "UDP6Addr harus berupa alamat IPv6 UDP yang valid", }, { - ns: "Test.UUID", - expected: "UUID harus berupa UUID yang valid", + ns: "TestNetworkTags.UDPAddr", + expected: "UDPAddr harus berupa alamat UDP yang valid", }, { - ns: "Test.UUID3", - expected: "UUID3 harus berupa UUID versi 3 yang valid", + ns: "TestNetworkTags.URI", + expected: "URI harus berupa URI yang valid", }, { - ns: "Test.UUID4", - expected: "UUID4 harus berupa UUID versi 4 yang valid", + ns: "TestNetworkTags.URL", + expected: "URL harus berupa URL yang valid", }, { - ns: "Test.UUID5", - expected: "UUID5 harus berupa UUID versi 5 yang valid", + ns: "TestNetworkTags.HTTPURL", + expected: "HTTPURL harus berupa URL HTTP/HTTPS yang valid", }, { - ns: "Test.ULID", - expected: "ULID harus berupa ULID yang valid", + ns: "TestNetworkTags.URLEncoded", + expected: "URLEncoded harus berupa string URL yang terenkode", }, { - ns: "Test.ISBN", + ns: "TestNetworkTags.URN", + expected: "URN harus berupa URN sesuai RFC 2141 yang valid", + }, + } + + // verify each expected error message + for _, tt := range tests { + var fe validator.FieldError + + // find matching field error + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } +} + +// TestStringTagsTranslations tests all string tags registered translations for Indonesian language +func TestStringTagsTranslations(t *testing.T) { + + // init validator with Indonesian translations + validate, trans, err := InitValidator() + Equal(t, err, nil) + + // TestStringTags for string validations + type TestStringTags struct { + Alpha string `validate:"alpha"` + Alphanum string `validate:"alphanum"` + AlphanumUni string `validate:"alphanumunicode"` + AlphaUni string `validate:"alphaunicode"` + ASCII string `validate:"ascii"` + Boolean string `validate:"boolean"` + Contains string `validate:"contains=test"` + ContainsAny string `validate:"containsany=!@#"` + ContainsRune string `validate:"containsrune=☺"` + EndsNotWith string `validate:"endsnotwith=end"` + EndsWith string `validate:"endswith=end"` + Excludes string `validate:"excludes=exclude"` + ExcludesAll string `validate:"excludesall=!@#"` + ExcludesRune string `validate:"excludesrune=☺"` + Lowercase string `validate:"lowercase"` + Multibyte string `validate:"multibyte"` + Number string `validate:"number"` + Numeric string `validate:"numeric"` + PrintASCII string `validate:"printascii"` + StartsNotWith string `validate:"startsnotwith=start"` + StartsWith string `validate:"startswith=start"` + Uppercase string `validate:"uppercase"` + } + + // init test struct with invalid values + test := TestStringTags{ + Alpha: "123", // should only contain letters + Alphanum: "!@#", // should only contain letters and numbers + AlphanumUni: "!@#", // should only contain unicode letters and numbers + AlphaUni: "123", // should only contain unicode letters + ASCII: "ñ", // should only contain ASCII characters + Boolean: "invalid", // should be a valid boolean + Contains: "invalid", // should contain "test" + ContainsAny: "abc", // should contain any of "!@#" + ContainsRune: "abc", // should contain "☺" + EndsNotWith: "test-end", // should not end with "end" + EndsWith: "test-no-start", // should end with "end" + Excludes: "has-exclude-here", // should not contain "exclude" + ExcludesAll: "test!@#", // should not contain any of "!@#" + ExcludesRune: "test☺here", // should not contain "☺" + Lowercase: "TEST", // should be lowercase + Multibyte: "abc", // should contain multibyte characters + Number: "abc", // should be a valid number + Numeric: "abc", // should be numeric + PrintASCII: string([]byte{0x7f}), // should only contain printable ASCII + StartsNotWith: "start-test", // should not start with "start" + StartsWith: "test-no-start", // should start with "start" + Uppercase: "test", // should be uppercase + } + + // validate struct + err = validate.Struct(test) + NotEqual(t, err, nil) + + // get validation errors + errs := err.(validator.ValidationErrors) + + // verify each expected error message + tests := []struct { + ns string + expected string + }{ + { + ns: "TestStringTags.Alpha", + expected: "Alpha hanya dapat berisi karakter alfanumerik", + }, + { + ns: "TestStringTags.Alphanum", + expected: "Alphanum hanya dapat berisi karakter alfanumerik", + }, + { + ns: "TestStringTags.AlphanumUni", + expected: "AlphanumUni hanya boleh berisi karakter alfanumerik unicode", + }, + { + ns: "TestStringTags.AlphaUni", + expected: "AlphaUni hanya boleh berisi karakter alfanumerik unicode", + }, + { + ns: "TestStringTags.ASCII", + expected: "ASCII hanya boleh berisi karakter ASCII", + }, + { + ns: "TestStringTags.Boolean", + expected: "Boolean harus berupa nilai boolean yang valid", + }, + { + ns: "TestStringTags.Contains", + expected: "Contains harus berisi teks 'test'", + }, + { + ns: "TestStringTags.ContainsAny", + expected: "ContainsAny harus berisi setidaknya salah satu karakter berikut '!@#'", + }, + { + ns: "TestStringTags.ContainsRune", + expected: "ContainsRune harus berisi setidaknya salah satu karakter berikut '☺'", + }, + { + ns: "TestStringTags.EndsNotWith", + expected: "EndsNotWith tidak boleh diakhiri dengan 'end'", + }, + { + ns: "TestStringTags.EndsWith", + expected: "EndsWith harus diakhiri dengan 'end'", + }, + { + ns: "TestStringTags.Excludes", + expected: "Excludes tidak boleh berisi teks 'exclude'", + }, + { + ns: "TestStringTags.ExcludesAll", + expected: "ExcludesAll tidak boleh berisi salah satu karakter berikut '!@#'", + }, + { + ns: "TestStringTags.ExcludesRune", + expected: "ExcludesRune tidak boleh berisi '☺'", + }, + { + ns: "TestStringTags.Lowercase", + expected: "Lowercase harus berupa string huruf kecil", + }, + { + ns: "TestStringTags.Multibyte", + expected: "Multibyte harus berisi karakter multibyte", + }, + { + ns: "TestStringTags.Number", + expected: "Number harus berupa angka yang valid", + }, + { + ns: "TestStringTags.Numeric", + expected: "Numeric harus berupa nilai numerik yang valid", + }, + { + ns: "TestStringTags.PrintASCII", + expected: "PrintASCII hanya boleh berisi karakter ASCII yang dapat dicetak", + }, + { + ns: "TestStringTags.StartsNotWith", + expected: "StartsNotWith tidak boleh diawali dengan 'start'", + }, + { + ns: "TestStringTags.StartsWith", + expected: "StartsWith harus diawali dengan 'start'", + }, + { + ns: "TestStringTags.Uppercase", + expected: "Uppercase harus berupa string huruf besar", + }, + } + + // verify each expected error message + for _, tt := range tests { + var fe validator.FieldError + + // find matching field error + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } +} + +// TestFormatTagsTranslations tests all format tags registered translations for Indonesian language +func TestFormatTagsTranslations(t *testing.T) { + + // init validator with Indonesian translations + validate, trans, err := InitValidator() + Equal(t, err, nil) + + // TestFormatTags for format validations + type TestFormatTags struct { + Hexadecimal string `validate:"hexadecimal"` + Base64 string `validate:"base64"` + Base64URL string `validate:"base64url"` + Base64RawURL string `validate:"base64rawurl"` + BIC string `validate:"bic"` + BCP47Lang string `validate:"bcp47_language_tag"` + BTCAddr string `validate:"btc_addr"` + BTCAddrBech32 string `validate:"btc_addr_bech32"` + CreditCard string `validate:"credit_card"` + MongoDB string `validate:"mongodb"` + MongoDBConn string `validate:"mongodb_connection_string"` + Cron string `validate:"cron"` + SpiceDB string `validate:"spicedb"` + DateTime string `validate:"datetime=2006-01-02"` + E164 string `validate:"e164"` + Email string `validate:"email"` + EthAddr string `validate:"eth_addr"` + HexColor string `validate:"hexcolor"` + HSL string `validate:"hsl"` + HSLA string `validate:"hsla"` + HTML string `validate:"html"` + HTMLEncoded string `validate:"html_encoded"` + ISBN string `validate:"isbn"` + ISBN10 string `validate:"isbn10"` + ISBN13 string `validate:"isbn13"` + ISSN string `validate:"issn"` + ISO3166Alpha2 string `validate:"iso3166_1_alpha2"` + ISO3166Alpha3 string `validate:"iso3166_1_alpha3"` + ISO3166AlphaNumeric string `validate:"iso3166_1_alpha_numeric"` + ISO31662 string `validate:"iso3166_2"` + ISO4217 string `validate:"iso4217"` + JSON string `validate:"json"` + JWT string `validate:"jwt"` + Latitude string `validate:"latitude"` + Longitude string `validate:"longitude"` + LuhnChecksum string `validate:"luhn_checksum"` + PostcodeISO3166Alpha2 string `validate:"postcode_iso3166_alpha2"` + PostcodeISO3166Alpha2Field string `validate:"postcode_iso3166_alpha2_field"` + RGB string `validate:"rgb"` + RGBA string `validate:"rgba"` + SSN string `validate:"ssn"` + Timezone string `validate:"timezone"` + UUID string `validate:"uuid"` + UUID3 string `validate:"uuid3"` + UUID3RFC4122 string `validate:"uuid3_rfc4122"` + UUID4 string `validate:"uuid4"` + UUID4RFC4122 string `validate:"uuid4_rfc4122"` + UUID5 string `validate:"uuid5"` + UUID5RFC4122 string `validate:"uuid5_rfc4122"` + UUIDRFC4122 string `validate:"uuid_rfc4122"` + MD4 string `validate:"md4"` + MD5 string `validate:"md5"` + SHA256 string `validate:"sha256"` + SHA384 string `validate:"sha384"` + SHA512 string `validate:"sha512"` + RIPEMD128 string `validate:"ripemd128"` + RIPEMD160 string `validate:"ripemd160"` + Tiger128 string `validate:"tiger128"` + Tiger160 string `validate:"tiger160"` + Tiger192 string `validate:"tiger192"` + Semver string `validate:"semver"` + ULID string `validate:"ulid"` + CVE string `validate:"cve"` + } + + // init test struct with invalid values + test := TestFormatTags{} + + // validate struct + err = validate.Struct(test) + NotEqual(t, err, nil) + + // get validation errors + errs := err.(validator.ValidationErrors) + + // verify each expected error message + tests := []struct { + ns string + expected string + }{ + { + ns: "TestFormatTags.Hexadecimal", + expected: "Hexadecimal harus berupa heksadesimal yang valid", + }, + { + ns: "TestFormatTags.Base64", + expected: "Base64 harus berupa string Base64 yang valid", + }, + { + ns: "TestFormatTags.Base64URL", + expected: "Base64URL harus berupa string Base64 URL yang valid", + }, + { + ns: "TestFormatTags.Base64RawURL", + expected: "Base64RawURL harus berupa string Base64 Raw URL yang valid", + }, + { + ns: "TestFormatTags.BIC", + expected: "BIC harus berupa kode BIC (SWIFT) yang valid sesuai ISO 9362", + }, + { + ns: "TestFormatTags.BCP47Lang", + expected: "BCP47Lang harus berupa tag bahasa BCP 47 yang valid", + }, + { + ns: "TestFormatTags.BTCAddr", + expected: "BTCAddr harus berupa alamat Bitcoin yang valid", + }, + { + ns: "TestFormatTags.BTCAddrBech32", + expected: "BTCAddrBech32 harus berupa alamat Bitcoin Bech32 yang valid", + }, + { + ns: "TestFormatTags.CreditCard", + expected: "CreditCard harus berupa nomor kartu kredit yang valid", + }, + { + ns: "TestFormatTags.MongoDB", + expected: "MongoDB harus berupa ObjectID MongoDB yang valid", + }, + { + ns: "TestFormatTags.MongoDBConn", + expected: "MongoDBConn harus berupa string koneksi MongoDB yang valid", + }, + { + ns: "TestFormatTags.Cron", + expected: "Cron harus berupa ekspresi cron yang valid", + }, + { + ns: "TestFormatTags.SpiceDB", + expected: "SpiceDB harus berupa format SpiceDB yang valid", + }, + { + ns: "TestFormatTags.DateTime", + expected: "DateTime tidak sesuai dengan format 2006-01-02", + }, + { + ns: "TestFormatTags.E164", + expected: "E164 harus berupa nomor telepon format E.164 yang valid", + }, + { + ns: "TestFormatTags.Email", + expected: "Email harus berupa alamat email yang valid", + }, + { + ns: "TestFormatTags.EthAddr", + expected: "EthAddr harus berupa alamat Ethereum yang valid", + }, + { + ns: "TestFormatTags.HexColor", + expected: "HexColor harus berupa warna HEX yang valid", + }, + { + ns: "TestFormatTags.HSL", + expected: "HSL harus berupa warna HSL yang valid", + }, + { + ns: "TestFormatTags.HSLA", + expected: "HSLA harus berupa warna HSLA yang valid", + }, + { + ns: "TestFormatTags.HTML", + expected: "HTML harus berupa HTML yang valid", + }, + { + ns: "TestFormatTags.HTMLEncoded", + expected: "HTMLEncoded harus berupa HTML terenkode yang valid", + }, + { + ns: "TestFormatTags.ISBN", expected: "ISBN harus berupa nomor ISBN yang valid", }, { - ns: "Test.ISBN10", + ns: "TestFormatTags.ISBN10", expected: "ISBN10 harus berupa nomor ISBN-10 yang valid", }, { - ns: "Test.ISBN13", + ns: "TestFormatTags.ISBN13", expected: "ISBN13 harus berupa nomor ISBN-13 yang valid", }, { - ns: "Test.ISSN", + ns: "TestFormatTags.ISSN", expected: "ISSN harus berupa nomor ISSN yang valid", }, { - ns: "Test.Excludes", - expected: "Excludes tidak boleh berisi teks 'text'", + ns: "TestFormatTags.ISO3166Alpha2", + expected: "ISO3166Alpha2 harus berupa kode negara ISO 3166-1 alpha-2 yang valid", }, { - ns: "Test.ExcludesAll", - expected: "ExcludesAll tidak boleh berisi salah satu karakter berikut '!@#$'", + ns: "TestFormatTags.ISO3166Alpha3", + expected: "ISO3166Alpha3 harus berupa kode negara ISO 3166-1 alpha-3 yang valid", }, { - ns: "Test.ExcludesRune", - expected: "ExcludesRune tidak boleh berisi '☻'", + ns: "TestFormatTags.ISO3166AlphaNumeric", + expected: "ISO3166AlphaNumeric harus berupa kode negara numerik ISO 3166-1 yang valid", }, { - ns: "Test.ContainsAny", - expected: "ContainsAny harus berisi setidaknya salah satu karakter berikut '!@#$'", + ns: "TestFormatTags.ISO31662", + expected: "ISO31662 harus berupa kode subdivisi negara ISO 3166-2 yang valid", }, { - ns: "Test.Contains", - expected: "Contains harus berisi teks 'tujuan'", + ns: "TestFormatTags.ISO4217", + expected: "ISO4217 harus berupa kode mata uang ISO 4217 yang valid", }, { - ns: "Test.Base64", - expected: "Base64 harus berupa string Base64 yang valid", + ns: "TestFormatTags.JSON", + expected: "JSON harus berupa string JSON yang valid", }, { - ns: "Test.Email", - expected: "Email harus berupa alamat email yang valid", + ns: "TestFormatTags.JWT", + expected: "JWT harus berupa JSON Web Token (JWT) yang valid", }, { - ns: "Test.URL", - expected: "URL harus berupa URL yang valid", + ns: "TestFormatTags.Latitude", + expected: "Latitude harus berisi koordinat lintang yang valid", }, { - ns: "Test.URI", - expected: "URI harus berupa URI yang valid", + ns: "TestFormatTags.Longitude", + expected: "Longitude harus berisi koordinat bujur yang valid", + }, + { + ns: "TestFormatTags.LuhnChecksum", + expected: "LuhnChecksum harus memiliki checksum Luhn yang valid", + }, + { + ns: "TestFormatTags.PostcodeISO3166Alpha2", + expected: "PostcodeISO3166Alpha2 tidak sesuai dengan format kode pos negara ", }, { - ns: "Test.RGBColorString", - expected: "RGBColorString harus berupa warna RGB yang valid", + ns: "TestFormatTags.PostcodeISO3166Alpha2Field", + expected: "PostcodeISO3166Alpha2Field tidak sesuai dengan format kode pos negara dalam field ", }, { - ns: "Test.RGBAColorString", - expected: "RGBAColorString harus berupa warna RGBA yang valid", + ns: "TestFormatTags.RGB", + expected: "RGB harus berupa warna RGB yang valid", }, { - ns: "Test.HSLColorString", - expected: "HSLColorString harus berupa warna HSL yang valid", + ns: "TestFormatTags.RGBA", + expected: "RGBA harus berupa warna RGBA yang valid", }, { - ns: "Test.HSLAColorString", - expected: "HSLAColorString harus berupa warna HSLA yang valid", + ns: "TestFormatTags.SSN", + expected: "SSN harus berupa nomor SSN (Social Security Number) yang valid", }, { - ns: "Test.HexadecimalString", - expected: "HexadecimalString harus berupa heksadesimal yang valid", + ns: "TestFormatTags.Timezone", + expected: "Timezone harus berupa zona waktu yang valid", }, { - ns: "Test.HexColorString", - expected: "HexColorString harus berupa warna HEX yang valid", + ns: "TestFormatTags.UUID", + expected: "UUID harus berupa UUID yang valid", }, { - ns: "Test.NumberString", - expected: "NumberString harus berupa angka yang valid", + ns: "TestFormatTags.UUID3", + expected: "UUID3 harus berupa UUID versi 3 yang valid", }, { - ns: "Test.NumericString", - expected: "NumericString harus berupa nilai numerik yang valid", + ns: "TestFormatTags.UUID3RFC4122", + expected: "UUID3RFC4122 harus berupa UUID versi 3 RFC4122 yang valid", }, { - ns: "Test.AlphanumString", - expected: "AlphanumString hanya dapat berisi karakter alfanumerik", + ns: "TestFormatTags.UUID4", + expected: "UUID4 harus berupa UUID versi 4 yang valid", }, { - ns: "Test.AlphaString", - expected: "AlphaString hanya dapat berisi karakter abjad", + ns: "TestFormatTags.UUID4RFC4122", + expected: "UUID4RFC4122 harus berupa UUID versi 4 RFC4122 yang valid", }, { - ns: "Test.LtFieldString", - expected: "LtFieldString harus kurang dari MaxString", + ns: "TestFormatTags.UUID5", + expected: "UUID5 harus berupa UUID versi 5 yang valid", }, { - ns: "Test.LteFieldString", - expected: "LteFieldString harus kurang dari atau sama dengan MaxString", + ns: "TestFormatTags.UUID5RFC4122", + expected: "UUID5RFC4122 harus berupa UUID versi 5 RFC4122 yang valid", }, { - ns: "Test.GtFieldString", - expected: "GtFieldString harus lebih besar dari MaxString", + ns: "TestFormatTags.UUIDRFC4122", + expected: "UUIDRFC4122 harus berupa UUID RFC4122 yang valid", }, { - ns: "Test.GteFieldString", - expected: "GteFieldString harus lebih besar dari atau sama dengan MaxString", + ns: "TestFormatTags.MD4", + expected: "MD4 harus berupa hash MD4 yang valid", }, { - ns: "Test.NeFieldString", - expected: "NeFieldString tidak sama dengan EqFieldString", + ns: "TestFormatTags.MD5", + expected: "MD5 harus berupa hash MD5 yang valid", }, { - ns: "Test.LtCSFieldString", - expected: "LtCSFieldString harus kurang dari Inner.LtCSFieldString", + ns: "TestFormatTags.SHA256", + expected: "SHA256 harus berupa hash SHA256 yang valid", }, { - ns: "Test.LteCSFieldString", - expected: "LteCSFieldString harus kurang dari atau sama dengan Inner.LteCSFieldString", + ns: "TestFormatTags.SHA384", + expected: "SHA384 harus berupa hash SHA384 yang valid", }, { - ns: "Test.GtCSFieldString", - expected: "GtCSFieldString harus lebih besar dari Inner.GtCSFieldString", + ns: "TestFormatTags.SHA512", + expected: "SHA512 harus berupa hash SHA512 yang valid", }, { - ns: "Test.GteCSFieldString", - expected: "GteCSFieldString harus lebih besar dari atau sama dengan Inner.GteCSFieldString", + ns: "TestFormatTags.RIPEMD128", + expected: "RIPEMD128 harus berupa hash RIPEMD128 yang valid", }, { - ns: "Test.NeCSFieldString", - expected: "NeCSFieldString tidak sama dengan Inner.NeCSFieldString", + ns: "TestFormatTags.RIPEMD160", + expected: "RIPEMD160 harus berupa hash RIPEMD160 yang valid", }, { - ns: "Test.EqCSFieldString", - expected: "EqCSFieldString harus sama dengan Inner.EqCSFieldString", + ns: "TestFormatTags.Tiger128", + expected: "Tiger128 harus berupa hash TIGER128 yang valid", }, { - ns: "Test.EqFieldString", - expected: "EqFieldString harus sama dengan MaxString", + ns: "TestFormatTags.Tiger160", + expected: "Tiger160 harus berupa hash TIGER160 yang valid", }, { - ns: "Test.GteString", - expected: "panjang minimal GteString adalah 3 karakter", + ns: "TestFormatTags.Tiger192", + expected: "Tiger192 harus berupa hash TIGER192 yang valid", }, { - ns: "Test.GteNumber", - expected: "GteNumber harus 5,56 atau lebih besar", + ns: "TestFormatTags.Semver", + expected: "Semver harus berupa nomor versi semantik yang valid", }, { - ns: "Test.GteMultiple", - expected: "GteMultiple harus berisi setidaknya 2 item", + ns: "TestFormatTags.ULID", + expected: "ULID harus berupa ULID yang valid", }, { - ns: "Test.GteTime", - expected: "GteTime harus lebih besar dari atau sama dengan tanggal & waktu saat ini", + ns: "TestFormatTags.CVE", + expected: "CVE harus berupa identifikasi CVE yang valid", + }, + } + + // verify each expected error message + for _, tt := range tests { + var fe validator.FieldError + + // find matching field error + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } +} + +// TestComparisonTagsTranslations tests all comparison tags registered translations for Indonesian language +func TestComparisonTagsTranslations(t *testing.T) { + + // init validator with Indonesian translations + validate, trans, err := InitValidator() + Equal(t, err, nil) + + // TestComparisonTags for comparison validations + type TestComparisonTags struct { + // Equal comparisons + EqString string `validate:"eq=test"` + EqNumber int `validate:"eq=10"` + EqIgnoreCase string `validate:"eq_ignore_case=Test"` + + // Not equal comparisons + NeString string `validate:"ne=test"` + NeNumber int `validate:"ne=10"` + NeIgnoreCase string `validate:"ne_ignore_case=Test"` + + // Greater than comparisons + GtString string `validate:"gt=5"` // length > 5 + GtNumber float64 `validate:"gt=10.5"` + GtTime time.Time `validate:"gt"` + GtSlice []string `validate:"gt=1"` // length > 1 + + // Greater than or equal comparisons + GteString string `validate:"gte=5"` // length >= 5 + GteNumber float64 `validate:"gte=10.5"` + GteTime time.Time `validate:"gte"` + GteSlice []string `validate:"gte=1"` // length >= 1 + + // Less than comparisons + LtString string `validate:"lt=5"` // length < 5 + LtNumber float64 `validate:"lt=10.5"` + LtTime time.Time `validate:"lt"` + LtSlice []string `validate:"lt=2"` // length < 1 + + // Less than or equal comparisons + LteString string `validate:"lte=5"` // length <= 5 + LteNumber float64 `validate:"lte=10.5"` + LteTime time.Time `validate:"lte"` + LteSlice []string `validate:"lte=1"` // length <= 1 + } + + // init test struct with invalid values + now := time.Now() + test := TestComparisonTags{ + EqString: "not-test", + EqNumber: 20, + EqIgnoreCase: "not-test", + + NeString: "test", + NeNumber: 10, + NeIgnoreCase: "Test", + + GtString: "abc", // length = 3, should be > 5 + GtNumber: 5.5, // should be > 10.5 + GtTime: now.Add(-time.Hour), // should be > now + + GteString: "abc", // length = 3, should be >= 5 + GteNumber: 5.5, // should be >= 10.5 + GteTime: now.Add(-time.Hour), // should be >= now + + LtString: "toolong", // length = 7, should be < 5 + LtNumber: 15.5, // should be < 10.5 + LtTime: now.Add(time.Hour), // should be < now + LtSlice: []string{"satu", "dua"}, // should be < 2 + + LteString: "toolong", // length = 7, should be <= 5 + LteNumber: 15.5, // should be <= 10.5 + LteTime: now.Add(time.Hour), // should be <= now + LteSlice: []string{"satu", "dua"}, // should be <= 1 + } + + // validate struct + err = validate.Struct(test) + NotEqual(t, err, nil) + + // get validation errors + errs := err.(validator.ValidationErrors) + + // verify each expected error message + tests := []struct { + ns string + expected string + }{ + { + ns: "TestComparisonTags.EqString", + expected: "EqString tidak sama dengan test", + }, + { + ns: "TestComparisonTags.EqNumber", + expected: "EqNumber tidak sama dengan 10", + }, + { + ns: "TestComparisonTags.EqIgnoreCase", + expected: "EqIgnoreCase harus sama dengan Test (tidak case-sensitive)", + }, + { + ns: "TestComparisonTags.NeString", + expected: "NeString tidak sama dengan test", + }, + { + ns: "TestComparisonTags.NeNumber", + expected: "NeNumber tidak sama dengan 10", }, { - ns: "Test.GtString", - expected: "panjang GtString harus lebih dari 3 karakter", + ns: "TestComparisonTags.NeIgnoreCase", + expected: "NeIgnoreCase tidak sama dengan Test (tidak case-sensitive)", }, { - ns: "Test.GtNumber", - expected: "GtNumber harus lebih besar dari 5,56", + ns: "TestComparisonTags.GtString", + expected: "panjang GtString harus lebih dari 5 karakter", }, { - ns: "Test.GtMultiple", - expected: "GtMultiple harus berisi lebih dari 2 item", + ns: "TestComparisonTags.GtNumber", + expected: "GtNumber harus lebih besar dari 10,5", }, { - ns: "Test.GtTime", + ns: "TestComparisonTags.GtTime", expected: "GtTime harus lebih besar dari tanggal & waktu saat ini", }, { - ns: "Test.LteString", - expected: "panjang maksimal LteString adalah 3 karakter", + ns: "TestComparisonTags.GtSlice", + expected: "GtSlice harus berisi lebih dari 1 item", }, { - ns: "Test.LteNumber", - expected: "LteNumber harus 5,56 atau kurang", + ns: "TestComparisonTags.GteString", + expected: "panjang minimal GteString adalah 5 karakter", }, { - ns: "Test.LteMultiple", - expected: "LteMultiple harus berisi maksimal 2 item", + ns: "TestComparisonTags.GteNumber", + expected: "GteNumber harus 10,5 atau lebih besar", }, { - ns: "Test.LteTime", - expected: "LteTime harus kurang dari atau sama dengan tanggal & waktu saat ini", + ns: "TestComparisonTags.GteTime", + expected: "GteTime harus lebih besar dari atau sama dengan tanggal & waktu saat ini", }, { - ns: "Test.LtString", - expected: "panjang LtString harus kurang dari 3 karakter", + ns: "TestComparisonTags.GteSlice", + expected: "GteSlice harus berisi setidaknya 1 item", }, { - ns: "Test.LtNumber", - expected: "LtNumber harus kurang dari 5,56", + ns: "TestComparisonTags.LtString", + expected: "panjang LtString harus kurang dari 5 karakter", }, { - ns: "Test.LtMultiple", - expected: "LtMultiple harus berisi kurang dari 2 item", + ns: "TestComparisonTags.LtNumber", + expected: "LtNumber harus kurang dari 10,5", }, { - ns: "Test.LtTime", + ns: "TestComparisonTags.LtTime", expected: "LtTime harus kurang dari tanggal & waktu saat ini", }, { - ns: "Test.NeString", - expected: "NeString tidak sama dengan ", + ns: "TestComparisonTags.LtSlice", + expected: "LtSlice harus berisi kurang dari 2 item", + }, + { + ns: "TestComparisonTags.LteString", + expected: "panjang maksimal LteString adalah 5 karakter", }, { - ns: "Test.NeNumber", - expected: "NeNumber tidak sama dengan 0.00", + ns: "TestComparisonTags.LteNumber", + expected: "LteNumber harus 10,5 atau kurang", + }, + { + ns: "TestComparisonTags.LteTime", + expected: "LteTime harus kurang dari atau sama dengan tanggal & waktu saat ini", + }, + { + ns: "TestComparisonTags.LteSlice", + expected: "LteSlice harus berisi maksimal 1 item", + }, + } + + // verify each expected error message + for _, tt := range tests { + var fe validator.FieldError + + // find matching field error + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } +} + +// TestOtherTagsTranslations tests all other tags registered translations for Indonesian language +func TestOtherTagsTranslations(t *testing.T) { + + // init validator with Indonesian translations + validate, trans, err := InitValidator() + Equal(t, err, nil) + + // TestOtherTags for other validations + type Inner struct { + RequiredWith string + ExcludedWith string + Field string + } + + type TestOtherTags struct { + Dir string `validate:"dir"` + DirPath string `validate:"dirpath"` + File string `validate:"file"` + FilePath string `validate:"filepath"` + Image string `validate:"image"` + LenString string `validate:"len=5"` + LenSlice []string `validate:"len=3"` + LenNumber int `validate:"len=10"` + MinString string `validate:"min=3"` + MinSlice []string `validate:"min=1"` + MaxString string `validate:"max=5"` + MaxSlice []string `validate:"max=1"` + IsDefault string `validate:"isdefault"` + Required string `validate:"required"` + RequiredIf string `validate:"required_if=Inner.RequiredWith value"` + RequiredUnless string `validate:"required_unless=Inner.RequiredWith values"` + RequiredWith string `validate:"required_with=Inner.RequiredWith"` + RequiredWithAll string `validate:"required_with_all=Inner.RequiredWith"` + RequiredWithout string `validate:"required_without=Inner.ExcludedWith"` + RequiredWithoutAll string `validate:"required_without_all=Inner.ExcludedWith"` + ExcludedIf string `validate:"excluded_if=Inner.RequiredWith value"` + ExcludedUnless string `validate:"excluded_unless=Inner.ExcludedWith value"` + ExcludedWith string `validate:"excluded_with=Inner.RequiredWith"` + ExcludedWithAll string `validate:"excluded_with_all=Inner.RequiredWith"` + ExcludedWithout string `validate:"excluded_without=Inner.ExcludedWith"` + ExcludedWithoutAll string `validate:"excluded_without_all=Inner.ExcludedWith"` + OneOf string `validate:"oneof=red green blue"` + Unique []string `validate:"unique"` + Inner Inner + } + + // init test struct with invalid values + test := TestOtherTags{ + Dir: "nonexistent", + DirPath: "invalid/dir/path", + File: "nonexistent.txt", + Image: "not-an-image.txt", + + LenString: "toolong", // should be exactly 5 chars + LenSlice: []string{"a", "b"}, // should be exactly 3 items + LenNumber: 5, // should be 10 + MinString: "ab", // should be min 3 chars + MinSlice: []string{}, // should be min 1 item + MaxString: "toolong", // should be max 5 chars + MaxSlice: []string{"satu", "dua"}, // should be max 1 item + + IsDefault: "non-default", + + ExcludedIf: "value", // should fail when Inner.RequiredWith is "value" + ExcludedUnless: "value", // should fail unless Inner.ExcludedWith is "value" + ExcludedWith: "value", // should fail when Inner.Field is populated + ExcludedWithAll: "value", // should fail when both Inner.Field and Inner.ExcludedWith are populated + ExcludedWithout: "value", // should fail when Inner.ExcludedWith is not populated + ExcludedWithoutAll: "value", // should fail when Inner.ExcludedWithoutAll is not populated + + OneOf: "yellow", // not in [red green blue] + Unique: []string{"a", "a"}, // contains duplicate + + Inner: Inner{ + RequiredWith: "value", // triggers required_if validation + ExcludedWith: "", // triggers excluded_unless validation }, + } + + // validate struct + err = validate.Struct(test) + NotEqual(t, err, nil) + + // get validation errors + errs := err.(validator.ValidationErrors) + + // verify each expected error message + tests := []struct { + ns string + expected string + }{ { - ns: "Test.NeMultiple", - expected: "NeMultiple tidak sama dengan 0", + ns: "TestOtherTags.Dir", + expected: "Dir harus berupa direktori yang ada", }, { - ns: "Test.EqString", - expected: "EqString tidak sama dengan 3", + ns: "TestOtherTags.DirPath", + expected: "DirPath harus berupa path direktori yang valid", }, { - ns: "Test.EqNumber", - expected: "EqNumber tidak sama dengan 2.33", + ns: "TestOtherTags.File", + expected: "File harus berupa file yang valid", }, { - ns: "Test.EqMultiple", - expected: "EqMultiple tidak sama dengan 7", + ns: "TestOtherTags.FilePath", + expected: "FilePath harus berupa path file yang valid", }, { - ns: "Test.MaxString", - expected: "panjang maksimal MaxString adalah 3 karakter", + ns: "TestOtherTags.Image", + expected: "Image harus berupa gambar yang valid", }, { - ns: "Test.MaxNumber", - expected: "MaxNumber harus 1.113,00 atau kurang", + ns: "TestOtherTags.LenString", + expected: "panjang LenString harus 5 karakter", }, { - ns: "Test.MaxMultiple", - expected: "MaxMultiple harus berisi maksimal 7 item", + ns: "TestOtherTags.LenSlice", + expected: "LenSlice harus berisi 3 item", }, { - ns: "Test.MinString", - expected: "panjang minimal MinString adalah 1 karakter", + ns: "TestOtherTags.LenNumber", + expected: "LenNumber harus sama dengan 10", }, { - ns: "Test.MinNumber", - expected: "MinNumber harus 1.113,00 atau lebih besar", + ns: "TestOtherTags.MinString", + expected: "panjang minimal MinString adalah 3 karakter", }, { - ns: "Test.MinMultiple", - expected: "panjang minimal MinMultiple adalah 7 item", + ns: "TestOtherTags.MinSlice", + expected: "MinSlice harus berisi minimal 1 item", }, { - ns: "Test.LenString", - expected: "panjang LenString harus 1 karakter", + ns: "TestOtherTags.MaxString", + expected: "panjang maksimal MaxString adalah 5 karakter", }, { - ns: "Test.LenNumber", - expected: "LenNumber harus sama dengan 1.113,00", + ns: "TestOtherTags.MaxSlice", + expected: "MaxSlice harus berisi maksimal 1 item", }, { - ns: "Test.LenMultiple", - expected: "LenMultiple harus berisi 7 item", + ns: "TestOtherTags.IsDefault", + expected: "IsDefault harus berupa nilai default", }, { - ns: "Test.RequiredString", - expected: "RequiredString wajib diisi", + ns: "TestOtherTags.Required", + expected: "Required wajib diisi", }, { - ns: "Test.RequiredNumber", - expected: "RequiredNumber wajib diisi", + ns: "TestOtherTags.RequiredIf", + expected: "RequiredIf wajib diisi jika Inner.RequiredWith value", }, { - ns: "Test.RequiredMultiple", - expected: "RequiredMultiple wajib diisi", + ns: "TestOtherTags.RequiredUnless", + expected: "RequiredUnless wajib diisi kecuali Inner.RequiredWith values", }, { - ns: "Test.StrPtrMinLen", - expected: "panjang minimal StrPtrMinLen adalah 10 karakter", + ns: "TestOtherTags.RequiredWith", + expected: "RequiredWith wajib diisi jika Inner.RequiredWith telah diisi", }, { - ns: "Test.StrPtrMaxLen", - expected: "panjang maksimal StrPtrMaxLen adalah 1 karakter", + ns: "TestOtherTags.RequiredWithAll", + expected: "RequiredWithAll wajib diisi jika Inner.RequiredWith telah diisi", }, { - ns: "Test.StrPtrLen", - expected: "panjang StrPtrLen harus 2 karakter", + ns: "TestOtherTags.RequiredWithout", + expected: "RequiredWithout wajib diisi jika Inner.ExcludedWith tidak diisi", }, { - ns: "Test.StrPtrLt", - expected: "panjang StrPtrLt harus kurang dari 1 karakter", + ns: "TestOtherTags.RequiredWithoutAll", + expected: "RequiredWithoutAll wajib diisi jika Inner.ExcludedWith tidak diisi", }, { - ns: "Test.StrPtrLte", - expected: "panjang maksimal StrPtrLte adalah 1 karakter", + ns: "TestOtherTags.ExcludedIf", + expected: "ExcludedIf tidak boleh diisi jika Inner.RequiredWith value", }, { - ns: "Test.StrPtrGt", - expected: "panjang StrPtrGt harus lebih dari 10 karakter", + ns: "TestOtherTags.ExcludedUnless", + expected: "ExcludedUnless tidak boleh diisi kecuali Inner.ExcludedWith value", }, { - ns: "Test.StrPtrGte", - expected: "panjang minimal StrPtrGte adalah 10 karakter", + ns: "TestOtherTags.ExcludedWith", + expected: "ExcludedWith tidak boleh diisi jika Inner.RequiredWith telah diisi", }, { - ns: "Test.OneOfString", - expected: "OneOfString harus berupa salah satu dari [merah hijau]", + ns: "TestOtherTags.ExcludedWithAll", + expected: "ExcludedWithAll tidak boleh diisi jika semua Inner.RequiredWith telah diisi", }, { - ns: "Test.OneOfInt", - expected: "OneOfInt harus berupa salah satu dari [5 63]", + ns: "TestOtherTags.ExcludedWithout", + expected: "ExcludedWithout tidak boleh diisi jika Inner.ExcludedWith tidak diisi", }, { - ns: "Test.Image", - expected: "Image harus berupa gambar yang valid", + ns: "TestOtherTags.ExcludedWithoutAll", + expected: "ExcludedWithoutAll tidak boleh diisi jika Inner.ExcludedWith tidak diisi", + }, + { + ns: "TestOtherTags.OneOf", + expected: "OneOf harus berupa salah satu dari [red green blue]", + }, + { + ns: "TestOtherTags.Unique", + expected: "Unique harus berisi nilai yang unik", }, } + // verify each expected error message for _, tt := range tests { - var fe validator.FieldError + // find matching field error for _, e := range errs { if tt.ns == e.Namespace() { fe = e @@ -645,5 +1343,100 @@ func TestTranslations(t *testing.T) { NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } +} + +// TestAliasesTagsTranslations tests all aliases tags registered translations for Indonesian language +func TestAliasesTagsTranslations(t *testing.T) { + + // init validator with Indonesian translations + validate, trans, err := InitValidator() + Equal(t, err, nil) + + // TestAliasTags for alias validations + type TestAliasTags struct { + // Color validations + Color string `validate:"iscolor"` + HexColor string `validate:"hexcolor"` + RGBColor string `validate:"rgb"` + RGBAColor string `validate:"rgba"` + HSLColor string `validate:"hsl"` + HSLAColor string `validate:"hsla"` + + // Country code validation + CountryCode string `validate:"country_code"` + ISO2Code string `validate:"iso3166_1_alpha2"` + ISO3Code string `validate:"iso3166_1_alpha3"` + } + + // init test struct with invalid values + test := TestAliasTags{ + Color: "not-a-color", + HexColor: "not-hex", + RGBColor: "not-rgb", + RGBAColor: "not-rgba", + HSLColor: "not-hsl", + HSLAColor: "not-hsla", + + CountryCode: "XX", // invalid country code + ISO2Code: "XX", // invalid ISO 3166-1 alpha-2 + ISO3Code: "XXX", // invalid ISO 3166-1 alpha-3 + } + + // validate struct + err = validate.Struct(test) + NotEqual(t, err, nil) + + // get validation errors + errs := err.(validator.ValidationErrors) + + // verify each expected error message + tests := []struct { + ns string + expected string + }{ + { + ns: "TestAliasTags.Color", + expected: "Color harus berupa warna yang valid", + }, + { + ns: "TestAliasTags.HexColor", + expected: "HexColor harus berupa warna HEX yang valid", + }, + { + ns: "TestAliasTags.RGBColor", + expected: "RGBColor harus berupa warna RGB yang valid", + }, + { + ns: "TestAliasTags.RGBAColor", + expected: "RGBAColor harus berupa warna RGBA yang valid", + }, + { + ns: "TestAliasTags.HSLColor", + expected: "HSLColor harus berupa warna HSL yang valid", + }, + { + ns: "TestAliasTags.HSLAColor", + expected: "HSLAColor harus berupa warna HSLA yang valid", + }, + { + ns: "TestAliasTags.CountryCode", + expected: "CountryCode harus berupa kode negara yang valid", + }, + } + // verify each expected error message + for _, tt := range tests { + var fe validator.FieldError + + // find matching field error + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } }