Repository: go-playground/validator
Pull request #1376 (2025-02-14 11:23:40)

feat(translations): improve Indonesian translations and add tests
## Enhances
- Add comprehensive test coverage for all validation tags
- Improve Indonesian translation messages for better clarity
- Add tests for field, network, string, format, comparison, other, and alias tags
- Ensure consistent translation style across all validation messages
- Follow idiomatic Indonesian language patterns
- Grouping each tags based on README.md (Field, Network, Strings, etc.)

### Tests cover:
- Field validations (required, min, max, etc.)
- Network validations (email, ip, url, etc.)
- String validations (alpha, contains, etc.)
- Format validations (datetime, uuid, etc.)
- Comparison validations (eq, gt, lt, etc.)
- Other validations (file, unique, etc.)
- Alias validations (color, country code)

**Make sure that you've checked the boxes below before you submit PR:**
- [x] Tests exist or have been written that cover this particular change.

@go-playground/validator-maintainers


Patch:
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 40b774a..0000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,16 +0,0 @@
-- [ ] I have looked at the documentation [here](https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation) first?
-- [ ] I have looked at the examples provided that may showcase my question [here](/_examples)?
-
-### Package version eg. v9, v10: 
-
-
-
-### Issue, Question or Enhancement:
-
-
-
-### Code sample, to showcase or reproduce:
-
-```go
-
-```
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..38dce27
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,31 @@
+name: Bug Report
+description: File a bug report
+title: "[Bug]: "
+labels: ["bug"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thanks for taking the time to fill out this bug report!
+  - type: textarea
+    id: what-happened
+    attributes:
+      label: What happened?
+      description: Also tell us, what did you expect to happen?
+    validations:
+      required: true
+  - type: textarea
+    id: version
+    attributes:
+      label: Version
+      description: What version of validator are you running?
+    validations:
+      required: true
+  - type: textarea
+    id: code
+    attributes:
+      label: Example Code
+      description: Please provide a code example that demonstrates the issue
+      render: go
+    validations:
+      required: true 
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..ce811d1
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+# Maintain dependencies for Golang
+- package-ecosystem: gomod
+  directory: "/"
+  schedule:
+    interval: weekly
+# Maintain dependencies for GitHub Actions
+- package-ecosystem: github-actions
+  directory: "/"
+  schedule:
+    interval: weekly
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 04507cb..9235bbe 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -38,6 +38,6 @@ jobs:
         with:
           go-version: 1.23.x
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v4
+        uses: golangci/golangci-lint-action@v6
         with:
           version: latest
diff --git a/README.md b/README.md
index ee51a5f..e273e39 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 Package validator
 =================
 <img align="right" src="logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-![Project status](https://img.shields.io/badge/version-10.24.0-green.svg)
+![Project status](https://img.shields.io/badge/version-10.25.0-green.svg)
 [![Build Status](https://github.com/go-playground/validator/actions/workflows/workflow.yml/badge.svg)](https://github.com/go-playground/validator/actions)
 [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
 [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
diff --git a/_examples/simple/main.go b/_examples/simple/main.go
index 5a5da4d..606822b 100644
--- a/_examples/simple/main.go
+++ b/_examples/simple/main.go
@@ -62,7 +62,8 @@ func validateStruct() {
 		// this check is only needed when your code could produce
 		// an invalid value for validation such as interface with nil
 		// value most including myself do not usually have code like this.
-		if errors.As(err, &validator.InvalidValidationError{}) {
+		var invalidValidationError *validator.InvalidValidationError
+		if errors.As(err, &invalidValidationError) {
 			fmt.Println(err)
 			return
 		}
diff --git a/_examples/struct-level/main.go b/_examples/struct-level/main.go
index 1885fc7..faba03f 100644
--- a/_examples/struct-level/main.go
+++ b/_examples/struct-level/main.go
@@ -115,7 +115,8 @@ func main() {
 		// this check is only needed when your code could produce
 		// an invalid value for validation such as interface with nil
 		// value most including myself do not usually have code like this.
-		if errors.As(err, &validator.InvalidValidationError{}) {
+		var invalidValidationError *validator.InvalidValidationError
+		if errors.As(err, &invalidValidationError) {
 			fmt.Println(err)
 			return
 		}
diff --git a/baked_in.go b/baked_in.go
index dab60f1..cca3e09 100644
--- a/baked_in.go
+++ b/baked_in.go
@@ -50,6 +50,7 @@ var (
 		keysTag:           {},
 		endKeysTag:        {},
 		structOnlyTag:     {},
+		omitzero:          {},
 		omitempty:         {},
 		omitnil:           {},
 		skipValidationTag: {},
@@ -1797,6 +1798,20 @@ func hasValue(fl FieldLevel) bool {
 	}
 }
 
+// hasNotZeroValue is the validation function for validating if the current field's value is not the zero value for its type.
+func hasNotZeroValue(fl FieldLevel) bool {
+	field := fl.Field()
+	switch field.Kind() {
+	case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
+		return !field.IsNil()
+	default:
+		if fl.(*validate).fldIsPointer && field.Interface() != nil {
+			return !field.IsZero()
+		}
+		return field.IsValid() && !field.IsZero()
+	}
+}
+
 // requireCheckFieldKind is a func for check field kind
 func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
 	field := fl.Field()
diff --git a/cache.go b/cache.go
index 2063e1b..cbf5ff0 100644
--- a/cache.go
+++ b/cache.go
@@ -21,6 +21,7 @@ const (
 	typeKeys
 	typeEndKeys
 	typeOmitNil
+	typeOmitZero
 )
 
 const (
@@ -249,6 +250,10 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
 			}
 			return
 
+		case omitzero:
+			current.typeof = typeOmitZero
+			continue
+
 		case omitempty:
 			current.typeof = typeOmitEmpty
 			continue
diff --git a/go.mod b/go.mod
index 9f3e458..4ffea09 100644
--- a/go.mod
+++ b/go.mod
@@ -8,11 +8,11 @@ require (
 	github.com/go-playground/locales v0.14.1
 	github.com/go-playground/universal-translator v0.18.1
 	github.com/leodido/go-urn v1.4.0
-	golang.org/x/crypto v0.32.0
-	golang.org/x/text v0.21.0
+	golang.org/x/crypto v0.33.0
+	golang.org/x/text v0.22.0
 )
 
 require (
 	golang.org/x/net v0.34.0 // indirect
-	golang.org/x/sys v0.29.0 // indirect
+	golang.org/x/sys v0.30.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 5100996..d0d2a98 100644
--- a/go.sum
+++ b/go.sum
@@ -11,12 +11,12 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
-golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
 golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
 golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
-golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/translations/id/id.go b/translations/id/id.go
index 96cd8fc..eda1c66 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/validator.go b/validator.go
index 901e7b5..d7c2e65 100644
--- a/validator.go
+++ b/validator.go
@@ -117,6 +117,10 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
 			return
 		}
 
+		if ct.typeof == typeOmitZero {
+			return
+		}
+
 		if ct.hasTag {
 			if kind == reflect.Invalid {
 				v.str1 = string(append(ns, cf.altName...))
@@ -238,6 +242,19 @@ OUTER:
 			ct = ct.next
 			continue
 
+		case typeOmitZero:
+			v.slflParent = parent
+			v.flField = current
+			v.cf = cf
+			v.ct = ct
+
+			if !hasNotZeroValue(v) {
+				return
+			}
+
+			ct = ct.next
+			continue
+
 		case typeOmitNil:
 			v.slflParent = parent
 			v.flField = current
diff --git a/validator_instance.go b/validator_instance.go
index d9f148d..779f689 100644
--- a/validator_instance.go
+++ b/validator_instance.go
@@ -21,6 +21,7 @@ const (
 	tagKeySeparator       = "="
 	structOnlyTag         = "structonly"
 	noStructLevelTag      = "nostructlevel"
+	omitzero              = "omitzero"
 	omitempty             = "omitempty"
 	omitnil               = "omitnil"
 	isdefault             = "isdefault"


Test patch:
diff --git a/translations/id/id_test.go b/translations/id/id_test.go
index 4a5b70f..e14db2c 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))
+	}
 }
diff --git a/validator_test.go b/validator_test.go
index 5eadb25..af05d19 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -14022,6 +14022,57 @@ func TestOmitNilAndRequired(t *testing.T) {
 	})
 }
 
+func TestOmitZero(t *testing.T) {
+	type (
+		OmitEmpty struct {
+			Str    string  `validate:"omitempty,min=10"`
+			StrPtr *string `validate:"omitempty,min=10"`
+		}
+		OmitZero struct {
+			Str    string  `validate:"omitzero,min=10"`
+			StrPtr *string `validate:"omitzero,min=10"`
+		}
+	)
+
+	var (
+		validate = New()
+		valid    = "this is the long string to pass the validation rule"
+		empty    = ""
+	)
+
+	t.Run("compare using valid data", func(t *testing.T) {
+		err1 := validate.Struct(OmitEmpty{Str: valid, StrPtr: &valid})
+		err2 := validate.Struct(OmitZero{Str: valid, StrPtr: &valid})
+
+		Equal(t, err1, nil)
+		Equal(t, err2, nil)
+	})
+
+	t.Run("compare fully empty omitempty and omitzero", func(t *testing.T) {
+		err1 := validate.Struct(OmitEmpty{})
+		err2 := validate.Struct(OmitZero{})
+
+		Equal(t, err1, nil)
+		Equal(t, err2, nil)
+	})
+
+	t.Run("compare with zero value", func(t *testing.T) {
+		err1 := validate.Struct(OmitEmpty{Str: "", StrPtr: nil})
+		err2 := validate.Struct(OmitZero{Str: "", StrPtr: nil})
+
+		Equal(t, err1, nil)
+		Equal(t, err2, nil)
+	})
+
+	t.Run("compare with empty value", func(t *testing.T) {
+		err1 := validate.Struct(OmitEmpty{Str: empty, StrPtr: &empty})
+		err2 := validate.Struct(OmitZero{Str: empty, StrPtr: &empty})
+
+		AssertError(t, err1, "OmitEmpty.StrPtr", "OmitEmpty.StrPtr", "StrPtr", "StrPtr", "min")
+		Equal(t, err2, nil)
+	})
+}
+
 func TestPrivateFieldsStruct(t *testing.T) {
 	type tc struct {
 		stct     interface{}