Repository: go-playground/validator
Pull request #934 (2022-04-20 11:10:33)

Feat: support validate struct without struct tag
## Fixes Or Enhances

validate struct without struct tag, use `map[string]string` to define rules, ref: #853 


**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

coveralls: 
[![Coverage Status](https://coveralls.io/builds/48412593/badge)](https://coveralls.io/builds/48412593)

Coverage decreased (-0.3%) to 74.837% when pulling **1d017686d4fb8b0a4bbf9c3d6a04fcfa21b7b0c8 on leoliang1997:dev/add-struct-without-tag-support** into **58d5778b183e89cc374ca4ebbf06da1eed088a63 on go-playground:master**.


Patch:
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index d1ca1e8..d6bfd55 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -8,7 +8,7 @@ jobs:
   test:
     strategy:
       matrix:
-        go-version: [1.15.x, 1.16.x]
+        go-version: [1.17.x, 1.18.x]
         os: [ubuntu-latest, macos-latest, windows-latest]
     runs-on: ${{ matrix.os }}
     steps:
@@ -32,7 +32,7 @@ jobs:
         run: go test -race -covermode=atomic -coverprofile="profile.cov" ./...
 
       - name: Send Coverage
-        if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.16.x'
+        if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.18.x'
         uses: shogo82148/actions-goveralls@v1
         with:
           path-to-profile: profile.cov
@@ -41,8 +41,11 @@ jobs:
     name: lint
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/setup-go@v3
+        with:
+          go-version: 1.16
+      - uses: actions/checkout@v3
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v2
+        uses: golangci/golangci-lint-action@v3
         with:
-          version: v1.41.1
+          version: v1.45.2
diff --git a/README.md b/README.md
index 6712e95..2294cce 100644
--- a/README.md
+++ b/README.md
@@ -130,7 +130,7 @@ Baked-in Validations
 | contains | Contains |
 | containsany | Contains Any |
 | containsrune | Contains Rune |
-| endsnotwith | Ends With |
+| endsnotwith | Ends Not With |
 | endswith | Ends With |
 | excludes | Excludes |
 | excludesall | Excludes All |
@@ -153,6 +153,7 @@ Baked-in Validations
 | bcp47_language_tag | Language tag (BCP 47) |
 | btc_addr | Bitcoin Address |
 | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
+| credit_card | Credit Card Number |
 | datetime | Datetime |
 | e164 | e164 formatted phone number |
 | email | E-mail String
@@ -189,6 +190,16 @@ Baked-in Validations
 | uuid5 | Universally Unique Identifier UUID v5 |
 | uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
 | uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
+| md4 | MD4 hash |
+| md5 | MD5 hash |
+| sha256 | SHA256 hash |
+| sha384 | SHA384 hash |
+| sha512 | SHA512 hash |
+| ripemd128 | RIPEMD-128 hash |
+| ripemd128 | RIPEMD-160 hash |
+| tiger128 | TIGER128 hash |
+| tiger160 | TIGER160 hash |
+| tiger192 | TIGER192 hash |
 | semver | Semantic Versioning 2.0.0 |
 | ulid | Universally Unique Lexicographically Sortable Identifier ULID |
 
@@ -219,6 +230,8 @@ Baked-in Validations
 | required_with_all | Required With All |
 | required_without | Required Without |
 | required_without_all | Required Without All |
+| excluded_if | Excluded If |
+| excluded_unless | Excluded Unless |
 | excluded_with | Excluded With |
 | excluded_with_all | Excluded With All |
 | excluded_without | Excluded Without |
diff --git a/_examples/map-validation/main.go b/_examples/map-validation/main.go
index 92e282f..dfcfa4f 100644
--- a/_examples/map-validation/main.go
+++ b/_examples/map-validation/main.go
@@ -48,6 +48,16 @@ func validateNestedMap() {
 				"mother_name": "Hannah",
 			},
 			"salary": "1000",
+			"phones": []map[string]interface{}{
+				{
+					"number": "11-111-1111",
+					"remark": "home",
+				},
+				{
+					"number": "22-222-2222",
+					"remark": "work",
+				},
+			},
 		},
 	}
 
@@ -62,6 +72,10 @@ func validateNestedMap() {
 				"mother_name": "required,min=4,max=32",
 			},
 			"salary": "number",
+			"phones": map[string]interface{}{
+				"number": "required,min=4,max=32",
+				"remark": "required,min=1,max=32",
+			},
 		},
 	}
 
diff --git a/_examples/struct-map-rules-validation/main.go b/_examples/struct-map-rules-validation/main.go
new file mode 100644
index 0000000..e936117
--- /dev/null
+++ b/_examples/struct-map-rules-validation/main.go
@@ -0,0 +1,92 @@
+package main
+
+import (
+	"fmt"
+	"github.com/go-playground/validator/v10"
+)
+
+type Data struct {
+	Name    string
+	Email   string
+	Details *Details
+}
+
+type Details struct {
+	FamilyMembers *FamilyMembers
+	Salary        string
+}
+
+type FamilyMembers struct {
+	FatherName string
+	MotherName string
+}
+
+type Data2 struct {
+	Name string
+	Age  uint32
+}
+
+var validate = validator.New()
+
+func main() {
+	validateStruct()
+	// output
+	// Key: 'Data2.Name' Error:Field validation for 'Name' failed on the 'min' tag
+	// Key: 'Data2.Age' Error:Field validation for 'Age' failed on the 'max' tag
+
+	validateStructNested()
+	// output
+	// Key: 'Data.Name' Error:Field validation for 'Name' failed on the 'max' tag
+	// Key: 'Data.Details.FamilyMembers' Error:Field validation for 'FamilyMembers' failed on the 'required' tag
+}
+
+func validateStruct() {
+	data := Data2{
+		Name: "leo",
+		Age:  1000,
+	}
+
+	rules := map[string]string{
+		"Name": "min=4,max=6",
+		"Age":  "min=4,max=6",
+	}
+
+	validate.RegisterStructValidationMapRules(rules, Data2{})
+
+	err := validate.Struct(data)
+	fmt.Println(err)
+	fmt.Println()
+}
+
+func validateStructNested() {
+	data := Data{
+		Name:  "11sdfddd111",
+		Email: "zytel3301@mail.com",
+		Details: &Details{
+			Salary: "1000",
+		},
+	}
+
+	rules1 := map[string]string{
+		"Name":    "min=4,max=6",
+		"Email":   "required,email",
+		"Details": "required",
+	}
+
+	rules2 := map[string]string{
+		"Salary":        "number",
+		"FamilyMembers": "required",
+	}
+
+	rules3 := map[string]string{
+		"FatherName": "required,min=4,max=32",
+		"MotherName": "required,min=4,max=32",
+	}
+
+	validate.RegisterStructValidationMapRules(rules1, Data{})
+	validate.RegisterStructValidationMapRules(rules2, Details{})
+	validate.RegisterStructValidationMapRules(rules3, FamilyMembers{})
+	err := validate.Struct(data)
+
+	fmt.Println(err)
+}
diff --git a/baked_in.go b/baked_in.go
index 7868b66..f2f0939 100644
--- a/baked_in.go
+++ b/baked_in.go
@@ -75,6 +75,8 @@ var (
 		"required_with_all":             requiredWithAll,
 		"required_without":              requiredWithout,
 		"required_without_all":          requiredWithoutAll,
+		"excluded_if":                   excludedIf,
+		"excluded_unless":               excludedUnless,
 		"excluded_with":                 excludedWith,
 		"excluded_with_all":             excludedWithAll,
 		"excluded_without":              excludedWithout,
@@ -149,6 +151,16 @@ var (
 		"uuid4_rfc4122":                 isUUID4RFC4122,
 		"uuid5_rfc4122":                 isUUID5RFC4122,
 		"ulid":                          isULID,
+		"md4":                           isMD4,
+		"md5":                           isMD5,
+		"sha256":                        isSHA256,
+		"sha384":                        isSHA384,
+		"sha512":                        isSHA512,
+		"ripemd128":                     isRIPEMD128,
+		"ripemd160":                     isRIPEMD160,
+		"tiger128":                      isTIGER128,
+		"tiger160":                      isTIGER160,
+		"tiger192":                      isTIGER192,
 		"ascii":                         isASCII,
 		"printascii":                    isPrintableASCII,
 		"multibyte":                     hasMultiByteCharacter,
@@ -201,11 +213,14 @@ var (
 		"bic":                           isIsoBicFormat,
 		"semver":                        isSemverFormat,
 		"dns_rfc1035_label":             isDnsRFC1035LabelFormat,
+		"credit_card":                   isCreditCard,
 	}
 )
 
-var oneofValsCache = map[string][]string{}
-var oneofValsCacheRWLock = sync.RWMutex{}
+var (
+	oneofValsCache       = map[string][]string{}
+	oneofValsCacheRWLock = sync.RWMutex{}
+)
 
 func parseOneOfParam2(s string) []string {
 	oneofValsCacheRWLock.RLock()
@@ -261,7 +276,6 @@ func isOneOf(fl FieldLevel) bool {
 
 // isUnique is the validation function for validating if each array|slice|map value is unique
 func isUnique(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 	v := reflect.ValueOf(struct{}{})
@@ -311,7 +325,6 @@ func isUnique(fl FieldLevel) bool {
 
 // isMAC is the validation function for validating if the field's value is a valid MAC address.
 func isMAC(fl FieldLevel) bool {
-
 	_, err := net.ParseMAC(fl.Field().String())
 
 	return err == nil
@@ -319,7 +332,6 @@ func isMAC(fl FieldLevel) bool {
 
 // isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
 func isCIDRv4(fl FieldLevel) bool {
-
 	ip, _, err := net.ParseCIDR(fl.Field().String())
 
 	return err == nil && ip.To4() != nil
@@ -327,7 +339,6 @@ func isCIDRv4(fl FieldLevel) bool {
 
 // isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
 func isCIDRv6(fl FieldLevel) bool {
-
 	ip, _, err := net.ParseCIDR(fl.Field().String())
 
 	return err == nil && ip.To4() == nil
@@ -335,7 +346,6 @@ func isCIDRv6(fl FieldLevel) bool {
 
 // isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
 func isCIDR(fl FieldLevel) bool {
-
 	_, _, err := net.ParseCIDR(fl.Field().String())
 
 	return err == nil
@@ -343,7 +353,6 @@ func isCIDR(fl FieldLevel) bool {
 
 // isIPv4 is the validation function for validating if a value is a valid v4 IP address.
 func isIPv4(fl FieldLevel) bool {
-
 	ip := net.ParseIP(fl.Field().String())
 
 	return ip != nil && ip.To4() != nil
@@ -351,7 +360,6 @@ func isIPv4(fl FieldLevel) bool {
 
 // isIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
 func isIPv6(fl FieldLevel) bool {
-
 	ip := net.ParseIP(fl.Field().String())
 
 	return ip != nil && ip.To4() == nil
@@ -359,7 +367,6 @@ func isIPv6(fl FieldLevel) bool {
 
 // isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
 func isIP(fl FieldLevel) bool {
-
 	ip := net.ParseIP(fl.Field().String())
 
 	return ip != nil
@@ -367,7 +374,6 @@ func isIP(fl FieldLevel) bool {
 
 // isSSN is the validation function for validating if the field's value is a valid SSN.
 func isSSN(fl FieldLevel) bool {
-
 	field := fl.Field()
 
 	if field.Len() != 11 {
@@ -425,7 +431,6 @@ func isLatitude(fl FieldLevel) bool {
 
 // isDataURI is the validation function for validating if the field's value is a valid data URI.
 func isDataURI(fl FieldLevel) bool {
-
 	uri := strings.SplitN(fl.Field().String(), ",", 2)
 
 	if len(uri) != 2 {
@@ -441,7 +446,6 @@ func isDataURI(fl FieldLevel) bool {
 
 // hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
 func hasMultiByteCharacter(fl FieldLevel) bool {
-
 	field := fl.Field()
 
 	if field.Len() == 0 {
@@ -506,6 +510,56 @@ func isULID(fl FieldLevel) bool {
 	return uLIDRegex.MatchString(fl.Field().String())
 }
 
+// isMD4 is the validation function for validating if the field's value is a valid MD4.
+func isMD4(fl FieldLevel) bool {
+	return md4Regex.MatchString(fl.Field().String())
+}
+
+// isMD5 is the validation function for validating if the field's value is a valid MD5.
+func isMD5(fl FieldLevel) bool {
+	return md5Regex.MatchString(fl.Field().String())
+}
+
+// isSHA256 is the validation function for validating if the field's value is a valid SHA256.
+func isSHA256(fl FieldLevel) bool {
+	return sha256Regex.MatchString(fl.Field().String())
+}
+
+// isSHA384 is the validation function for validating if the field's value is a valid SHA384.
+func isSHA384(fl FieldLevel) bool {
+	return sha384Regex.MatchString(fl.Field().String())
+}
+
+// isSHA512 is the validation function for validating if the field's value is a valid SHA512.
+func isSHA512(fl FieldLevel) bool {
+	return sha512Regex.MatchString(fl.Field().String())
+}
+
+// isRIPEMD128 is the validation function for validating if the field's value is a valid PIPEMD128.
+func isRIPEMD128(fl FieldLevel) bool {
+	return ripemd128Regex.MatchString(fl.Field().String())
+}
+
+// isRIPEMD160 is the validation function for validating if the field's value is a valid PIPEMD160.
+func isRIPEMD160(fl FieldLevel) bool {
+	return ripemd160Regex.MatchString(fl.Field().String())
+}
+
+// isTIGER128 is the validation function for validating if the field's value is a valid TIGER128.
+func isTIGER128(fl FieldLevel) bool {
+	return tiger128Regex.MatchString(fl.Field().String())
+}
+
+// isTIGER160 is the validation function for validating if the field's value is a valid TIGER160.
+func isTIGER160(fl FieldLevel) bool {
+	return tiger160Regex.MatchString(fl.Field().String())
+}
+
+// isTIGER192 is the validation function for validating if the field's value is a valid isTIGER192.
+func isTIGER192(fl FieldLevel) bool {
+	return tiger192Regex.MatchString(fl.Field().String())
+}
+
 // isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
 func isISBN(fl FieldLevel) bool {
 	return isISBN10(fl) || isISBN13(fl)
@@ -513,7 +567,6 @@ func isISBN(fl FieldLevel) bool {
 
 // isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
 func isISBN13(fl FieldLevel) bool {
-
 	s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
 
 	if !iSBN13Regex.MatchString(s) {
@@ -534,7 +587,6 @@ func isISBN13(fl FieldLevel) bool {
 
 // isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
 func isISBN10(fl FieldLevel) bool {
-
 	s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
 
 	if !iSBN10Regex.MatchString(s) {
@@ -722,7 +774,6 @@ func excludes(fl FieldLevel) bool {
 
 // containsRune is the validation function for validating that the field's value contains the rune specified within the param.
 func containsRune(fl FieldLevel) bool {
-
 	r, _ := utf8.DecodeRuneInString(fl.Param())
 
 	return strings.ContainsRune(fl.Field().String(), r)
@@ -785,7 +836,6 @@ func fieldExcludes(fl FieldLevel) bool {
 
 // isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
 func isNeField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -816,12 +866,7 @@ func isNeField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != currentField.Type() {
-			return true
-		}
-
-		if fieldType == timeType {
+		if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
 
 			t := currentField.Interface().(time.Time)
 			fieldTime := field.Interface().(time.Time)
@@ -829,6 +874,10 @@ func isNeField(fl FieldLevel) bool {
 			return !fieldTime.Equal(t)
 		}
 
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return true
+		}
 	}
 
 	// default reflect.String:
@@ -842,7 +891,6 @@ func isNe(fl FieldLevel) bool {
 
 // isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
 func isLteCrossStructField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -869,18 +917,18 @@ func isLteCrossStructField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != topField.Type() {
-			return false
-		}
-
-		if fieldType == timeType {
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
 
-			fieldTime := field.Interface().(time.Time)
-			topTime := topField.Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
+			topTime := topField.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -890,7 +938,6 @@ func isLteCrossStructField(fl FieldLevel) bool {
 // isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
 // NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
 func isLtCrossStructField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -917,18 +964,18 @@ func isLtCrossStructField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != topField.Type() {
-			return false
-		}
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			fieldTime := field.Interface().(time.Time)
-			topTime := topField.Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
+			topTime := topField.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.Before(topTime)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -937,7 +984,6 @@ func isLtCrossStructField(fl FieldLevel) bool {
 
 // isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
 func isGteCrossStructField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -964,18 +1010,18 @@ func isGteCrossStructField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != topField.Type() {
-			return false
-		}
-
-		if fieldType == timeType {
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
 
-			fieldTime := field.Interface().(time.Time)
-			topTime := topField.Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
+			topTime := topField.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.After(topTime) || fieldTime.Equal(topTime)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -984,7 +1030,6 @@ func isGteCrossStructField(fl FieldLevel) bool {
 
 // isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
 func isGtCrossStructField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1011,18 +1056,18 @@ func isGtCrossStructField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != topField.Type() {
-			return false
-		}
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			fieldTime := field.Interface().(time.Time)
-			topTime := topField.Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
+			topTime := topField.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.After(topTime)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -1031,7 +1076,6 @@ func isGtCrossStructField(fl FieldLevel) bool {
 
 // isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
 func isNeCrossStructField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1061,18 +1105,18 @@ func isNeCrossStructField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != topField.Type() {
-			return true
-		}
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			t := field.Interface().(time.Time)
-			fieldTime := topField.Interface().(time.Time)
+			t := field.Convert(timeType).Interface().(time.Time)
+			fieldTime := topField.Convert(timeType).Interface().(time.Time)
 
 			return !fieldTime.Equal(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return true
+		}
 	}
 
 	// default reflect.String:
@@ -1081,7 +1125,6 @@ func isNeCrossStructField(fl FieldLevel) bool {
 
 // isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
 func isEqCrossStructField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1111,18 +1154,18 @@ func isEqCrossStructField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != topField.Type() {
-			return false
-		}
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			t := field.Interface().(time.Time)
-			fieldTime := topField.Interface().(time.Time)
+			t := field.Convert(timeType).Interface().(time.Time)
+			fieldTime := topField.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.Equal(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -1131,7 +1174,6 @@ func isEqCrossStructField(fl FieldLevel) bool {
 
 // isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
 func isEqField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1161,19 +1203,18 @@ func isEqField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != currentField.Type() {
-			return false
-		}
-
-		if fieldType == timeType {
+		if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
 
-			t := currentField.Interface().(time.Time)
-			fieldTime := field.Interface().(time.Time)
+			t := currentField.Convert(timeType).Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.Equal(t)
 		}
 
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -1182,7 +1223,6 @@ func isEqField(fl FieldLevel) bool {
 
 // isEq is the validation function for validating if the current field's value is equal to the param's value.
 func isEq(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 
@@ -1234,7 +1274,7 @@ func isPostcodeByIso3166Alpha2(fl FieldLevel) bool {
 	return reg.MatchString(field.String())
 }
 
-// isPostcodeByIso3166Alpha2 validates by field which represents for a value of country code in iso 3166 alpha 2
+// isPostcodeByIso3166Alpha2Field validates by field which represents for a value of country code in iso 3166 alpha 2
 // example: `postcode_iso3166_alpha2_field=CountryCode`
 func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
 	field := fl.Field()
@@ -1273,11 +1313,9 @@ func isBase64URL(fl FieldLevel) bool {
 
 // isURI is the validation function for validating if the current field's value is a valid URI.
 func isURI(fl FieldLevel) bool {
-
 	field := fl.Field()
 
 	switch field.Kind() {
-
 	case reflect.String:
 
 		s := field.String()
@@ -1302,11 +1340,9 @@ func isURI(fl FieldLevel) bool {
 
 // isURL is the validation function for validating if the current field's value is a valid URL.
 func isURL(fl FieldLevel) bool {
-
 	field := fl.Field()
 
 	switch field.Kind() {
-
 	case reflect.String:
 
 		var i int
@@ -1339,7 +1375,6 @@ func isUrnRFC2141(fl FieldLevel) bool {
 	field := fl.Field()
 
 	switch field.Kind() {
-
 	case reflect.String:
 
 		str := field.String()
@@ -1542,6 +1577,22 @@ func requiredIf(fl FieldLevel) bool {
 	return hasValue(fl)
 }
 
+// excludedIf is the validation function
+// The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field.
+func excludedIf(fl FieldLevel) bool {
+	params := parseOneOfParam2(fl.Param())
+	if len(params)%2 != 0 {
+		panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName()))
+	}
+
+	for i := 0; i < len(params); i += 2 {
+		if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
+			return false
+		}
+	}
+	return true
+}
+
 // requiredUnless is the validation function
 // The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
 func requiredUnless(fl FieldLevel) bool {
@@ -1558,6 +1609,21 @@ func requiredUnless(fl FieldLevel) bool {
 	return hasValue(fl)
 }
 
+// excludedUnless is the validation function
+// The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field.
+func excludedUnless(fl FieldLevel) bool {
+	params := parseOneOfParam2(fl.Param())
+	if len(params)%2 != 0 {
+		panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName()))
+	}
+	for i := 0; i < len(params); i += 2 {
+		if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
+			return true
+		}
+	}
+	return !hasValue(fl)
+}
+
 // excludedWith is the validation function
 // The field under validation must not be present or is empty if any of the other specified fields are present.
 func excludedWith(fl FieldLevel) bool {
@@ -1650,7 +1716,6 @@ func requiredWithoutAll(fl FieldLevel) bool {
 
 // isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
 func isGteField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1677,18 +1742,18 @@ func isGteField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != currentField.Type() {
-			return false
-		}
+		if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			t := currentField.Interface().(time.Time)
-			fieldTime := field.Interface().(time.Time)
+			t := currentField.Convert(timeType).Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.After(t) || fieldTime.Equal(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String
@@ -1697,7 +1762,6 @@ func isGteField(fl FieldLevel) bool {
 
 // isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
 func isGtField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1724,18 +1788,18 @@ func isGtField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != currentField.Type() {
-			return false
-		}
+		if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			t := currentField.Interface().(time.Time)
-			fieldTime := field.Interface().(time.Time)
+			t := currentField.Convert(timeType).Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.After(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String
@@ -1744,7 +1808,6 @@ func isGtField(fl FieldLevel) bool {
 
 // isGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
 func isGte(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 
@@ -1777,10 +1840,10 @@ func isGte(fl FieldLevel) bool {
 
 	case reflect.Struct:
 
-		if field.Type() == timeType {
+		if field.Type().ConvertibleTo(timeType) {
 
 			now := time.Now().UTC()
-			t := field.Interface().(time.Time)
+			t := field.Convert(timeType).Interface().(time.Time)
 
 			return t.After(now) || t.Equal(now)
 		}
@@ -1791,7 +1854,6 @@ func isGte(fl FieldLevel) bool {
 
 // isGt is the validation function for validating if the current field's value is greater than the param's value.
 func isGt(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 
@@ -1823,9 +1885,9 @@ func isGt(fl FieldLevel) bool {
 		return field.Float() > p
 	case reflect.Struct:
 
-		if field.Type() == timeType {
+		if field.Type().ConvertibleTo(timeType) {
 
-			return field.Interface().(time.Time).After(time.Now().UTC())
+			return field.Convert(timeType).Interface().(time.Time).After(time.Now().UTC())
 		}
 	}
 
@@ -1834,7 +1896,6 @@ func isGt(fl FieldLevel) bool {
 
 // hasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
 func hasLengthOf(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 
@@ -1876,7 +1937,6 @@ func hasMinOf(fl FieldLevel) bool {
 
 // isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
 func isLteField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1903,18 +1963,18 @@ func isLteField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != currentField.Type() {
-			return false
-		}
-
-		if fieldType == timeType {
+		if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
 
-			t := currentField.Interface().(time.Time)
-			fieldTime := field.Interface().(time.Time)
+			t := currentField.Convert(timeType).Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.Before(t) || fieldTime.Equal(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String
@@ -1923,7 +1983,6 @@ func isLteField(fl FieldLevel) bool {
 
 // isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
 func isLtField(fl FieldLevel) bool {
-
 	field := fl.Field()
 	kind := field.Kind()
 
@@ -1950,18 +2009,18 @@ func isLtField(fl FieldLevel) bool {
 
 		fieldType := field.Type()
 
-		// Not Same underlying type i.e. struct and time
-		if fieldType != currentField.Type() {
-			return false
-		}
+		if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
 
-		if fieldType == timeType {
-
-			t := currentField.Interface().(time.Time)
-			fieldTime := field.Interface().(time.Time)
+			t := currentField.Convert(timeType).Interface().(time.Time)
+			fieldTime := field.Convert(timeType).Interface().(time.Time)
 
 			return fieldTime.Before(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String
@@ -1970,7 +2029,6 @@ func isLtField(fl FieldLevel) bool {
 
 // isLte is the validation function for validating if the current field's value is less than or equal to the param's value.
 func isLte(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 
@@ -2003,10 +2061,10 @@ func isLte(fl FieldLevel) bool {
 
 	case reflect.Struct:
 
-		if field.Type() == timeType {
+		if field.Type().ConvertibleTo(timeType) {
 
 			now := time.Now().UTC()
-			t := field.Interface().(time.Time)
+			t := field.Convert(timeType).Interface().(time.Time)
 
 			return t.Before(now) || t.Equal(now)
 		}
@@ -2017,7 +2075,6 @@ func isLte(fl FieldLevel) bool {
 
 // isLt is the validation function for validating if the current field's value is less than the param's value.
 func isLt(fl FieldLevel) bool {
-
 	field := fl.Field()
 	param := fl.Param()
 
@@ -2050,9 +2107,9 @@ func isLt(fl FieldLevel) bool {
 
 	case reflect.Struct:
 
-		if field.Type() == timeType {
+		if field.Type().ConvertibleTo(timeType) {
 
-			return field.Interface().(time.Time).Before(time.Now().UTC())
+			return field.Convert(timeType).Interface().(time.Time).Before(time.Now().UTC())
 		}
 	}
 
@@ -2066,7 +2123,6 @@ func hasMaxOf(fl FieldLevel) bool {
 
 // isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
 func isTCP4AddrResolvable(fl FieldLevel) bool {
-
 	if !isIP4Addr(fl) {
 		return false
 	}
@@ -2077,7 +2133,6 @@ func isTCP4AddrResolvable(fl FieldLevel) bool {
 
 // isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
 func isTCP6AddrResolvable(fl FieldLevel) bool {
-
 	if !isIP6Addr(fl) {
 		return false
 	}
@@ -2089,7 +2144,6 @@ func isTCP6AddrResolvable(fl FieldLevel) bool {
 
 // isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
 func isTCPAddrResolvable(fl FieldLevel) bool {
-
 	if !isIP4Addr(fl) && !isIP6Addr(fl) {
 		return false
 	}
@@ -2101,7 +2155,6 @@ func isTCPAddrResolvable(fl FieldLevel) bool {
 
 // isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
 func isUDP4AddrResolvable(fl FieldLevel) bool {
-
 	if !isIP4Addr(fl) {
 		return false
 	}
@@ -2113,7 +2166,6 @@ func isUDP4AddrResolvable(fl FieldLevel) bool {
 
 // isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
 func isUDP6AddrResolvable(fl FieldLevel) bool {
-
 	if !isIP6Addr(fl) {
 		return false
 	}
@@ -2125,7 +2177,6 @@ func isUDP6AddrResolvable(fl FieldLevel) bool {
 
 // isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
 func isUDPAddrResolvable(fl FieldLevel) bool {
-
 	if !isIP4Addr(fl) && !isIP6Addr(fl) {
 		return false
 	}
@@ -2137,7 +2188,6 @@ func isUDPAddrResolvable(fl FieldLevel) bool {
 
 // isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
 func isIP4AddrResolvable(fl FieldLevel) bool {
-
 	if !isIPv4(fl) {
 		return false
 	}
@@ -2149,7 +2199,6 @@ func isIP4AddrResolvable(fl FieldLevel) bool {
 
 // isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
 func isIP6AddrResolvable(fl FieldLevel) bool {
-
 	if !isIPv6(fl) {
 		return false
 	}
@@ -2161,7 +2210,6 @@ func isIP6AddrResolvable(fl FieldLevel) bool {
 
 // isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
 func isIPAddrResolvable(fl FieldLevel) bool {
-
 	if !isIP(fl) {
 		return false
 	}
@@ -2173,14 +2221,12 @@ func isIPAddrResolvable(fl FieldLevel) bool {
 
 // isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
 func isUnixAddrResolvable(fl FieldLevel) bool {
-
 	_, err := net.ResolveUnixAddr("unix", fl.Field().String())
 
 	return err == nil
 }
 
 func isIP4Addr(fl FieldLevel) bool {
-
 	val := fl.Field().String()
 
 	if idx := strings.LastIndex(val, ":"); idx != -1 {
@@ -2193,7 +2239,6 @@ func isIP4Addr(fl FieldLevel) bool {
 }
 
 func isIP6Addr(fl FieldLevel) bool {
-
 	val := fl.Field().String()
 
 	if idx := strings.LastIndex(val, ":"); idx != -1 {
@@ -2436,3 +2481,41 @@ func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
 	val := fl.Field().String()
 	return dnsRegexRFC1035Label.MatchString(val)
 }
+
+// isCreditCard is the validation function for validating if the current field's value is a valid credit card number
+func isCreditCard(fl FieldLevel) bool {
+	val := fl.Field().String()
+	var creditCard bytes.Buffer
+	segments := strings.Split(val, " ")
+	for _, segment := range segments {
+		if len(segment) < 3 {
+			return false
+		}
+		creditCard.WriteString(segment)
+	}
+
+	ccDigits := strings.Split(creditCard.String(), "")
+	size := len(ccDigits)
+	if size < 12 || size > 19 {
+		return false
+	}
+
+	sum := 0
+	for i, digit := range ccDigits {
+		value, err := strconv.Atoi(digit)
+		if err != nil {
+			return false
+		}
+		if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 {
+			v := value * 2
+			if v >= 10 {
+				sum += 1 + (v % 10)
+			} else {
+				sum += v
+			}
+		} else {
+			sum += value
+		}
+	}
+	return (sum % 10) == 0
+}
diff --git a/cache.go b/cache.go
index 0d18d6e..7b84c91 100644
--- a/cache.go
+++ b/cache.go
@@ -114,12 +114,13 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
 	cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]}
 
 	numFields := current.NumField()
+	rules := v.rules[typ]
 
 	var ctag *cTag
 	var fld reflect.StructField
 	var tag string
 	var customName string
-
+	
 	for i := 0; i < numFields; i++ {
 
 		fld = typ.Field(i)
@@ -128,7 +129,11 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
 			continue
 		}
 
-		tag = fld.Tag.Get(v.tagName)
+		if rtag, ok := rules[fld.Name]; ok {
+			tag = rtag
+		} else {
+			tag = fld.Tag.Get(v.tagName)
+		}
 
 		if tag == skipValidationTag {
 			continue
diff --git a/doc.go b/doc.go
index b284c37..7341c67 100644
--- a/doc.go
+++ b/doc.go
@@ -349,6 +349,40 @@ Example:
 	// require the field if the Field1 and Field2 is not present:
 	Usage: required_without_all=Field1 Field2
 
+Excluded If
+
+The field under validation must not be present or not empty only if all
+the other specified fields are equal to the value following the specified
+field. For strings ensures value is not "". For slices, maps, pointers,
+interfaces, channels and functions ensures the value is not nil.
+
+	Usage: excluded_if
+
+Examples:
+
+	// exclude the field if the Field1 is equal to the parameter given:
+	Usage: excluded_if=Field1 foobar
+
+	// exclude the field if the Field1 and Field2 is equal to the value respectively:
+	Usage: excluded_if=Field1 foo Field2 bar
+
+Excluded Unless
+
+The field under validation must not be present or empty unless all
+the other specified fields are equal to the value following the specified
+field. For strings ensures value is not "". For slices, maps, pointers,
+interfaces, channels and functions ensures the value is not nil.
+
+	Usage: excluded_unless
+
+Examples:
+
+	// exclude the field unless the Field1 is equal to the parameter given:
+	Usage: excluded_unless=Field1 foobar
+
+	// exclude the field unless the Field1 and Field2 is equal to the value respectively:
+	Usage: excluded_unless=Field1 foo Field2 bar
+
 Is Default
 
 This validates that the value is the default value and is almost the
@@ -1283,6 +1317,12 @@ More information on https://semver.org/
 
 	Usage: semver
 
+Credit Card
+
+This validates that a string value contains a valid credit card number using Luhn algoritm.
+
+	Usage: credit_card
+
 Alias Validators and Tags
 
 NOTE: When returning an error, the tag returned in "FieldError" will be
diff --git a/regexes.go b/regexes.go
index 48e51d5..9c1c634 100644
--- a/regexes.go
+++ b/regexes.go
@@ -30,6 +30,16 @@ const (
 	uUID5RFC4122RegexString          = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
 	uUIDRFC4122RegexString           = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
 	uLIDRegexString                  = "^[A-HJKMNP-TV-Z0-9]{26}$"
+	md4RegexString                   = "^[0-9a-f]{32}$"
+	md5RegexString                   = "^[0-9a-f]{32}$"
+	sha256RegexString                = "^[0-9a-f]{64}$"
+	sha384RegexString                = "^[0-9a-f]{96}$"
+	sha512RegexString                = "^[0-9a-f]{128}$"
+	ripemd128RegexString             = "^[0-9a-f]{32}$"
+	ripemd160RegexString             = "^[0-9a-f]{40}$"
+	tiger128RegexString              = "^[0-9a-f]{32}$"
+	tiger160RegexString              = "^[0-9a-f]{40}$"
+	tiger192RegexString              = "^[0-9a-f]{48}$"
 	aSCIIRegexString                 = "^[\x00-\x7F]*$"
 	printableASCIIRegexString        = "^[\x20-\x7E]*$"
 	multibyteRegexString             = "[^\x00-\x7F]"
@@ -37,12 +47,12 @@ const (
 	latitudeRegexString              = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
 	longitudeRegexString             = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
 	sSNRegexString                   = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$`
-	hostnameRegexStringRFC952        = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`                                                                      // https://tools.ietf.org/html/rfc952
-	hostnameRegexStringRFC1123       = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$`                                 // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
-	fqdnRegexStringRFC1123           = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
-	btcAddressRegexString            = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$`                                                                                // bitcoin address
-	btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$`                                                                                      // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
-	btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$`                                                                                      // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
+	hostnameRegexStringRFC952        = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`                                                                   // https://tools.ietf.org/html/rfc952
+	hostnameRegexStringRFC1123       = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62}){1}(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?$`                                 // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
+	fqdnRegexStringRFC1123           = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
+	btcAddressRegexString            = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$`                                                                             // bitcoin address
+	btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$`                                                                                   // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
+	btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$`                                                                                   // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
 	ethAddressRegexString            = `^0x[0-9a-fA-F]{40}$`
 	ethAddressUpperRegexString       = `^0x[0-9A-F]{40}$`
 	ethAddressLowerRegexString       = `^0x[0-9a-f]{40}$`
@@ -84,6 +94,16 @@ var (
 	uUID5RFC4122Regex          = regexp.MustCompile(uUID5RFC4122RegexString)
 	uUIDRFC4122Regex           = regexp.MustCompile(uUIDRFC4122RegexString)
 	uLIDRegex                  = regexp.MustCompile(uLIDRegexString)
+	md4Regex                   = regexp.MustCompile(md4RegexString)
+	md5Regex                   = regexp.MustCompile(md5RegexString)
+	sha256Regex                = regexp.MustCompile(sha256RegexString)
+	sha384Regex                = regexp.MustCompile(sha384RegexString)
+	sha512Regex                = regexp.MustCompile(sha512RegexString)
+	ripemd128Regex             = regexp.MustCompile(ripemd128RegexString)
+	ripemd160Regex             = regexp.MustCompile(ripemd160RegexString)
+	tiger128Regex              = regexp.MustCompile(tiger128RegexString)
+	tiger160Regex              = regexp.MustCompile(tiger160RegexString)
+	tiger192Regex              = regexp.MustCompile(tiger192RegexString)
 	aSCIIRegex                 = regexp.MustCompile(aSCIIRegexString)
 	printableASCIIRegex        = regexp.MustCompile(printableASCIIRegexString)
 	multibyteRegex             = regexp.MustCompile(multibyteRegexString)
diff --git a/translations/ar/ar.go b/translations/ar/ar.go
new file mode 100644
index 0000000..3886120
--- /dev/null
+++ b/translations/ar/ar.go
@@ -0,0 +1,1389 @@
+package ar
+
+import (
+	"fmt"
+	"log"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/go-playground/locales"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+)
+
+// 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
+		override        bool
+		customRegisFunc validator.RegisterTranslationsFunc
+		customTransFunc validator.TranslationFunc
+	}{
+		{
+			tag:         "required",
+			translation: "حقل {0} مطلوب",
+			override:    false,
+		},
+		{
+			tag: "len",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("len-string", "يجب أن يكون طول {0} مساويا ل {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("len-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("len-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("len-number", "يجب أن يكون {0} مساويا ل {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("len-items", "يجب أن يحتوي {0} على {1}", false); err != nil {
+					return
+				}
+				if err = ut.AddCardinal("len-items-item", "{0} عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("len-items-item", "{0} عناصر", 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: "min",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("min-string", "{0} يجب أن يكون {1} أو اقل", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("min-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("min-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("min-number", "{0} يجب أن يكون {1} أو اقل", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("min-items", "يجب أن يحتوي {0} على {1} على الأقل", false); err != nil {
+					return
+				}
+				if err = ut.AddCardinal("min-items-item", "{0} عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("min-items-item", "{0} عناصر", 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("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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "max",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("max-string", "يجب أن يكون طول {0} بحد أقصى {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("max-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("max-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("max-number", "{0} يجب أن يكون {1} أو اقل", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("max-items", "يجب أن يحتوي {0} على {1} كحد أقصى", false); err != nil {
+					return
+				}
+				if err = ut.AddCardinal("max-items-item", "{0} عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("max-items-item", "{0} عناصر", 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:         "eq",
+			translation: "{0} لا يساوي {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 {
+					fmt.Printf("warning: error translating FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ne",
+			translation: "{0} يجب ألا يساوي {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 {
+					fmt.Printf("warning: error translating FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "lt",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("lt-string", "يجب أن يكون طول {0} أقل من {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-number", "يجب أن يكون {0} أقل من {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-items", "يجب أن يحتوي {0} على أقل من {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-items-item", "{0} عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-items-item", "{0} عناصر", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-datetime", "يجب أن يكون {0} أقل من التاريخ والوقت الحاليين", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("lt-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-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: "lte",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("lte-string", "يجب أن يكون طول {0} كحد أقصى {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-number", "{0} يجب أن يكون {1} أو اقل", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-items", "يجب أن يحتوي {0} على {1} كحد أقصى", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-items-item", "{0} عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-items-item", "{0} عناصر", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-datetime", "يجب أن يكون {0} أقل من أو يساوي التاريخ والوقت الحاليين", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("lte-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-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: "gt",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("gt-string", "يجب أن يكون طول {0} أكبر من {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-number", "يجب أن يكون {0} أكبر من {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-items", "يجب أن يحتوي {0} على أكثر من {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-items-item", "{0}عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-items-item", "{0} عناصر", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-datetime", "يجب أن يكون {0} أكبر من التاريخ والوقت الحاليين", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("gt-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-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: "gte",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("gte-string", "يجب أن يكون طول {0} على الأقل {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-string-character", "{0} حرف", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-string-character", "{0} أحرف", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-number", "{0} يجب أن يكون {1} أو أكبر", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-items", "يجب أن يحتوي {0} على {1} على الأقل", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-items-item", "{0} عنصر", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-items-item", "{0} عناصر", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-datetime", "يجب أن يكون {0} أكبر من أو يساوي التاريخ والوقت الحاليين", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("gte-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-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} مساويا ل {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "eqcsfield",
+			translation: "يجب أن يكون {0} مساويا ل {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "necsfield",
+			translation: "{0} لا يمكن أن يساوي {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtcsfield",
+			translation: "يجب أن يكون {0} أكبر من {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtecsfield",
+			translation: "يجب أن يكون {0} أكبر من أو يساوي {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltcsfield",
+			translation: "يجب أن يكون {0} أصغر من {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltecsfield",
+			translation: "يجب أن يكون {0} أصغر من أو يساوي {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "nefield",
+			translation: "{0} لا يمكن أن يساوي {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtfield",
+			translation: "يجب أن يكون {0} أكبر من {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtefield",
+			translation: "يجب أن يكون {0} أكبر من أو يساوي {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltfield",
+			translation: "يجب أن يكون {0} أصغر من {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltefield",
+			translation: "يجب أن يكون {0} أصغر من أو يساوي {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "alpha",
+			translation: "يمكن أن يحتوي {0} على أحرف أبجدية فقط",
+			override:    false,
+		},
+		{
+			tag:         "alphanum",
+			translation: "يمكن أن يحتوي {0} على أحرف أبجدية رقمية فقط",
+			override:    false,
+		},
+		{
+			tag:         "numeric",
+			translation: "يجب أن يكون {0} قيمة رقمية صالحة",
+			override:    false,
+		},
+		{
+			tag:         "number",
+			translation: "يجب أن يكون {0} رقم صالح",
+			override:    false,
+		},
+		{
+			tag:         "hexadecimal",
+			translation: "يجب أن يكون {0} عددًا سداسيًا عشريًا صالحاً",
+			override:    false,
+		},
+		{
+			tag:         "hexcolor",
+			translation: "يجب أن يكون {0} لون HEX صالح",
+			override:    false,
+		},
+		{
+			tag:         "rgb",
+			translation: "يجب أن يكون {0} لون RGB صالح",
+			override:    false,
+		},
+		{
+			tag:         "rgba",
+			translation: "يجب أن يكون {0} لون RGBA صالح",
+			override:    false,
+		},
+		{
+			tag:         "hsl",
+			translation: "يجب أن يكون {0} لون HSL صالح",
+			override:    false,
+		},
+		{
+			tag:         "hsla",
+			translation: "يجب أن يكون {0} لون HSLA صالح",
+			override:    false,
+		},
+		{
+			tag:         "e164",
+			translation: "يجب أن يكون {0} رقم هاتف صالح بتنسيق E.164",
+			override:    false,
+		},
+		{
+			tag:         "email",
+			translation: "يجب أن يكون {0} عنوان بريد إلكتروني صالح",
+			override:    false,
+		},
+		{
+			tag:         "url",
+			translation: "يجب أن يكون {0} رابط إنترنت صالح",
+			override:    false,
+		},
+		{
+			tag:         "uri",
+			translation: "يجب أن يكون {0} URI صالح",
+			override:    false,
+		},
+		{
+			tag:         "base64",
+			translation: "يجب أن يكون {0} سلسلة Base64 صالحة",
+			override:    false,
+		},
+		{
+			tag:         "contains",
+			translation: "يجب أن يحتوي {0} على النص '{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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "containsany",
+			translation: "يجب أن يحتوي {0} على حرف واحد على الأقل من الأحرف التالية '{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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "excludes",
+			translation: "لا يمكن أن يحتوي {0} على النص '{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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "excludesall",
+			translation: "لا يمكن أن يحتوي {0} على أي من الأحرف التالية '{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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "excludesrune",
+			translation: "لا يمكن أن يحتوي {0} على التالي '{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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "isbn",
+			translation: "يجب أن يكون {0} رقم ISBN صالح",
+			override:    false,
+		},
+		{
+			tag:         "isbn10",
+			translation: "يجب أن يكون {0} رقم ISBN-10 صالح",
+			override:    false,
+		},
+		{
+			tag:         "isbn13",
+			translation: "يجب أن يكون {0} رقم ISBN-13 صالح",
+			override:    false,
+		},
+		{
+			tag:         "uuid",
+			translation: "يجب أن يكون {0} UUID صالح",
+			override:    false,
+		},
+		{
+			tag:         "uuid3",
+			translation: "يجب أن يكون {0} UUID صالح من النسخة 3",
+			override:    false,
+		},
+		{
+			tag:         "uuid4",
+			translation: "يجب أن يكون {0} UUID صالح من النسخة 4",
+			override:    false,
+		},
+		{
+			tag:         "uuid5",
+			translation: "يجب أن يكون {0} UUID صالح من النسخة 5",
+			override:    false,
+		},
+		{
+			tag:         "ulid",
+			translation: "يجب أن يكون {0} ULID صالح من نسخة",
+			override:    false,
+		},
+		{
+			tag:         "ascii",
+			translation: "يجب أن يحتوي {0} على أحرف ascii فقط",
+			override:    false,
+		},
+		{
+			tag:         "printascii",
+			translation: "يجب أن يحتوي {0} على أحرف ascii قابلة للطباعة فقط",
+			override:    false,
+		},
+		{
+			tag:         "multibyte",
+			translation: "يجب أن يحتوي {0} على أحرف متعددة البايت",
+			override:    false,
+		},
+		{
+			tag:         "datauri",
+			translation: "يجب أن يحتوي {0} على URI صالح للبيانات",
+			override:    false,
+		},
+		{
+			tag:         "latitude",
+			translation: "يجب أن يحتوي {0} على إحداثيات خط عرض صالحة",
+			override:    false,
+		},
+		{
+			tag:         "longitude",
+			translation: "يجب أن يحتوي {0} على إحداثيات خط طول صالحة",
+			override:    false,
+		},
+		{
+			tag:         "ssn",
+			translation: "يجب أن يكون {0} رقم SSN صالح",
+			override:    false,
+		},
+		{
+			tag:         "ipv4",
+			translation: "يجب أن يكون {0} عنوان IPv4 صالح",
+			override:    false,
+		},
+		{
+			tag:         "ipv6",
+			translation: "يجب أن يكون {0} عنوان IPv6 صالح",
+			override:    false,
+		},
+		{
+			tag:         "ip",
+			translation: "يجب أن يكون {0} عنوان IP صالح",
+			override:    false,
+		},
+		{
+			tag:         "cidr",
+			translation: "يجب أن يحتوي {0} على علامة CIDR صالحة",
+			override:    false,
+		},
+		{
+			tag:         "cidrv4",
+			translation: "يجب أن يحتوي {0} على علامة CIDR صالحة لعنوان IPv4",
+			override:    false,
+		},
+		{
+			tag:         "cidrv6",
+			translation: "يجب أن يحتوي {0} على علامة CIDR صالحة لعنوان IPv6",
+			override:    false,
+		},
+		{
+			tag:         "tcp_addr",
+			translation: "يجب أن يكون {0} عنوان TCP صالح",
+			override:    false,
+		},
+		{
+			tag:         "tcp4_addr",
+			translation: "يجب أن يكون {0} عنوان IPv4 TCP صالح",
+			override:    false,
+		},
+		{
+			tag:         "tcp6_addr",
+			translation: "يجب أن يكون {0} عنوان IPv6 TCP صالح",
+			override:    false,
+		},
+		{
+			tag:         "udp_addr",
+			translation: "يجب أن يكون {0} عنوان UDP صالح",
+			override:    false,
+		},
+		{
+			tag:         "udp4_addr",
+			translation: "يجب أن يكون {0} عنوان IPv4 UDP صالح",
+			override:    false,
+		},
+		{
+			tag:         "udp6_addr",
+			translation: "يجب أن يكون {0} عنوان IPv6 UDP صالح",
+			override:    false,
+		},
+		{
+			tag:         "ip_addr",
+			translation: "يجب أن يكون {0} عنوان IP قابل للحل",
+			override:    false,
+		},
+		{
+			tag:         "ip4_addr",
+			translation: "يجب أن يكون {0} عنوان IP قابل للحل",
+			override:    false,
+		},
+		{
+			tag:         "ip6_addr",
+			translation: "يجب أن يكون {0} عنوان IPv6 قابل للحل",
+			override:    false,
+		},
+		{
+			tag:         "unix_addr",
+			translation: "يجب أن يكون {0} عنوان UNIX قابل للحل",
+			override:    false,
+		},
+		{
+			tag:         "mac",
+			translation: "يجب أن يحتوي {0} على عنوان MAC صالح",
+			override:    false,
+		},
+		{
+			tag:         "unique",
+			translation: "يجب أن يحتوي {0} على قيم فريدة",
+			override:    false,
+		},
+		{
+			tag:         "iscolor",
+			translation: "يجب أن يكون {0} لون صالح",
+			override:    false,
+		},
+		{
+			tag:         "oneof",
+			translation: "يجب أن يكون {0} واحدا من [{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:         "json",
+			translation: "يجب أن يكون {0} نص json صالح",
+			override:    false,
+		},
+		{
+			tag:         "jwt",
+			translation: "يجب أن يكون {0} نص jwt صالح",
+			override:    false,
+		},
+		{
+			tag:         "lowercase",
+			translation: "يجب أن يكون {0} نص حروف صغيرة",
+			override:    false,
+		},
+		{
+			tag:         "uppercase",
+			translation: "يجب أن يكون {0} نص حروف كبيرة",
+			override:    false,
+		},
+		{
+			tag:         "datetime",
+			translation: "لا يتطابق {0} مع تنسيق {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "postcode_iso3166_alpha2",
+			translation: "لا يتطابق {0} مع تنسيق الرمز البريدي للبلد {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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "postcode_iso3166_alpha2_field",
+			translation: "لا يتطابق {0} مع تنسيق الرمز البريدي للبلد في حقل {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()
+				}
+
+				return t
+			},
+		},
+	}
+
+	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)
+		}
+
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+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
+	}
+}
+
+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
+}
diff --git a/translations/en/en.go b/translations/en/en.go
index 5ed76ae..ee05f91 100644
--- a/translations/en/en.go
+++ b/translations/en/en.go
@@ -28,6 +28,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} is a required field",
 			override:    false,
 		},
+		{
+			tag:         "required_if",
+			translation: "{0} is a required field",
+			override:    false,
+		},
 		{
 			tag: "len",
 			customRegisFunc: func(ut ut.Translator) (err error) {
@@ -1346,6 +1351,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 				return t
 			},
 		},
+		{
+			tag:         "boolean",
+			translation: "{0} must be a valid boolean value",
+			override:    false,
+		},
 	}
 
 	for _, t := range translations {
diff --git a/translations/it/it.go b/translations/it/it.go
new file mode 100644
index 0000000..0b46fc4
--- /dev/null
+++ b/translations/it/it.go
@@ -0,0 +1,1256 @@
+package it
+
+import (
+	"fmt"
+	"log"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/go-playground/locales"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+)
+
+// 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
+		override        bool
+		customRegisFunc validator.RegisterTranslationsFunc
+		customTransFunc validator.TranslationFunc
+	}{
+		{
+			tag:         "required",
+			translation: "{0} è un campo obbligatorio",
+			override:    false,
+		},
+		{
+			tag:         "required_without",
+			translation: "{0} è un campo obbligatorio",
+			override:    false,
+		},
+		{
+			tag: "len",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("len-string", "{0} deve essere lungo {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("len-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("len-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("len-number", "{0} deve essere uguale a {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("len-items", "{0} deve contenere {1}", false); err != nil {
+					return
+				}
+				if err = ut.AddCardinal("len-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("len-items-item", "{0} elementi", 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: "min",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+        
+				if err = ut.Add("min-string", "{0} deve essere lungo almeno {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("min-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("min-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("min-number", "{0} deve essere maggiore o uguale a {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("min-items", "{0} deve contenere almeno {1}", false); err != nil {
+					return
+				}
+				if err = ut.AddCardinal("min-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("min-items-item", "{0} elementi", 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("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()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "max",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("max-string", "{0} deve essere lungo al massimo {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("max-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("max-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("max-number", "{0} deve essere minore o uguale a {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("max-items", "{0} deve contenere al massimo {1}", false); err != nil {
+					return
+				}
+				if err = ut.AddCardinal("max-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("max-items-item", "{0} elementi", 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:             "eq",
+			translation:     "{0} non è uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "ne",
+			translation:     "{0} deve essere diverso da {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag: "lt",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("lt-string", "{0} deve essere lungo meno di {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-number", "{0} deve essere minore di {1}", false); err != nil {
+
+					return
+				}
+
+				if err = ut.Add("lt-items", "{0} deve contenere meno di {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lt-items-item", "{0} elementi", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-datetime", "{0} deve essere precedente alla Data/Ora corrente", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("lt-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-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: "lte",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+        
+				if err = ut.Add("lte-string", "{0} deve essere lungo al massimo {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-number", "{0} deve essere minore o uguale a {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-items", "{0} deve contenere al massimo {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("lte-items-item", "{0} elementi", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-datetime", "{0} deve essere uguale o precedente alla Data/Ora corrente", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("lte-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-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: "gt",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+
+				if err = ut.Add("gt-string", "{0} deve essere lungo più di {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-number", "{0} deve essere maggiore di {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-items", "{0} deve contenere più di {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gt-items-item", "{0} elementi", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-datetime", "{0} deve essere successivo alla Data/Ora corrente", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("gt-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-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: "gte",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("gte-string", "{0} deve essere lungo almeno {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-string-character", "{0} carattere", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-string-character", "{0} caratteri", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-number", "{0} deve essere maggiore o uguale a {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-items", "{0} deve contenere almeno {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-items-item", "{0} elemento", locales.PluralRuleOne, false); err != nil {
+					return
+				}
+
+				if err = ut.AddCardinal("gte-items-item", "{0} elementi", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-datetime", "{0} deve essere uguale o successivo alla Data/Ora corrente", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("gte-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-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} deve essere uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "eqcsfield",
+			translation:     "{0} deve essere uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "necsfield",
+			translation:     "{0} deve essere diverso da {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "gtcsfield",
+			translation:     "{0} deve essere maggiore di {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "gtecsfield",
+			translation:     "{0} deve essere maggiore o uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "ltcsfield",
+			translation:     "{0} deve essere minore di {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "ltecsfield",
+			translation:     "{0} deve essere minore o uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "nefield",
+			translation:     "{0} deve essere diverso da {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "gtfield",
+			translation:     "{0} deve essere maggiore di {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "gtefield",
+			translation:     "{0} deve essere maggiore o uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "ltfield",
+			translation:     "{0} deve essere minore di {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "ltefield",
+			translation:     "{0} deve essere minore o uguale a {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:         "alpha",
+			translation: "{0} può contenere solo caratteri alfabetici",
+			override:    false,
+		},
+		{
+			tag:         "alphanum",
+			translation: "{0} può contenere solo caratteri alfanumerici",
+			override:    false,
+		},
+		{
+			tag:         "numeric",
+			translation: "{0} deve essere un valore numerico valido",
+			override:    false,
+		},
+		{
+			tag:         "number",
+			translation: "{0} deve essere un numero valido",
+			override:    false,
+		},
+		{
+			tag:         "hexadecimal",
+			translation: "{0} deve essere un esadecimale valido",
+			override:    false,
+		},
+		{
+			tag:         "hexcolor",
+			translation: "{0} deve essere un colore HEX valido",
+			override:    false,
+		},
+		{
+			tag:         "rgb",
+			translation: "{0} deve essere un colore RGB valido",
+			override:    false,
+		},
+		{
+			tag:         "rgba",
+			translation: "{0} deve essere un colore RGBA valido",
+			override:    false,
+		},
+		{
+			tag:         "hsl",
+			translation: "{0} deve essere un colore HSL valido",
+			override:    false,
+		},
+		{
+			tag:         "hsla",
+			translation: "{0} deve essere un colore HSLA valido",
+			override:    false,
+		},
+		{
+			tag:         "e164",
+			translation: "{0} deve essere un numero telefonico in formato E.164 valido",
+			override:    false,
+		},
+		{
+			tag:         "email",
+			translation: "{0} deve essere un indirizzo email valido",
+			override:    false,
+		},
+		{
+			tag:         "url",
+			translation: "{0} deve essere un URL valido",
+			override:    false,
+		},
+		{
+			tag:         "uri",
+			translation: "{0} deve essere un URI valido",
+			override:    false,
+		},
+		{
+			tag:         "base64",
+			translation: "{0} deve essere una stringa Base64 valida",
+			override:    false,
+		},
+		{
+			tag:             "contains",
+			translation:     "{0} deve contenere il testo '{1}'",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "containsany",
+			translation:     "{0} deve contenere almeno uno dei seguenti caratteri '{1}'",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "excludes",
+			translation:     "{0} non deve contenere il testo '{1}'",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "excludesall",
+			translation:     "{0} non deve contenere alcuno dei seguenti caratteri '{1}'",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "excludesrune",
+			translation:     "{0} non deve contenere '{1}'",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:         "isbn",
+			translation: "{0} deve essere un numero ISBN valido",
+			override:    false,
+		},
+		{
+			tag:         "isbn10",
+			translation: "{0} deve essere un numero ISBN-10 valido",
+			override:    false,
+		},
+		{
+			tag:         "isbn13",
+			translation: "{0} deve essere un numero ISBN-13 valido",
+			override:    false,
+		},
+		{
+			tag:         "uuid",
+			translation: "{0} deve essere un UUID valido",
+			override:    false,
+		},
+		{
+			tag:         "uuid3",
+			translation: "{0} deve essere un UUID versione 3 valido",
+			override:    false,
+		},
+		{
+			tag:         "uuid4",
+			translation: "{0} deve essere un UUID versione 4 valido",
+			override:    false,
+		},
+		{
+			tag:         "uuid5",
+			translation: "{0} deve essere un UUID versione 5 valido",
+			override:    false,
+		},
+		{
+			tag:         "ulid",
+			translation: "{0} deve essere un ULID valido",
+			override:    false,
+		},
+		{
+			tag:         "ascii",
+			translation: "{0} deve contenere solo caratteri ascii",
+			override:    false,
+		},
+		{
+			tag:         "printascii",
+			translation: "{0} deve contenere solo caratteri ascii stampabili",
+			override:    false,
+		},
+		{
+			tag:         "multibyte",
+			translation: "{0} deve contenere caratteri multibyte",
+			override:    false,
+		},
+		{
+			tag:         "datauri",
+			translation: "{0} deve contenere un Data URI valido",
+			override:    false,
+		},
+		{
+			tag:         "latitude",
+			translation: "{0} deve contenere una latitudine valida",
+			override:    false,
+		},
+		{
+			tag:         "longitude",
+			translation: "{0} deve contenere una longitudine valida",
+			override:    false,
+		},
+		{
+			tag:         "ssn",
+			translation: "{0} deve essere un numero SSN valido",
+			override:    false,
+		},
+		{
+			tag:         "ipv4",
+			translation: "{0} deve essere un indirizzo IPv4 valido",
+			override:    false,
+		},
+		{
+			tag:         "ipv6",
+			translation: "{0} deve essere un indirizzo IPv6 valido",
+			override:    false,
+		},
+		{
+			tag:         "ip",
+			translation: "{0} deve essere un indirizzo IP valido",
+			override:    false,
+		},
+		{
+			tag:         "cidr",
+			translation: "{0} deve contenere una notazione CIDR valida",
+			override:    false,
+		},
+		{
+			tag:         "cidrv4",
+			translation: "{0} deve contenere una notazione CIDR per un indirizzo IPv4 valida",
+			override:    false,
+		},
+		{
+			tag:         "cidrv6",
+			translation: "{0} deve contenere una notazione CIDR per un indirizzo IPv6 valida",
+			override:    false,
+		},
+		{
+			tag:         "tcp_addr",
+			translation: "{0} deve essere un indirizzo TCP valido",
+			override:    false,
+		},
+		{
+			tag:         "tcp4_addr",
+			translation: "{0} deve essere un indirizzo IPv4 TCP valido",
+			override:    false,
+		},
+		{
+			tag:         "tcp6_addr",
+			translation: "{0} deve essere un indirizzo IPv6 TCP valido",
+			override:    false,
+		},
+		{
+			tag:         "udp_addr",
+			translation: "{0} deve essere un indirizzo UDP valido",
+			override:    false,
+		},
+		{
+			tag:         "udp4_addr",
+			translation: "{0} deve essere un indirizzo IPv4 UDP valido",
+			override:    false,
+		},
+		{
+			tag:         "udp6_addr",
+			translation: "{0} deve essere un indirizzo IPv6 UDP valido",
+			override:    false,
+		},
+		{
+			tag:         "ip_addr",
+			translation: "{0} deve essere un indirizzo IP risolvibile",
+			override:    false,
+		},
+		{
+			tag:         "ip4_addr",
+			translation: "{0} deve essere un indirizzo IPv4 risolvibile",
+			override:    false,
+		},
+		{
+			tag:         "ip6_addr",
+			translation: "{0} deve essere un indirizzo IPv6 risolvibile",
+			override:    false,
+		},
+		{
+			tag:         "unix_addr",
+			translation: "{0} deve essere un indirizzo UNIX risolvibile",
+			override:    false,
+		},
+		{
+			tag:         "mac",
+			translation: "{0} deve contenere un indirizzo MAC valido",
+			override:    false,
+		},
+		{
+			tag:         "unique",
+			translation: "{0} deve contenere valori unici",
+			override:    false,
+		},
+		{
+			tag:         "iscolor",
+			translation: "{0} deve essere un colore valido",
+			override:    false,
+		},
+		{
+			tag:             "oneof",
+			translation:     "{0} deve essere uno di [{1}]",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:         "json",
+			translation: "{0} deve essere una stringa json valida",
+			override:    false,
+		},
+		{
+			tag:         "jwt",
+			translation: "{0} deve essere una stringa jwt valida",
+			override:    false,
+		},
+		{
+			tag:         "lowercase",
+			translation: "{0} deve essere una stringa minuscola",
+			override:    false,
+		},
+		{
+			tag:         "boolean",
+			translation: "{0} deve rappresentare un valore booleano",
+			override:    false,
+		},
+		{
+			tag:         "uppercase",
+			translation: "{0} deve essere una stringa maiuscola",
+			override:    false,
+		},
+		{
+			tag:             "startswith",
+			translation:     "{0} deve iniziare con {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "startsnotwith",
+			translation:     "{0} non deve iniziare con {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "endswith",
+			translation:     "{0} deve terminare con {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "endsnotwith",
+			translation:     "{0} non deve terminare con {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "datetime",
+			translation:     "{0} non corrisponde al formato {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "postcode_iso3166_alpha2",
+			translation:     "{0} non corrisponde al formato del codice postale dello stato {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+		{
+			tag:             "postcode_iso3166_alpha2_field",
+			translation:     "{0} non corrisponde al formato del codice postale dello stato nel campo {1}",
+			override:        false,
+			customTransFunc: customTransFuncV1,
+		},
+	}
+
+	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)
+		}
+
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+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
+	}
+}
+
+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
+}
+
+func customTransFuncV1(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
+}
diff --git a/translations/ja/ja.go b/translations/ja/ja.go
index 4502e2d..1cc67a4 100644
--- a/translations/ja/ja.go
+++ b/translations/ja/ja.go
@@ -136,7 +136,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 					return
 				}
 
-				if err = ut.Add("min-number", "{0}は{1}かより大きくなければなりません", false); err != nil {
+				if err = ut.Add("min-number", "{0}は{1}より大きくなければなりません", false); err != nil {
 					return
 				}
 
@@ -227,7 +227,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 					return
 				}
 
-				if err = ut.Add("max-number", "{0}は{1}かより小さくなければなりません", false); err != nil {
+				if err = ut.Add("max-number", "{0}は{1}より小さくなければなりません", false); err != nil {
 					return
 				}
 
@@ -525,7 +525,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 					return
 				}
 
-				if err = ut.Add("lte-number", "{0}は{1}かより小さくなければなりません", false); err != nil {
+				if err = ut.Add("lte-number", "{0}は{1}より小さくなければなりません", false); err != nil {
 					return
 				}
 
@@ -765,7 +765,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 					return
 				}
 
-				if err = ut.Add("gte-number", "{0}は{1}かより大きくなければなりません", false); err != nil {
+				if err = ut.Add("gte-number", "{0}は{1}より大きくなければなりません", false); err != nil {
 					return
 				}
 
diff --git a/translations/pt_BR/pt_BR.go b/translations/pt_BR/pt_BR.go
index ef04496..d6883aa 100644
--- a/translations/pt_BR/pt_BR.go
+++ b/translations/pt_BR/pt_BR.go
@@ -1316,6 +1316,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 				return s
 			},
 		},
+		{
+			tag:         "boolean",
+			translation: "{0} deve ser um valor booleano válido",
+			override:    false,
+		},
 	}
 
 	for _, t := range translations {
diff --git a/translations/vi/vi.go b/translations/vi/vi.go
new file mode 100644
index 0000000..009ba4c
--- /dev/null
+++ b/translations/vi/vi.go
@@ -0,0 +1,1384 @@
+package vi
+
+import (
+	"fmt"
+	"log"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/go-playground/locales"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+)
+
+// 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
+		override        bool
+		customRegisFunc validator.RegisterTranslationsFunc
+		customTransFunc validator.TranslationFunc
+	}{
+		{
+			tag:         "required",
+			translation: "{0} không được bỏ trống",
+			override:    false,
+		},
+		{
+			tag: "len",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("len-string", "{0} phải có độ dài là {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("len-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("len-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("len-number", "{0} phải bằng {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("len-items", "{0} phải chứa {1}", false); err != nil {
+					return
+				}
+				// if err = ut.AddCardinal("len-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("len-items-item", "{0} phần tử", 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("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "min",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("min-string", "{0} phải chứa ít nhất {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("min-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("min-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("min-number", "{0} phải bằng {1} hoặc lớn hơn", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("min-items", "{0} phải chứa ít nhất {1}", false); err != nil {
+					return
+				}
+				// if err = ut.AddCardinal("min-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("min-items-item", "{0} phần tử", 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("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("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "max",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("max-string", "{0} chỉ được chứa tối đa {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("max-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("max-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("max-number", "{0} phải là {1} hoặc nhỏ hơn", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("max-items", "{0} chỉ được chứa tối đa {1}", false); err != nil {
+					return
+				}
+				// if err = ut.AddCardinal("max-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("max-items-item", "{0} phần tử", 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("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "eq",
+			translation: "{0} không bằng {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 {
+					fmt.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ne",
+			translation: "{0} không được bằng {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 {
+					fmt.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "lt",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("lt-string", "{0} phải có độ dài nhỏ hơn {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("lt-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("lt-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-number", "{0} phải nhỏ hơn {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-items", "{0} chỉ được chứa ít hơn {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("lt-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("lt-items-item", "{0} phần tử", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lt-datetime", "{0} phải nhỏ hơn Ngày & Giờ hiện tại", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' không thể dùng trên kiểu struct", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("lt-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits))
+				}
+
+			END:
+				if err != nil {
+					fmt.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "lte",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("lte-string", "{0} chỉ được có độ dài tối đa là {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("lte-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("lte-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-number", "{0} phải là {1} hoặc nhỏ hơn", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-items", "{0} chỉ được chứa nhiều nhất {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("lte-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("lte-items-item", "{0} phần tử", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("lte-datetime", "{0} chỉ được nhỏ hơn hoặc bằng Ngày & Giờ hiện tại", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' không thể dùng trên kiểu struct", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("lte-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits))
+				}
+
+			END:
+				if err != nil {
+					fmt.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "gt",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("gt-string", "{0} phải có độ dài lớn hơn {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("gt-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("gt-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-number", "{0} phải lớn hơn {1}", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-items", "{0} phải chứa nhiều hơn {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("gt-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("gt-items-item", "{0} phần tử", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gt-datetime", "{0} phải lớn hơn Ngày & Giờ hiện tại", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' không thể dùng trên kiểu struct", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("gt-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits))
+				}
+
+			END:
+				if err != nil {
+					fmt.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag: "gte",
+			customRegisFunc: func(ut ut.Translator) (err error) {
+				if err = ut.Add("gte-string", "{0} phải có độ dài ít nhất {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("gte-string-character", "{0} ký tự", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("gte-string-character", "{0} ký tự", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-number", "{0} phải là {1} hoặc lớn hơn", false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-items", "{0} phải chứa ít nhất {1}", false); err != nil {
+					return
+				}
+
+				// if err = ut.AddCardinal("gte-items-item", "{0} phần tử", locales.PluralRuleOne, false); err != nil {
+				// 	return
+				// }
+
+				if err = ut.AddCardinal("gte-items-item", "{0} phần tử", locales.PluralRuleOther, false); err != nil {
+					return
+				}
+
+				if err = ut.Add("gte-datetime", "{0} phải lớn hơn hoặc bằng Ngày & Giờ hiện tại", false); err != nil {
+					return
+				}
+
+				return
+			},
+			customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
+				var err error
+				var t string
+				var f64 float64
+				var digits uint64
+				var kind reflect.Kind
+
+				fn := func() (err error) {
+					if idx := strings.Index(fe.Param(), "."); idx != -1 {
+						digits = uint64(len(fe.Param()[idx+1:]))
+					}
+
+					f64, err = strconv.ParseFloat(fe.Param(), 64)
+
+					return
+				}
+
+				kind = fe.Kind()
+				if kind == reflect.Ptr {
+					kind = fe.Type().Elem().Kind()
+				}
+
+				switch kind {
+				case reflect.String:
+
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-string", fe.Field(), c)
+
+				case reflect.Slice, reflect.Map, reflect.Array:
+					var c string
+
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits))
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-items", fe.Field(), c)
+
+				case reflect.Struct:
+					if fe.Type() != reflect.TypeOf(time.Time{}) {
+						err = fmt.Errorf("tag '%s' không thể dùng trên kiểu struct", fe.Tag())
+						goto END
+					}
+
+					t, err = ut.T("gte-datetime", fe.Field())
+
+				default:
+					err = fn()
+					if err != nil {
+						goto END
+					}
+
+					t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits))
+				}
+
+			END:
+				if err != nil {
+					fmt.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %s", err)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "eqfield",
+			translation: "{0} phải bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "eqcsfield",
+			translation: "{0} phải bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "necsfield",
+			translation: "{0} không được phép bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtcsfield",
+			translation: "{0} phải lớn hơn {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtecsfield",
+			translation: "{0} phải lớn hơn hoặc bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltcsfield",
+			translation: "{0} chỉ được nhỏ hơn {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltecsfield",
+			translation: "{0} chỉ được nhỏ hơn hoặc bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "nefield",
+			translation: "{0} không được phép bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtfield",
+			translation: "{0} phải lớn hơn {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "gtefield",
+			translation: "{0} phải lớn hơn hoặc bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltfield",
+			translation: "{0} chỉ được nhỏ hơn {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "ltefield",
+			translation: "{0} chỉ được nhỏ hơn hoặc bằng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "alpha",
+			translation: "{0} chỉ được chứa ký tự dạng alphabetic",
+			override:    false,
+		},
+		{
+			tag:         "alphanum",
+			translation: "{0} chỉ được chứa ký tự dạng alphanumeric",
+			override:    false,
+		},
+		{
+			tag:         "numeric",
+			translation: "{0} chỉ được chứa giá trị số hoặc số dưới dạng chữ",
+			override:    false,
+		},
+		{
+			tag:         "number",
+			translation: "{0} chỉ được chứa giá trị số",
+			override:    false,
+		},
+		{
+			tag:         "hexadecimal",
+			translation: "{0} phải là giá trị hexadecimal",
+			override:    false,
+		},
+		{
+			tag:         "hexcolor",
+			translation: "{0} phải là giá trị HEX color",
+			override:    false,
+		},
+		{
+			tag:         "rgb",
+			translation: "{0} phải là giá trị RGB color",
+			override:    false,
+		},
+		{
+			tag:         "rgba",
+			translation: "{0} phải là giá trị RGBA color",
+			override:    false,
+		},
+		{
+			tag:         "hsl",
+			translation: "{0} phải là giá trị HSL color",
+			override:    false,
+		},
+		{
+			tag:         "hsla",
+			translation: "{0} phải là giá trị HSLA color",
+			override:    false,
+		},
+		{
+			tag:         "e164",
+			translation: "{0} phải là giá trị số điện thoại theo định dạng E.164",
+			override:    false,
+		},
+		{
+			tag:         "email",
+			translation: "{0} phải là giá trị email address",
+			override:    false,
+		},
+		{
+			tag:         "url",
+			translation: "{0} phải là giá trị URL",
+			override:    false,
+		},
+		{
+			tag:         "uri",
+			translation: "{0} phải là giá trị URI",
+			override:    false,
+		},
+		{
+			tag:         "base64",
+			translation: "{0} phải là giá trị chuỗi Base64",
+			override:    false,
+		},
+		{
+			tag:         "contains",
+			translation: "{0} phải chứa chuỗi '{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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "containsany",
+			translation: "{0} phải chứa ít nhất 1 trong cách ký tự sau '{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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "excludes",
+			translation: "{0} không được chứa chuỗi '{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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "excludesall",
+			translation: "{0} không được chứa bất kỳ ký tự nào trong nhóm ký tự '{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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "excludesrune",
+			translation: "{0} không được chứa '{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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "isbn",
+			translation: "{0} phải là số ISBN",
+			override:    false,
+		},
+		{
+			tag:         "isbn10",
+			translation: "{0} phải là số ISBN-10",
+			override:    false,
+		},
+		{
+			tag:         "isbn13",
+			translation: "{0} phải là số ISBN-13",
+			override:    false,
+		},
+		{
+			tag:         "uuid",
+			translation: "{0} phải là giá trị UUID",
+			override:    false,
+		},
+		{
+			tag:         "uuid3",
+			translation: "{0} phải là giá trị UUID phiên bản 3",
+			override:    false,
+		},
+		{
+			tag:         "uuid4",
+			translation: "{0} phải là giá trị UUID phiên bản 4",
+			override:    false,
+		},
+		{
+			tag:         "uuid5",
+			translation: "{0} phải là giá trị UUID phiên bản 5",
+			override:    false,
+		},
+		{
+			tag:         "ascii",
+			translation: "{0} chỉ được chứa ký tự ASCII",
+			override:    false,
+		},
+		{
+			tag:         "printascii",
+			translation: "{0} chỉ được chứa ký tự ASCII có thể in ấn",
+			override:    false,
+		},
+		{
+			tag:         "multibyte",
+			translation: "{0} chỉ được chứa ký tự multibyte",
+			override:    false,
+		},
+		{
+			tag:         "datauri",
+			translation: "{0} chỉ được chứa Data URI",
+			override:    false,
+		},
+		{
+			tag:         "latitude",
+			translation: "{0} chỉ được chứa latitude (vỹ độ)",
+			override:    false,
+		},
+		{
+			tag:         "longitude",
+			translation: "{0} chỉ được chứa longitude (kinh độ)",
+			override:    false,
+		},
+		{
+			tag:         "ssn",
+			translation: "{0} phải là SSN number",
+			override:    false,
+		},
+		{
+			tag:         "ipv4",
+			translation: "{0} phải là địa chỉ IPv4",
+			override:    false,
+		},
+		{
+			tag:         "ipv6",
+			translation: "{0} phải là địa chỉ IPv6",
+			override:    false,
+		},
+		{
+			tag:         "ip",
+			translation: "{0} phải là địa chỉ IP",
+			override:    false,
+		},
+		{
+			tag:         "cidr",
+			translation: "{0} chỉ được chứa CIDR notation",
+			override:    false,
+		},
+		{
+			tag:         "cidrv4",
+			translation: "{0} chỉ được chứa CIDR notation của một địa chỉ IPv4",
+			override:    false,
+		},
+		{
+			tag:         "cidrv6",
+			translation: "{0} chỉ được chứa CIDR notation của một địa chỉ IPv6",
+			override:    false,
+		},
+		{
+			tag:         "tcp_addr",
+			translation: "{0} phải là địa chỉ TCP",
+			override:    false,
+		},
+		{
+			tag:         "tcp4_addr",
+			translation: "{0} phải là địa chỉ IPv4 TCP",
+			override:    false,
+		},
+		{
+			tag:         "tcp6_addr",
+			translation: "{0} phải là địa chỉ IPv6 TCP",
+			override:    false,
+		},
+		{
+			tag:         "udp_addr",
+			translation: "{0} phải là địa chỉ UDP",
+			override:    false,
+		},
+		{
+			tag:         "udp4_addr",
+			translation: "{0} phải là địa chỉ IPv4 UDP",
+			override:    false,
+		},
+		{
+			tag:         "udp6_addr",
+			translation: "{0} phải là địa chỉ IPv6 UDP",
+			override:    false,
+		},
+		{
+			tag:         "ip_addr",
+			translation: "{0} phải là địa chỉ IP có thể phân giải",
+			override:    false,
+		},
+		{
+			tag:         "ip4_addr",
+			translation: "{0} phải là địa chỉ IPv4 có thể phân giải",
+			override:    false,
+		},
+		{
+			tag:         "ip6_addr",
+			translation: "{0} phải là địa chỉ IPv6 có thể phân giải",
+			override:    false,
+		},
+		{
+			tag:         "unix_addr",
+			translation: "{0} phải là địa chỉ UNIX có thể phân giải",
+			override:    false,
+		},
+		{
+			tag:         "mac",
+			translation: "{0} chỉ được chứa địa chỉ MAC",
+			override:    false,
+		},
+		{
+			tag:         "unique",
+			translation: "{0} chỉ được chứa những giá trị không trùng lặp",
+			override:    false,
+		},
+		{
+			tag:         "iscolor",
+			translation: "{0} phải là màu sắc hợp lệ",
+			override:    false,
+		},
+		{
+			tag:         "oneof",
+			translation: "{0} phải là trong những giá trị [{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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+				return s
+			},
+		},
+		{
+			tag:         "json",
+			translation: "{0} phải là một chuỗi json hợp lệ",
+			override:    false,
+		},
+		{
+			tag:         "jwt",
+			translation: "{0} phải là một chuỗi jwt hợp lệ",
+			override:    false,
+		},
+		{
+			tag:         "lowercase",
+			translation: "{0} phải được viết thường",
+			override:    false,
+		},
+		{
+			tag:         "uppercase",
+			translation: "{0} phải được viết hoa",
+			override:    false,
+		},
+		{
+			tag:         "datetime",
+			translation: "{0} không trùng định dạng ngày tháng {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "postcode_iso3166_alpha2",
+			translation: "{0} sai định dạng postcode của quốc gia {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+		{
+			tag:         "postcode_iso3166_alpha2_field",
+			translation: "{0} sai định dạng postcode của quốc gia tương ứng thuộc trường {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("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+					return fe.(error).Error()
+				}
+
+				return t
+			},
+		},
+	}
+
+	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)
+		}
+
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+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
+	}
+}
+
+func translateFunc(ut ut.Translator, fe validator.FieldError) string {
+	t, err := ut.T(fe.Tag(), fe.Field())
+	if err != nil {
+		log.Printf("cảnh báo: lỗi chuyển ngữ FieldError: %#v", fe)
+		return fe.(error).Error()
+	}
+
+	return t
+}
diff --git a/translations/zh/zh.go b/translations/zh/zh.go
index 3dc7356..80165d0 100644
--- a/translations/zh/zh.go
+++ b/translations/zh/zh.go
@@ -29,6 +29,36 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0}为必填字段",
 			override:    false,
 		},
+		{
+			tag:         "required_if",
+			translation: "{0}为必填字段",
+			override:    false,
+		},
+		{
+			tag:         "required_unless",
+			translation: "{0}为必填字段",
+			override:    false,
+		},
+		{
+			tag:         "required_with",
+			translation: "{0}为必填字段",
+			override:    false,
+		},
+		{
+			tag:         "required_with_all",
+			translation: "{0}为必填字段",
+			override:    false,
+		},
+		{
+			tag:         "required_without",
+			translation: "{0}为必填字段",
+			override:    false,
+		},
+		{
+			tag:         "required_without_all",
+			translation: "{0}为必填字段",
+			override:    false,
+		},
 		{
 			tag: "len",
 			customRegisFunc: func(ut ut.Translator) (err error) {
diff --git a/util.go b/util.go
index 56420f4..36da855 100644
--- a/util.go
+++ b/util.go
@@ -82,7 +82,7 @@ BEGIN:
 		fld := namespace
 		var ns string
 
-		if typ != timeType {
+		if !typ.ConvertibleTo(timeType) {
 
 			idx := strings.Index(namespace, namespaceSeparator)
 
diff --git a/validator.go b/validator.go
index 2a4fad0..80da095 100644
--- a/validator.go
+++ b/validator.go
@@ -164,7 +164,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
 
 		typ = current.Type()
 
-		if typ != timeType {
+		if !typ.ConvertibleTo(timeType) {
 
 			if ct != nil {
 
@@ -355,6 +355,10 @@ OUTER:
 				v.ct = ct
 
 				if ct.fn(ctx, v) {
+					if ct.isBlockEnd {
+						ct = ct.next
+						continue OUTER
+					}
 
 					// drain rest of the 'or' values, then continue or leave
 					for {
@@ -368,6 +372,11 @@ OUTER:
 						if ct.typeof != typeOr {
 							continue OUTER
 						}
+
+						if ct.isBlockEnd {
+							ct = ct.next
+							continue OUTER
+						}
 					}
 				}
 
diff --git a/validator_instance.go b/validator_instance.go
index 973964f..48e726b 100644
--- a/validator_instance.go
+++ b/validator_instance.go
@@ -33,6 +33,8 @@ const (
 	excludedWithoutTag    = "excluded_without"
 	excludedWithTag       = "excluded_with"
 	excludedWithAllTag    = "excluded_with_all"
+	excludedIfTag         = "excluded_if"
+	excludedUnlessTag     = "excluded_unless"
 	skipValidationTag     = "-"
 	diveTag               = "dive"
 	keysTag               = "keys"
@@ -84,6 +86,7 @@ type Validate struct {
 	aliases          map[string]string
 	validations      map[string]internalValidationFuncWrapper
 	transTagFunc     map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
+	rules            map[reflect.Type]map[string]string
 	tagCache         *tagCache
 	structCache      *structCache
 }
@@ -120,7 +123,7 @@ func New() *Validate {
 		switch k {
 		// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
 		case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
-			excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
+			excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
 			_ = v.registerValidation(k, wrapFunc(val), true, true)
 		default:
 			// no need to error check here, baked in will always be valid
@@ -152,15 +155,24 @@ func (v *Validate) SetTagName(name string) {
 func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
 	errs := make(map[string]interface{})
 	for field, rule := range rules {
-		if reflect.ValueOf(rule).Kind() == reflect.Map && reflect.ValueOf(data[field]).Kind() == reflect.Map {
-			err := v.ValidateMapCtx(ctx, data[field].(map[string]interface{}), rule.(map[string]interface{}))
-			if len(err) > 0 {
-				errs[field] = err
+		if ruleObj, ok := rule.(map[string]interface{}); ok {
+			if dataObj, ok := data[field].(map[string]interface{}); ok {
+				err := v.ValidateMapCtx(ctx, dataObj, ruleObj)
+				if len(err) > 0 {
+					errs[field] = err
+				}
+			} else if dataObjs, ok := data[field].([]map[string]interface{}); ok {
+				for _, obj := range dataObjs {
+					err := v.ValidateMapCtx(ctx, obj, ruleObj)
+					if len(err) > 0 {
+						errs[field] = err
+					}
+				}
+			} else {
+				errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
 			}
-		} else if reflect.ValueOf(rule).Kind() == reflect.Map {
-			errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
-		} else {
-			err := v.VarCtx(ctx, data[field], rule.(string))
+		} else if ruleStr, ok := rule.(string); ok {
+			err := v.VarCtx(ctx, data[field], ruleStr)
 			if err != nil {
 				errs[field] = err
 			}
@@ -169,7 +181,7 @@ func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{
 	return errs
 }
 
-// ValidateMap validates map data form a map of tags
+// ValidateMap validates map data from a map of tags
 func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
 	return v.ValidateMapCtx(context.Background(), data, rules)
 }
@@ -180,6 +192,7 @@ func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]int
 //
 //    validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
 //        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
+//        // skip if tag key says it should be ignored
 //        if name == "-" {
 //            return ""
 //        }
@@ -271,6 +284,33 @@ func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...i
 	}
 }
 
+// RegisterStructValidationMapRules registers validate map rules
+//
+// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) {
+	if v.rules == nil {
+		v.rules = make(map[reflect.Type]map[string]string)
+	}
+
+	deepCopyRules := make(map[string]string)
+	for i, rule := range rules {
+		deepCopyRules[i] = rule
+	}
+
+	for _, t := range types {
+		typ := reflect.TypeOf(t)
+
+		if typ.Kind() == reflect.Ptr {
+			typ = typ.Elem()
+		}
+
+		if typ.Kind() != reflect.Struct {
+			continue
+		}
+		v.rules[typ] = deepCopyRules
+	}
+}
+
 // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
 //
 // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
@@ -331,7 +371,7 @@ func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
 		val = val.Elem()
 	}
 
-	if val.Kind() != reflect.Struct || val.Type() == timeType {
+	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
 		return &InvalidValidationError{Type: reflect.TypeOf(s)}
 	}
 
@@ -376,7 +416,7 @@ func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn Filt
 		val = val.Elem()
 	}
 
-	if val.Kind() != reflect.Struct || val.Type() == timeType {
+	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
 		return &InvalidValidationError{Type: reflect.TypeOf(s)}
 	}
 
@@ -424,7 +464,7 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
 		val = val.Elem()
 	}
 
-	if val.Kind() != reflect.Struct || val.Type() == timeType {
+	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
 		return &InvalidValidationError{Type: reflect.TypeOf(s)}
 	}
 
@@ -514,7 +554,7 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ..
 		val = val.Elem()
 	}
 
-	if val.Kind() != reflect.Struct || val.Type() == timeType {
+	if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
 		return &InvalidValidationError{Type: reflect.TypeOf(s)}
 	}
 


Test patch:
diff --git a/translations/ar/ar_test.go b/translations/ar/ar_test.go
new file mode 100644
index 0000000..93adfe9
--- /dev/null
+++ b/translations/ar/ar_test.go
@@ -0,0 +1,695 @@
+package ar
+
+import (
+	"testing"
+	"time"
+
+	. "github.com/go-playground/assert/v2"
+	english "github.com/go-playground/locales/en"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+)
+
+func TestTranslations(t *testing.T) {
+	eng := english.New()
+	uni := ut.New(eng, eng)
+	trans, _ := uni.GetTranslator("en")
+
+	validate := validator.New()
+
+	err := RegisterDefaultTranslations(validate, trans)
+	Equal(t, err, nil)
+
+	type Inner struct {
+		EqCSFieldString  string
+		NeCSFieldString  string
+		GtCSFieldString  string
+		GteCSFieldString string
+		LtCSFieldString  string
+		LteCSFieldString 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=purpose"`
+		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"`
+		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=red green"`
+		OneOfInt          int               `validate:"oneof=5 63"`
+		UniqueSlice       []string          `validate:"unique"`
+		UniqueArray       [3]string         `validate:"unique"`
+		UniqueMap         map[string]string `validate:"unique"`
+		JSONString        string            `validate:"json"`
+		JWTString         string            `validate:"jwt"`
+		LowercaseString   string            `validate:"lowercase"`
+		UppercaseString   string            `validate:"uppercase"`
+		Datetime          string            `validate:"datetime=2006-01-02"`
+		PostCode          string            `validate:"postcode_iso3166_alpha2=SG"`
+		PostCodeCountry   string
+		PostCodeByField   string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
+	}
+
+	var test Test
+
+	test.Inner.EqCSFieldString = "1234"
+	test.Inner.GtCSFieldString = "1234"
+	test.Inner.GteCSFieldString = "1234"
+
+	test.MaxString = "1234"
+	test.MaxNumber = 2000
+	test.MaxMultiple = make([]string, 9)
+
+	test.LtString = "1234"
+	test.LtNumber = 6
+	test.LtMultiple = make([]string, 3)
+	test.LtTime = time.Now().Add(time.Hour * 24)
+
+	test.LteString = "1234"
+	test.LteNumber = 6
+	test.LteMultiple = make([]string, 3)
+	test.LteTime = time.Now().Add(time.Hour * 24)
+
+	test.LtFieldString = "12345"
+	test.LteFieldString = "12345"
+
+	test.LtCSFieldString = "1234"
+	test.LteCSFieldString = "1234"
+
+	test.AlphaString = "abc3"
+	test.AlphanumString = "abc3!"
+	test.NumericString = "12E.00"
+	test.NumberString = "12E"
+
+	test.Excludes = "this is some test text"
+	test.ExcludesAll = "This is Great!"
+	test.ExcludesRune = "Love it ☻"
+
+	test.ASCII = "ｶﾀｶﾅ"
+	test.PrintableASCII = "ｶﾀｶﾅ"
+
+	test.MultiByte = "1234feerf"
+
+	test.LowercaseString = "ABCDEFG"
+	test.UppercaseString = "abcdefg"
+
+	s := "toolong"
+	test.StrPtrMaxLen = &s
+	test.StrPtrLen = &s
+
+	test.UniqueSlice = []string{"1234", "1234"}
+	test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
+	test.Datetime = "2008-Feb-01"
+
+	err = validate.Struct(test)
+	NotEqual(t, err, nil)
+
+	errs, ok := err.(validator.ValidationErrors)
+	Equal(t, ok, true)
+
+	tests := []struct {
+		ns       string
+		expected string
+	}{
+		{
+			ns:       "Test.IsColor",
+			expected: "يجب أن يكون IsColor لون صالح",
+		},
+		{
+			ns:       "Test.MAC",
+			expected: "يجب أن يحتوي MAC على عنوان MAC صالح",
+		},
+		{
+			ns:       "Test.IPAddr",
+			expected: "يجب أن يكون IPAddr عنوان IP قابل للحل",
+		},
+		{
+			ns:       "Test.IPAddrv4",
+			expected: "يجب أن يكون IPAddrv4 عنوان IP قابل للحل",
+		},
+		{
+			ns:       "Test.IPAddrv6",
+			expected: "يجب أن يكون IPAddrv6 عنوان IPv6 قابل للحل",
+		},
+		{
+			ns:       "Test.UDPAddr",
+			expected: "يجب أن يكون UDPAddr عنوان UDP صالح",
+		},
+		{
+			ns:       "Test.UDPAddrv4",
+			expected: "يجب أن يكون UDPAddrv4 عنوان IPv4 UDP صالح",
+		},
+		{
+			ns:       "Test.UDPAddrv6",
+			expected: "يجب أن يكون UDPAddrv6 عنوان IPv6 UDP صالح",
+		},
+		{
+			ns:       "Test.TCPAddr",
+			expected: "يجب أن يكون TCPAddr عنوان TCP صالح",
+		},
+		{
+			ns:       "Test.TCPAddrv4",
+			expected: "يجب أن يكون TCPAddrv4 عنوان IPv4 TCP صالح",
+		},
+		{
+			ns:       "Test.TCPAddrv6",
+			expected: "يجب أن يكون TCPAddrv6 عنوان IPv6 TCP صالح",
+		},
+		{
+			ns:       "Test.CIDR",
+			expected: "يجب أن يحتوي CIDR على علامة CIDR صالحة",
+		},
+		{
+			ns:       "Test.CIDRv4",
+			expected: "يجب أن يحتوي CIDRv4 على علامة CIDR صالحة لعنوان IPv4",
+		},
+		{
+			ns:       "Test.CIDRv6",
+			expected: "يجب أن يحتوي CIDRv6 على علامة CIDR صالحة لعنوان IPv6",
+		},
+		{
+			ns:       "Test.SSN",
+			expected: "يجب أن يكون SSN رقم SSN صالح",
+		},
+		{
+			ns:       "Test.IP",
+			expected: "يجب أن يكون IP عنوان IP صالح",
+		},
+		{
+			ns:       "Test.IPv4",
+			expected: "يجب أن يكون IPv4 عنوان IPv4 صالح",
+		},
+		{
+			ns:       "Test.IPv6",
+			expected: "يجب أن يكون IPv6 عنوان IPv6 صالح",
+		},
+		{
+			ns:       "Test.DataURI",
+			expected: "يجب أن يحتوي DataURI على URI صالح للبيانات",
+		},
+		{
+			ns:       "Test.Latitude",
+			expected: "يجب أن يحتوي Latitude على إحداثيات خط عرض صالحة",
+		},
+		{
+			ns:       "Test.Longitude",
+			expected: "يجب أن يحتوي Longitude على إحداثيات خط طول صالحة",
+		},
+		{
+			ns:       "Test.MultiByte",
+			expected: "يجب أن يحتوي MultiByte على أحرف متعددة البايت",
+		},
+		{
+			ns:       "Test.ASCII",
+			expected: "يجب أن يحتوي ASCII على أحرف ascii فقط",
+		},
+		{
+			ns:       "Test.PrintableASCII",
+			expected: "يجب أن يحتوي PrintableASCII على أحرف ascii قابلة للطباعة فقط",
+		},
+		{
+			ns:       "Test.UUID",
+			expected: "يجب أن يكون UUID UUID صالح",
+		},
+		{
+			ns:       "Test.UUID3",
+			expected: "يجب أن يكون UUID3 UUID صالح من النسخة 3",
+		},
+		{
+			ns:       "Test.UUID4",
+			expected: "يجب أن يكون UUID4 UUID صالح من النسخة 4",
+		},
+		{
+			ns:       "Test.UUID5",
+			expected: "يجب أن يكون UUID5 UUID صالح من النسخة 5",
+		},
+		{
+			ns:       "Test.ULID",
+			expected: "يجب أن يكون ULID ULID صالح من نسخة",
+		},
+		{
+			ns:       "Test.ISBN",
+			expected: "يجب أن يكون ISBN رقم ISBN صالح",
+		},
+		{
+			ns:       "Test.ISBN10",
+			expected: "يجب أن يكون ISBN10 رقم ISBN-10 صالح",
+		},
+		{
+			ns:       "Test.ISBN13",
+			expected: "يجب أن يكون ISBN13 رقم ISBN-13 صالح",
+		},
+		{
+			ns:       "Test.Excludes",
+			expected: "لا يمكن أن يحتوي Excludes على النص 'text'",
+		},
+		{
+			ns:       "Test.ExcludesAll",
+			expected: "لا يمكن أن يحتوي ExcludesAll على أي من الأحرف التالية '!@#$'",
+		},
+		{
+			ns:       "Test.ExcludesRune",
+			expected: "لا يمكن أن يحتوي ExcludesRune على التالي '☻'",
+		},
+		{
+			ns:       "Test.ContainsAny",
+			expected: "يجب أن يحتوي ContainsAny على حرف واحد على الأقل من الأحرف التالية '!@#$'",
+		},
+		{
+			ns:       "Test.Contains",
+			expected: "يجب أن يحتوي Contains على النص 'purpose'",
+		},
+		{
+			ns:       "Test.Base64",
+			expected: "يجب أن يكون Base64 سلسلة Base64 صالحة",
+		},
+		{
+			ns:       "Test.Email",
+			expected: "يجب أن يكون Email عنوان بريد إلكتروني صالح",
+		},
+		{
+			ns:       "Test.URL",
+			expected: "يجب أن يكون URL رابط إنترنت صالح",
+		},
+		{
+			ns:       "Test.URI",
+			expected: "يجب أن يكون URI URI صالح",
+		},
+		{
+			ns:       "Test.RGBColorString",
+			expected: "يجب أن يكون RGBColorString لون RGB صالح",
+		},
+		{
+			ns:       "Test.RGBAColorString",
+			expected: "يجب أن يكون RGBAColorString لون RGBA صالح",
+		},
+		{
+			ns:       "Test.HSLColorString",
+			expected: "يجب أن يكون HSLColorString لون HSL صالح",
+		},
+		{
+			ns:       "Test.HSLAColorString",
+			expected: "يجب أن يكون HSLAColorString لون HSLA صالح",
+		},
+		{
+			ns:       "Test.HexadecimalString",
+			expected: "يجب أن يكون HexadecimalString عددًا سداسيًا عشريًا صالحاً",
+		},
+		{
+			ns:       "Test.HexColorString",
+			expected: "يجب أن يكون HexColorString لون HEX صالح",
+		},
+		{
+			ns:       "Test.NumberString",
+			expected: "يجب أن يكون NumberString رقم صالح",
+		},
+		{
+			ns:       "Test.NumericString",
+			expected: "يجب أن يكون NumericString قيمة رقمية صالحة",
+		},
+		{
+			ns:       "Test.AlphanumString",
+			expected: "يمكن أن يحتوي AlphanumString على أحرف أبجدية رقمية فقط",
+		},
+		{
+			ns:       "Test.AlphaString",
+			expected: "يمكن أن يحتوي AlphaString على أحرف أبجدية فقط",
+		},
+		{
+			ns:       "Test.LtFieldString",
+			expected: "يجب أن يكون LtFieldString أصغر من MaxString",
+		},
+		{
+			ns:       "Test.LteFieldString",
+			expected: "يجب أن يكون LteFieldString أصغر من أو يساوي MaxString",
+		},
+		{
+			ns:       "Test.GtFieldString",
+			expected: "يجب أن يكون GtFieldString أكبر من MaxString",
+		},
+		{
+			ns:       "Test.GteFieldString",
+			expected: "يجب أن يكون GteFieldString أكبر من أو يساوي MaxString",
+		},
+		{
+			ns:       "Test.NeFieldString",
+			expected: "NeFieldString لا يمكن أن يساوي EqFieldString",
+		},
+		{
+			ns:       "Test.LtCSFieldString",
+			expected: "يجب أن يكون LtCSFieldString أصغر من Inner.LtCSFieldString",
+		},
+		{
+			ns:       "Test.LteCSFieldString",
+			expected: "يجب أن يكون LteCSFieldString أصغر من أو يساوي Inner.LteCSFieldString",
+		},
+		{
+			ns:       "Test.GtCSFieldString",
+			expected: "يجب أن يكون GtCSFieldString أكبر من Inner.GtCSFieldString",
+		},
+		{
+			ns:       "Test.GteCSFieldString",
+			expected: "يجب أن يكون GteCSFieldString أكبر من أو يساوي Inner.GteCSFieldString",
+		},
+		{
+			ns:       "Test.NeCSFieldString",
+			expected: "NeCSFieldString لا يمكن أن يساوي Inner.NeCSFieldString",
+		},
+		{
+			ns:       "Test.EqCSFieldString",
+			expected: "يجب أن يكون EqCSFieldString مساويا ل Inner.EqCSFieldString",
+		},
+		{
+			ns:       "Test.EqFieldString",
+			expected: "يجب أن يكون EqFieldString مساويا ل MaxString",
+		},
+		{
+			ns:       "Test.GteString",
+			expected: "يجب أن يكون طول GteString على الأقل 3 أحرف",
+		},
+		{
+			ns:       "Test.GteNumber",
+			expected: "GteNumber يجب أن يكون 5.56 أو أكبر",
+		},
+		{
+			ns:       "Test.GteMultiple",
+			expected: "يجب أن يحتوي GteMultiple على 2 عناصر على الأقل",
+		},
+		{
+			ns:       "Test.GteTime",
+			expected: "يجب أن يكون GteTime أكبر من أو يساوي التاريخ والوقت الحاليين",
+		},
+		{
+			ns:       "Test.GtString",
+			expected: "يجب أن يكون طول GtString أكبر من 3 أحرف",
+		},
+		{
+			ns:       "Test.GtNumber",
+			expected: "يجب أن يكون GtNumber أكبر من 5.56",
+		},
+		{
+			ns:       "Test.GtMultiple",
+			expected: "يجب أن يحتوي GtMultiple على أكثر من 2 عناصر",
+		},
+		{
+			ns:       "Test.GtTime",
+			expected: "يجب أن يكون GtTime أكبر من التاريخ والوقت الحاليين",
+		},
+		{
+			ns:       "Test.LteString",
+			expected: "يجب أن يكون طول LteString كحد أقصى 3 أحرف",
+		},
+		{
+			ns:       "Test.LteNumber",
+			expected: "LteNumber يجب أن يكون 5.56 أو اقل",
+		},
+		{
+			ns:       "Test.LteMultiple",
+			expected: "يجب أن يحتوي LteMultiple على 2 عناصر كحد أقصى",
+		},
+		{
+			ns:       "Test.LteTime",
+			expected: "يجب أن يكون LteTime أقل من أو يساوي التاريخ والوقت الحاليين",
+		},
+		{
+			ns:       "Test.LtString",
+			expected: "يجب أن يكون طول LtString أقل من 3 أحرف",
+		},
+		{
+			ns:       "Test.LtNumber",
+			expected: "يجب أن يكون LtNumber أقل من 5.56",
+		},
+		{
+			ns:       "Test.LtMultiple",
+			expected: "يجب أن يحتوي LtMultiple على أقل من 2 عناصر",
+		},
+		{
+			ns:       "Test.LtTime",
+			expected: "يجب أن يكون LtTime أقل من التاريخ والوقت الحاليين",
+		},
+		{
+			ns:       "Test.NeString",
+			expected: "NeString يجب ألا يساوي ",
+		},
+		{
+			ns:       "Test.NeNumber",
+			expected: "NeNumber يجب ألا يساوي 0.00",
+		},
+		{
+			ns:       "Test.NeMultiple",
+			expected: "NeMultiple يجب ألا يساوي 0",
+		},
+		{
+			ns:       "Test.EqString",
+			expected: "EqString لا يساوي 3",
+		},
+		{
+			ns:       "Test.EqNumber",
+			expected: "EqNumber لا يساوي 2.33",
+		},
+		{
+			ns:       "Test.EqMultiple",
+			expected: "EqMultiple لا يساوي 7",
+		},
+		{
+			ns:       "Test.MaxString",
+			expected: "يجب أن يكون طول MaxString بحد أقصى 3 أحرف",
+		},
+		{
+			ns:       "Test.MaxNumber",
+			expected: "MaxNumber يجب أن يكون 1,113.00 أو اقل",
+		},
+		{
+			ns:       "Test.MaxMultiple",
+			expected: "يجب أن يحتوي MaxMultiple على 7 عناصر كحد أقصى",
+		},
+		{
+			ns:       "Test.MinString",
+			expected: "MinString يجب أن يكون 1 حرف أو اقل",
+		},
+		{
+			ns:       "Test.MinNumber",
+			expected: "MinNumber يجب أن يكون 1,113.00 أو اقل",
+		},
+		{
+			ns:       "Test.MinMultiple",
+			expected: "يجب أن يحتوي MinMultiple على 7 عناصر على الأقل",
+		},
+		{
+			ns:       "Test.LenString",
+			expected: "يجب أن يكون طول LenString مساويا ل 1 حرف",
+		},
+		{
+			ns:       "Test.LenNumber",
+			expected: "يجب أن يكون LenNumber مساويا ل 1,113.00",
+		},
+		{
+			ns:       "Test.LenMultiple",
+			expected: "يجب أن يحتوي LenMultiple على 7 عناصر",
+		},
+		{
+			ns:       "Test.RequiredString",
+			expected: "حقل RequiredString مطلوب",
+		},
+		{
+			ns:       "Test.RequiredNumber",
+			expected: "حقل RequiredNumber مطلوب",
+		},
+		{
+			ns:       "Test.RequiredMultiple",
+			expected: "حقل RequiredMultiple مطلوب",
+		},
+		{
+			ns:       "Test.StrPtrMinLen",
+			expected: "StrPtrMinLen يجب أن يكون 10 أحرف أو اقل",
+		},
+		{
+			ns:       "Test.StrPtrMaxLen",
+			expected: "يجب أن يكون طول StrPtrMaxLen بحد أقصى 1 حرف",
+		},
+		{
+			ns:       "Test.StrPtrLen",
+			expected: "يجب أن يكون طول StrPtrLen مساويا ل 2 أحرف",
+		},
+		{
+			ns:       "Test.StrPtrLt",
+			expected: "يجب أن يكون طول StrPtrLt أقل من 1 حرف",
+		},
+		{
+			ns:       "Test.StrPtrLte",
+			expected: "يجب أن يكون طول StrPtrLte كحد أقصى 1 حرف",
+		},
+		{
+			ns:       "Test.StrPtrGt",
+			expected: "يجب أن يكون طول StrPtrGt أكبر من 10 أحرف",
+		},
+		{
+			ns:       "Test.StrPtrGte",
+			expected: "يجب أن يكون طول StrPtrGte على الأقل 10 أحرف",
+		},
+		{
+			ns:       "Test.OneOfString",
+			expected: "يجب أن يكون OneOfString واحدا من [red green]",
+		},
+		{
+			ns:       "Test.OneOfInt",
+			expected: "يجب أن يكون OneOfInt واحدا من [5 63]",
+		},
+		{
+			ns:       "Test.UniqueSlice",
+			expected: "يجب أن يحتوي UniqueSlice على قيم فريدة",
+		},
+		{
+			ns:       "Test.UniqueArray",
+			expected: "يجب أن يحتوي UniqueArray على قيم فريدة",
+		},
+		{
+			ns:       "Test.UniqueMap",
+			expected: "يجب أن يحتوي UniqueMap على قيم فريدة",
+		},
+		{
+			ns:       "Test.JSONString",
+			expected: "يجب أن يكون JSONString نص json صالح",
+		},
+		{
+			ns:       "Test.JWTString",
+			expected: "يجب أن يكون JWTString نص jwt صالح",
+		},
+		{
+			ns:       "Test.LowercaseString",
+			expected: "يجب أن يكون LowercaseString نص حروف صغيرة",
+		},
+		{
+			ns:       "Test.UppercaseString",
+			expected: "يجب أن يكون UppercaseString نص حروف كبيرة",
+		},
+		{
+			ns:       "Test.Datetime",
+			expected: "لا يتطابق Datetime مع تنسيق 2006-01-02",
+		},
+		{
+			ns:       "Test.PostCode",
+			expected: "لا يتطابق PostCode مع تنسيق الرمز البريدي للبلد SG",
+		},
+		{
+			ns:       "Test.PostCodeByField",
+			expected: "لا يتطابق PostCodeByField مع تنسيق الرمز البريدي للبلد في حقل PostCodeCountry",
+		},
+	}
+
+	for _, tt := range tests {
+
+		var fe validator.FieldError
+
+		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/translations/en/en_test.go b/translations/en/en_test.go
index 146c475..9cb6deb 100644
--- a/translations/en/en_test.go
+++ b/translations/en/en_test.go
@@ -27,6 +27,7 @@ func TestTranslations(t *testing.T) {
 		GteCSFieldString string
 		LtCSFieldString  string
 		LteCSFieldString string
+		RequiredIf       string
 	}
 
 	type Test struct {
@@ -34,6 +35,7 @@ func TestTranslations(t *testing.T) {
 		RequiredString    string            `validate:"required"`
 		RequiredNumber    int               `validate:"required"`
 		RequiredMultiple  []string          `validate:"required"`
+		RequiredIf        string            `validate:"required_if=Inner.RequiredIf abcd"`
 		LenString         string            `validate:"len=1"`
 		LenNumber         float64           `validate:"len=1113.00"`
 		LenMultiple       []string          `validate:"len=7"`
@@ -149,6 +151,7 @@ func TestTranslations(t *testing.T) {
 		PostCode          string            `validate:"postcode_iso3166_alpha2=SG"`
 		PostCodeCountry   string
 		PostCodeByField   string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
+		BooleanString     string `validate:"boolean"`
 	}
 
 	var test Test
@@ -201,6 +204,9 @@ func TestTranslations(t *testing.T) {
 	test.UniqueSlice = []string{"1234", "1234"}
 	test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
 	test.Datetime = "2008-Feb-01"
+	test.BooleanString = "A"
+
+	test.Inner.RequiredIf = "abcd"
 
 	err = validate.Struct(test)
 	NotEqual(t, err, nil)
@@ -592,6 +598,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.RequiredString",
 			expected: "RequiredString is a required field",
 		},
+		{
+			ns:       "Test.RequiredIf",
+			expected: "RequiredIf is a required field",
+		},
 		{
 			ns:       "Test.RequiredNumber",
 			expected: "RequiredNumber is a required field",
@@ -676,6 +686,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.PostCodeByField",
 			expected: "PostCodeByField does not match postcode format of country in PostCodeCountry field",
 		},
+		{
+			ns:       "Test.BooleanString",
+			expected: "BooleanString must be a valid boolean value",
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/translations/it/it_test.go b/translations/it/it_test.go
new file mode 100644
index 0000000..98d2ab5
--- /dev/null
+++ b/translations/it/it_test.go
@@ -0,0 +1,725 @@
+package it
+
+import (
+	"testing"
+	"time"
+
+	. "github.com/go-playground/assert/v2"
+	italian "github.com/go-playground/locales/it"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+)
+
+func TestTranslations(t *testing.T) {
+	ita := italian.New()
+	uni := ut.New(ita, ita)
+	trans, _ := uni.GetTranslator("it")
+
+	validate := validator.New()
+
+	err := RegisterDefaultTranslations(validate, trans)
+	Equal(t, err, nil)
+
+	type Inner struct {
+		EqCSFieldString  string
+		NeCSFieldString  string
+		GtCSFieldString  string
+		GteCSFieldString string
+		LtCSFieldString  string
+		LteCSFieldString 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=purpose"`
+		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"`
+		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=red green"`
+		OneOfInt            int               `validate:"oneof=5 63"`
+		UniqueSlice         []string          `validate:"unique"`
+		UniqueArray         [3]string         `validate:"unique"`
+		UniqueMap           map[string]string `validate:"unique"`
+		BooleanString       string            `validate:"boolean"`
+		JSONString          string            `validate:"json"`
+		JWTString           string            `validate:"jwt"`
+		LowercaseString     string            `validate:"lowercase"`
+		UppercaseString     string            `validate:"uppercase"`
+		StartsWithString    string            `validate:"startswith=foo"`
+		StartsNotWithString string            `validate:"startsnotwith=foo"`
+		EndsWithString      string            `validate:"endswith=foo"`
+		EndsNotWithString   string            `validate:"endsnotwith=foo"`
+		Datetime            string            `validate:"datetime=2006-01-02"`
+		PostCode            string            `validate:"postcode_iso3166_alpha2=SG"`
+		PostCodeCountry     string
+		PostCodeByField     string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
+	}
+
+	var test Test
+
+	test.Inner.EqCSFieldString = "1234"
+	test.Inner.GtCSFieldString = "1234"
+	test.Inner.GteCSFieldString = "1234"
+
+	test.MaxString = "1234"
+	test.MaxNumber = 2000
+	test.MaxMultiple = make([]string, 9)
+
+	test.LtString = "1234"
+	test.LtNumber = 6
+	test.LtMultiple = make([]string, 3)
+	test.LtTime = time.Now().Add(time.Hour * 24)
+
+	test.LteString = "1234"
+	test.LteNumber = 6
+	test.LteMultiple = make([]string, 3)
+	test.LteTime = time.Now().Add(time.Hour * 24)
+
+	test.LtFieldString = "12345"
+	test.LteFieldString = "12345"
+
+	test.LtCSFieldString = "1234"
+	test.LteCSFieldString = "1234"
+
+	test.AlphaString = "abc3"
+	test.AlphanumString = "abc3!"
+	test.NumericString = "12E.00"
+	test.NumberString = "12E"
+
+	test.Excludes = "this is some test text"
+	test.ExcludesAll = "This is Great!"
+	test.ExcludesRune = "Love it ☻"
+
+	test.ASCII = "ｶﾀｶﾅ"
+	test.PrintableASCII = "ｶﾀｶﾅ"
+
+	test.MultiByte = "1234feerf"
+
+	test.LowercaseString = "ABCDEFG"
+	test.UppercaseString = "abcdefg"
+
+	test.StartsWithString = "hello"
+	test.StartsNotWithString = "foo-hello"
+	test.EndsWithString = "hello"
+	test.EndsNotWithString = "hello-foo"
+
+	s := "toolong"
+	test.StrPtrMaxLen = &s
+	test.StrPtrLen = &s
+
+	test.UniqueSlice = []string{"1234", "1234"}
+	test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
+	test.Datetime = "2008-Feb-01"
+
+	err = validate.Struct(test)
+	NotEqual(t, err, nil)
+
+	errs, ok := err.(validator.ValidationErrors)
+	Equal(t, ok, true)
+
+	tests := []struct {
+		ns       string
+		expected string
+	}{
+		{
+			ns:       "Test.IsColor",
+			expected: "IsColor deve essere un colore valido",
+		},
+		{
+			ns:       "Test.MAC",
+			expected: "MAC deve contenere un indirizzo MAC valido",
+		},
+		{
+			ns:       "Test.IPAddr",
+			expected: "IPAddr deve essere un indirizzo IP risolvibile",
+		},
+		{
+			ns:       "Test.IPAddrv4",
+			expected: "IPAddrv4 deve essere un indirizzo IPv4 risolvibile",
+		},
+		{
+			ns:       "Test.IPAddrv6",
+			expected: "IPAddrv6 deve essere un indirizzo IPv6 risolvibile",
+		},
+		{
+			ns:       "Test.UDPAddr",
+			expected: "UDPAddr deve essere un indirizzo UDP valido",
+		},
+		{
+			ns:       "Test.UDPAddrv4",
+			expected: "UDPAddrv4 deve essere un indirizzo IPv4 UDP valido",
+		},
+		{
+			ns:       "Test.UDPAddrv6",
+			expected: "UDPAddrv6 deve essere un indirizzo IPv6 UDP valido",
+		},
+		{
+			ns:       "Test.TCPAddr",
+			expected: "TCPAddr deve essere un indirizzo TCP valido",
+		},
+		{
+			ns:       "Test.TCPAddrv4",
+			expected: "TCPAddrv4 deve essere un indirizzo IPv4 TCP valido",
+		},
+		{
+			ns:       "Test.TCPAddrv6",
+			expected: "TCPAddrv6 deve essere un indirizzo IPv6 TCP valido",
+		},
+		{
+			ns:       "Test.CIDR",
+			expected: "CIDR deve contenere una notazione CIDR valida",
+		},
+		{
+			ns:       "Test.CIDRv4",
+			expected: "CIDRv4 deve contenere una notazione CIDR per un indirizzo IPv4 valida",
+		},
+		{
+			ns:       "Test.CIDRv6",
+			expected: "CIDRv6 deve contenere una notazione CIDR per un indirizzo IPv6 valida",
+		},
+		{
+			ns:       "Test.SSN",
+			expected: "SSN deve essere un numero SSN valido",
+		},
+		{
+			ns:       "Test.IP",
+			expected: "IP deve essere un indirizzo IP valido",
+		},
+		{
+			ns:       "Test.IPv4",
+			expected: "IPv4 deve essere un indirizzo IPv4 valido",
+		},
+		{
+			ns:       "Test.IPv6",
+			expected: "IPv6 deve essere un indirizzo IPv6 valido",
+		},
+		{
+			ns:       "Test.DataURI",
+			expected: "DataURI deve contenere un Data URI valido",
+		},
+		{
+			ns:       "Test.Latitude",
+			expected: "Latitude deve contenere una latitudine valida",
+		},
+		{
+			ns:       "Test.Longitude",
+			expected: "Longitude deve contenere una longitudine valida",
+		},
+		{
+			ns:       "Test.MultiByte",
+			expected: "MultiByte deve contenere caratteri multibyte",
+		},
+		{
+			ns:       "Test.ASCII",
+			expected: "ASCII deve contenere solo caratteri ascii",
+		},
+		{
+			ns:       "Test.PrintableASCII",
+			expected: "PrintableASCII deve contenere solo caratteri ascii stampabili",
+		},
+		{
+			ns:       "Test.UUID",
+			expected: "UUID deve essere un UUID valido",
+		},
+		{
+			ns:       "Test.UUID3",
+			expected: "UUID3 deve essere un UUID versione 3 valido",
+		},
+		{
+			ns:       "Test.UUID4",
+			expected: "UUID4 deve essere un UUID versione 4 valido",
+		},
+		{
+			ns:       "Test.UUID5",
+			expected: "UUID5 deve essere un UUID versione 5 valido",
+		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID deve essere un ULID valido",
+		},
+		{
+			ns:       "Test.ISBN",
+			expected: "ISBN deve essere un numero ISBN valido",
+		},
+		{
+			ns:       "Test.ISBN10",
+			expected: "ISBN10 deve essere un numero ISBN-10 valido",
+		},
+		{
+			ns:       "Test.ISBN13",
+			expected: "ISBN13 deve essere un numero ISBN-13 valido",
+		},
+		{
+			ns:       "Test.Excludes",
+			expected: "Excludes non deve contenere il testo 'text'",
+		},
+		{
+			ns:       "Test.ExcludesAll",
+			expected: "ExcludesAll non deve contenere alcuno dei seguenti caratteri '!@#$'",
+		},
+		{
+			ns:       "Test.ExcludesRune",
+			expected: "ExcludesRune non deve contenere '☻'",
+		},
+		{
+			ns:       "Test.ContainsAny",
+			expected: "ContainsAny deve contenere almeno uno dei seguenti caratteri '!@#$'",
+		},
+		{
+			ns:       "Test.Contains",
+			expected: "Contains deve contenere il testo 'purpose'",
+		},
+		{
+			ns:       "Test.Base64",
+			expected: "Base64 deve essere una stringa Base64 valida",
+		},
+		{
+			ns:       "Test.Email",
+			expected: "Email deve essere un indirizzo email valido",
+		},
+		{
+			ns:       "Test.URL",
+			expected: "URL deve essere un URL valido",
+		},
+		{
+			ns:       "Test.URI",
+			expected: "URI deve essere un URI valido",
+		},
+		{
+			ns:       "Test.RGBColorString",
+			expected: "RGBColorString deve essere un colore RGB valido",
+		},
+		{
+			ns:       "Test.RGBAColorString",
+			expected: "RGBAColorString deve essere un colore RGBA valido",
+		},
+		{
+			ns:       "Test.HSLColorString",
+			expected: "HSLColorString deve essere un colore HSL valido",
+		},
+		{
+			ns:       "Test.HSLAColorString",
+			expected: "HSLAColorString deve essere un colore HSLA valido",
+		},
+		{
+			ns:       "Test.HexadecimalString",
+			expected: "HexadecimalString deve essere un esadecimale valido",
+		},
+		{
+			ns:       "Test.HexColorString",
+			expected: "HexColorString deve essere un colore HEX valido",
+		},
+		{
+			ns:       "Test.NumberString",
+			expected: "NumberString deve essere un numero valido",
+		},
+		{
+			ns:       "Test.NumericString",
+			expected: "NumericString deve essere un valore numerico valido",
+		},
+		{
+			ns:       "Test.AlphanumString",
+			expected: "AlphanumString può contenere solo caratteri alfanumerici",
+		},
+		{
+			ns:       "Test.AlphaString",
+			expected: "AlphaString può contenere solo caratteri alfabetici",
+		},
+		{
+			ns:       "Test.LtFieldString",
+			expected: "LtFieldString deve essere minore di MaxString",
+		},
+		{
+			ns:       "Test.LteFieldString",
+			expected: "LteFieldString deve essere minore o uguale a MaxString",
+		},
+		{
+			ns:       "Test.GtFieldString",
+			expected: "GtFieldString deve essere maggiore di MaxString",
+		},
+		{
+			ns:       "Test.GteFieldString",
+			expected: "GteFieldString deve essere maggiore o uguale a MaxString",
+		},
+		{
+			ns:       "Test.NeFieldString",
+			expected: "NeFieldString deve essere diverso da EqFieldString",
+		},
+		{
+			ns:       "Test.LtCSFieldString",
+			expected: "LtCSFieldString deve essere minore di Inner.LtCSFieldString",
+		},
+		{
+			ns:       "Test.LteCSFieldString",
+			expected: "LteCSFieldString deve essere minore o uguale a Inner.LteCSFieldString",
+		},
+		{
+			ns:       "Test.GtCSFieldString",
+			expected: "GtCSFieldString deve essere maggiore di Inner.GtCSFieldString",
+		},
+		{
+			ns:       "Test.GteCSFieldString",
+			expected: "GteCSFieldString deve essere maggiore o uguale a Inner.GteCSFieldString",
+		},
+		{
+			ns:       "Test.NeCSFieldString",
+			expected: "NeCSFieldString deve essere diverso da Inner.NeCSFieldString",
+		},
+		{
+			ns:       "Test.EqCSFieldString",
+			expected: "EqCSFieldString deve essere uguale a Inner.EqCSFieldString",
+		},
+		{
+			ns:       "Test.EqFieldString",
+			expected: "EqFieldString deve essere uguale a MaxString",
+		},
+		{
+			ns:       "Test.GteString",
+			expected: "GteString deve essere lungo almeno 3 caratteri",
+		},
+		{
+			ns:       "Test.GteNumber",
+			expected: "GteNumber deve essere maggiore o uguale a 5,56",
+		},
+		{
+			ns:       "Test.GteMultiple",
+			expected: "GteMultiple deve contenere almeno 2 elementi",
+		},
+		{
+			ns:       "Test.GteTime",
+			expected: "GteTime deve essere uguale o successivo alla Data/Ora corrente",
+		},
+		{
+			ns:       "Test.GtString",
+			expected: "GtString deve essere lungo più di 3 caratteri",
+		},
+		{
+			ns:       "Test.GtNumber",
+			expected: "GtNumber deve essere maggiore di 5,56",
+		},
+		{
+			ns:       "Test.GtMultiple",
+			expected: "GtMultiple deve contenere più di 2 elementi",
+		},
+		{
+			ns:       "Test.GtTime",
+			expected: "GtTime deve essere successivo alla Data/Ora corrente",
+		},
+		{
+			ns:       "Test.LteString",
+			expected: "LteString deve essere lungo al massimo 3 caratteri",
+		},
+		{
+			ns:       "Test.LteNumber",
+			expected: "LteNumber deve essere minore o uguale a 5,56",
+		},
+		{
+			ns:       "Test.LteMultiple",
+			expected: "LteMultiple deve contenere al massimo 2 elementi",
+		},
+		{
+			ns:       "Test.LteTime",
+			expected: "LteTime deve essere uguale o precedente alla Data/Ora corrente",
+		},
+		{
+			ns:       "Test.LtString",
+			expected: "LtString deve essere lungo meno di 3 caratteri",
+		},
+		{
+			ns:       "Test.LtNumber",
+			expected: "LtNumber deve essere minore di 5,56",
+		},
+		{
+			ns:       "Test.LtMultiple",
+			expected: "LtMultiple deve contenere meno di 2 elementi",
+		},
+		{
+			ns:       "Test.LtTime",
+			expected: "LtTime deve essere precedente alla Data/Ora corrente",
+		},
+		{
+			ns:       "Test.NeString",
+			expected: "NeString deve essere diverso da ",
+		},
+		{
+			ns:       "Test.NeNumber",
+			expected: "NeNumber deve essere diverso da 0.00",
+		},
+		{
+			ns:       "Test.NeMultiple",
+			expected: "NeMultiple deve essere diverso da 0",
+		},
+		{
+			ns:       "Test.EqString",
+			expected: "EqString non è uguale a 3",
+		},
+		{
+			ns:       "Test.EqNumber",
+			expected: "EqNumber non è uguale a 2.33",
+		},
+		{
+			ns:       "Test.EqMultiple",
+			expected: "EqMultiple non è uguale a 7",
+		},
+		{
+			ns:       "Test.MaxString",
+			expected: "MaxString deve essere lungo al massimo 3 caratteri",
+		},
+		{
+			ns:       "Test.MaxNumber",
+			expected: "MaxNumber deve essere minore o uguale a 1.113,00",
+		},
+		{
+			ns:       "Test.MaxMultiple",
+			expected: "MaxMultiple deve contenere al massimo 7 elementi",
+		},
+		{
+			ns:       "Test.MinString",
+			expected: "MinString deve essere lungo almeno 1 carattere",
+		},
+		{
+			ns:       "Test.MinNumber",
+			expected: "MinNumber deve essere maggiore o uguale a 1.113,00",
+		},
+		{
+			ns:       "Test.MinMultiple",
+			expected: "MinMultiple deve contenere almeno 7 elementi",
+		},
+		{
+			ns:       "Test.LenString",
+			expected: "LenString deve essere lungo 1 carattere",
+		},
+		{
+			ns:       "Test.LenNumber",
+			expected: "LenNumber deve essere uguale a 1.113,00",
+		},
+		{
+			ns:       "Test.LenMultiple",
+			expected: "LenMultiple deve contenere 7 elementi",
+		},
+		{
+			ns:       "Test.RequiredString",
+			expected: "RequiredString è un campo obbligatorio",
+		},
+		{
+			ns:       "Test.RequiredNumber",
+			expected: "RequiredNumber è un campo obbligatorio",
+		},
+		{
+			ns:       "Test.RequiredMultiple",
+			expected: "RequiredMultiple è un campo obbligatorio",
+		},
+		{
+			ns:       "Test.StrPtrMinLen",
+			expected: "StrPtrMinLen deve essere lungo almeno 10 caratteri",
+		},
+		{
+			ns:       "Test.StrPtrMaxLen",
+			expected: "StrPtrMaxLen deve essere lungo al massimo 1 carattere",
+		},
+		{
+			ns:       "Test.StrPtrLen",
+			expected: "StrPtrLen deve essere lungo 2 caratteri",
+		},
+		{
+			ns:       "Test.StrPtrLt",
+			expected: "StrPtrLt deve essere lungo meno di 1 carattere",
+		},
+		{
+			ns:       "Test.StrPtrLte",
+			expected: "StrPtrLte deve essere lungo al massimo 1 carattere",
+		},
+		{
+			ns:       "Test.StrPtrGt",
+			expected: "StrPtrGt deve essere lungo più di 10 caratteri",
+		},
+		{
+			ns:       "Test.StrPtrGte",
+			expected: "StrPtrGte deve essere lungo almeno 10 caratteri",
+		},
+		{
+			ns:       "Test.OneOfString",
+			expected: "OneOfString deve essere uno di [red green]",
+		},
+		{
+			ns:       "Test.OneOfInt",
+			expected: "OneOfInt deve essere uno di [5 63]",
+		},
+		{
+			ns:       "Test.UniqueSlice",
+			expected: "UniqueSlice deve contenere valori unici",
+		},
+		{
+			ns:       "Test.UniqueArray",
+			expected: "UniqueArray deve contenere valori unici",
+		},
+		{
+			ns:       "Test.UniqueMap",
+			expected: "UniqueMap deve contenere valori unici",
+		},
+		{
+			ns:       "Test.BooleanString",
+			expected: "BooleanString deve rappresentare un valore booleano",
+		},
+		{
+			ns:       "Test.JSONString",
+			expected: "JSONString deve essere una stringa json valida",
+		},
+		{
+			ns:       "Test.JWTString",
+			expected: "JWTString deve essere una stringa jwt valida",
+		},
+		{
+			ns:       "Test.LowercaseString",
+			expected: "LowercaseString deve essere una stringa minuscola",
+		},
+		{
+			ns:       "Test.UppercaseString",
+			expected: "UppercaseString deve essere una stringa maiuscola",
+		},
+		{
+			ns:       "Test.StartsWithString",
+			expected: "StartsWithString deve iniziare con foo",
+		},
+		{
+			ns:       "Test.StartsNotWithString",
+			expected: "StartsNotWithString non deve iniziare con foo",
+		},
+		{
+			ns:       "Test.EndsWithString",
+			expected: "EndsWithString deve terminare con foo",
+		},
+		{
+			ns:       "Test.EndsNotWithString",
+			expected: "EndsNotWithString non deve terminare con foo",
+		},
+		{
+			ns:       "Test.Datetime",
+			expected: "Datetime non corrisponde al formato 2006-01-02",
+		},
+		{
+			ns:       "Test.PostCode",
+			expected: "PostCode non corrisponde al formato del codice postale dello stato SG",
+		},
+		{
+			ns:       "Test.PostCodeByField",
+			expected: "PostCodeByField non corrisponde al formato del codice postale dello stato nel campo PostCodeCountry",
+		},
+	}
+
+	for _, tt := range tests {
+
+		var fe validator.FieldError
+
+		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/translations/ja/ja_test.go b/translations/ja/ja_test.go
index 393bcb3..7950251 100644
--- a/translations/ja/ja_test.go
+++ b/translations/ja/ja_test.go
@@ -453,7 +453,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.GteNumber",
-			expected: "GteNumberは5.56かより大きくなければなりません",
+			expected: "GteNumberは5.56より大きくなければなりません",
 		},
 		{
 			ns:       "Test.GteMultiple",
@@ -485,7 +485,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.LteNumber",
-			expected: "LteNumberは5.56かより小さくなければなりません",
+			expected: "LteNumberは5.56より小さくなければなりません",
 		},
 		{
 			ns:       "Test.LteMultiple",
@@ -541,7 +541,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.MaxNumber",
-			expected: "MaxNumberは1,113.00かより小さくなければなりません",
+			expected: "MaxNumberは1,113.00より小さくなければなりません",
 		},
 		{
 			ns:       "Test.MaxMultiple",
@@ -553,7 +553,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.MinNumber",
-			expected: "MinNumberは1,113.00かより大きくなければなりません",
+			expected: "MinNumberは1,113.00より大きくなければなりません",
 		},
 		{
 			ns:       "Test.MinMultiple",
diff --git a/translations/pt_BR/pt_BR_test.go b/translations/pt_BR/pt_BR_test.go
index c8a6482..426f246 100644
--- a/translations/pt_BR/pt_BR_test.go
+++ b/translations/pt_BR/pt_BR_test.go
@@ -139,6 +139,7 @@ func TestTranslations(t *testing.T) {
 		StrPtrGte         *string   `validate:"gte=10"`
 		OneOfString       string    `validate:"oneof=red green"`
 		OneOfInt          int       `validate:"oneof=5 63"`
+		BooleanString     string    `validate:"boolean"`
 	}
 
 	var test Test
@@ -171,6 +172,7 @@ func TestTranslations(t *testing.T) {
 	test.AlphanumString = "abc3!"
 	test.NumericString = "12E.00"
 	test.NumberString = "12E"
+	test.BooleanString = "A"
 
 	test.Excludes = "este é um texto de teste"
 	test.ExcludesAll = "Isso é Ótimo!"
@@ -619,6 +621,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.OneOfInt",
 			expected: "OneOfInt deve ser um de [5 63]",
 		},
+		{
+			ns:       "Test.BooleanString",
+			expected: "BooleanString deve ser um valor booleano válido",
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/translations/vi/vi_test.go b/translations/vi/vi_test.go
new file mode 100644
index 0000000..6e12866
--- /dev/null
+++ b/translations/vi/vi_test.go
@@ -0,0 +1,690 @@
+package vi
+
+import (
+	"testing"
+	"time"
+
+	. "github.com/go-playground/assert/v2"
+	vietnamese "github.com/go-playground/locales/vi"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+)
+
+func TestTranslations(t *testing.T) {
+	vie := vietnamese.New()
+	uni := ut.New(vie, vie)
+	trans, _ := uni.GetTranslator("vi")
+
+	validate := validator.New()
+
+	err := RegisterDefaultTranslations(validate, trans)
+	Equal(t, err, nil)
+
+	type Inner struct {
+		EqCSFieldString  string
+		NeCSFieldString  string
+		GtCSFieldString  string
+		GteCSFieldString string
+		LtCSFieldString  string
+		LteCSFieldString 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=purpose"`
+		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"`
+		UUID              string            `validate:"uuid"`
+		UUID3             string            `validate:"uuid3"`
+		UUID4             string            `validate:"uuid4"`
+		UUID5             string            `validate:"uuid5"`
+		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=red green"`
+		OneOfInt          int               `validate:"oneof=5 63"`
+		UniqueSlice       []string          `validate:"unique"`
+		UniqueArray       [3]string         `validate:"unique"`
+		UniqueMap         map[string]string `validate:"unique"`
+		JSONString        string            `validate:"json"`
+		JWTString         string            `validate:"jwt"`
+		LowercaseString   string            `validate:"lowercase"`
+		UppercaseString   string            `validate:"uppercase"`
+		Datetime          string            `validate:"datetime=2006-01-02"`
+		PostCode          string            `validate:"postcode_iso3166_alpha2=SG"`
+		PostCodeCountry   string
+		PostCodeByField   string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
+	}
+
+	var test Test
+
+	test.Inner.EqCSFieldString = "1234"
+	test.Inner.GtCSFieldString = "1234"
+	test.Inner.GteCSFieldString = "1234"
+
+	test.MaxString = "1234"
+	test.MaxNumber = 2000
+	test.MaxMultiple = make([]string, 9)
+
+	test.LtString = "1234"
+	test.LtNumber = 6
+	test.LtMultiple = make([]string, 3)
+	test.LtTime = time.Now().Add(time.Hour * 24)
+
+	test.LteString = "1234"
+	test.LteNumber = 6
+	test.LteMultiple = make([]string, 3)
+	test.LteTime = time.Now().Add(time.Hour * 24)
+
+	test.LtFieldString = "12345"
+	test.LteFieldString = "12345"
+
+	test.LtCSFieldString = "1234"
+	test.LteCSFieldString = "1234"
+
+	test.AlphaString = "abc3"
+	test.AlphanumString = "abc3!"
+	test.NumericString = "12E.00"
+	test.NumberString = "12E"
+
+	test.Excludes = "this is some test text"
+	test.ExcludesAll = "This is Great!"
+	test.ExcludesRune = "Love it ☻"
+
+	test.ASCII = "ｶﾀｶﾅ"
+	test.PrintableASCII = "ｶﾀｶﾅ"
+
+	test.MultiByte = "1234feerf"
+
+	test.LowercaseString = "ABCDEFG"
+	test.UppercaseString = "abcdefg"
+
+	s := "toolong"
+	test.StrPtrMaxLen = &s
+	test.StrPtrLen = &s
+
+	test.UniqueSlice = []string{"1234", "1234"}
+	test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
+	test.Datetime = "2008-Feb-01"
+
+	err = validate.Struct(test)
+	NotEqual(t, err, nil)
+
+	errs, ok := err.(validator.ValidationErrors)
+	Equal(t, ok, true)
+
+	tests := []struct {
+		ns       string
+		expected string
+	}{
+		{
+			ns:       "Test.IsColor",
+			expected: "IsColor phải là màu sắc hợp lệ",
+		},
+		{
+			ns:       "Test.MAC",
+			expected: "MAC chỉ được chứa địa chỉ MAC",
+		},
+		{
+			ns:       "Test.IPAddr",
+			expected: "IPAddr phải là địa chỉ IP có thể phân giải",
+		},
+		{
+			ns:       "Test.IPAddrv4",
+			expected: "IPAddrv4 phải là địa chỉ IPv4 có thể phân giải",
+		},
+		{
+			ns:       "Test.IPAddrv6",
+			expected: "IPAddrv6 phải là địa chỉ IPv6 có thể phân giải",
+		},
+		{
+			ns:       "Test.UDPAddr",
+			expected: "UDPAddr phải là địa chỉ UDP",
+		},
+		{
+			ns:       "Test.UDPAddrv4",
+			expected: "UDPAddrv4 phải là địa chỉ IPv4 UDP",
+		},
+		{
+			ns:       "Test.UDPAddrv6",
+			expected: "UDPAddrv6 phải là địa chỉ IPv6 UDP",
+		},
+		{
+			ns:       "Test.TCPAddr",
+			expected: "TCPAddr phải là địa chỉ TCP",
+		},
+		{
+			ns:       "Test.TCPAddrv4",
+			expected: "TCPAddrv4 phải là địa chỉ IPv4 TCP",
+		},
+		{
+			ns:       "Test.TCPAddrv6",
+			expected: "TCPAddrv6 phải là địa chỉ IPv6 TCP",
+		},
+		{
+			ns:       "Test.CIDR",
+			expected: "CIDR chỉ được chứa CIDR notation",
+		},
+		{
+			ns:       "Test.CIDRv4",
+			expected: "CIDRv4 chỉ được chứa CIDR notation của một địa chỉ IPv4",
+		},
+		{
+			ns:       "Test.CIDRv6",
+			expected: "CIDRv6 chỉ được chứa CIDR notation của một địa chỉ IPv6",
+		},
+		{
+			ns:       "Test.SSN",
+			expected: "SSN phải là SSN number",
+		},
+		{
+			ns:       "Test.IP",
+			expected: "IP phải là địa chỉ IP",
+		},
+		{
+			ns:       "Test.IPv4",
+			expected: "IPv4 phải là địa chỉ IPv4",
+		},
+		{
+			ns:       "Test.IPv6",
+			expected: "IPv6 phải là địa chỉ IPv6",
+		},
+		{
+			ns:       "Test.DataURI",
+			expected: "DataURI chỉ được chứa Data URI",
+		},
+		{
+			ns:       "Test.Latitude",
+			expected: "Latitude chỉ được chứa latitude (vỹ độ)",
+		},
+		{
+			ns:       "Test.Longitude",
+			expected: "Longitude chỉ được chứa longitude (kinh độ)",
+		},
+		{
+			ns:       "Test.MultiByte",
+			expected: "MultiByte chỉ được chứa ký tự multibyte",
+		},
+		{
+			ns:       "Test.ASCII",
+			expected: "ASCII chỉ được chứa ký tự ASCII",
+		},
+		{
+			ns:       "Test.PrintableASCII",
+			expected: "PrintableASCII chỉ được chứa ký tự ASCII có thể in ấn",
+		},
+		{
+			ns:       "Test.UUID",
+			expected: "UUID phải là giá trị UUID",
+		},
+		{
+			ns:       "Test.UUID3",
+			expected: "UUID3 phải là giá trị UUID phiên bản 3",
+		},
+		{
+			ns:       "Test.UUID4",
+			expected: "UUID4 phải là giá trị UUID phiên bản 4",
+		},
+		{
+			ns:       "Test.UUID5",
+			expected: "UUID5 phải là giá trị UUID phiên bản 5",
+		},
+		{
+			ns:       "Test.ISBN",
+			expected: "ISBN phải là số ISBN",
+		},
+		{
+			ns:       "Test.ISBN10",
+			expected: "ISBN10 phải là số ISBN-10",
+		},
+		{
+			ns:       "Test.ISBN13",
+			expected: "ISBN13 phải là số ISBN-13",
+		},
+		{
+			ns:       "Test.Excludes",
+			expected: "Excludes không được chứa chuỗi 'text'",
+		},
+		{
+			ns:       "Test.ExcludesAll",
+			expected: "ExcludesAll không được chứa bất kỳ ký tự nào trong nhóm ký tự '!@#$'",
+		},
+		{
+			ns:       "Test.ExcludesRune",
+			expected: "ExcludesRune không được chứa '☻'",
+		},
+		{
+			ns:       "Test.ContainsAny",
+			expected: "ContainsAny phải chứa ít nhất 1 trong cách ký tự sau '!@#$'",
+		},
+		{
+			ns:       "Test.Contains",
+			expected: "Contains phải chứa chuỗi 'purpose'",
+		},
+		{
+			ns:       "Test.Base64",
+			expected: "Base64 phải là giá trị chuỗi Base64",
+		},
+		{
+			ns:       "Test.Email",
+			expected: "Email phải là giá trị email address",
+		},
+		{
+			ns:       "Test.URL",
+			expected: "URL phải là giá trị URL",
+		},
+		{
+			ns:       "Test.URI",
+			expected: "URI phải là giá trị URI",
+		},
+		{
+			ns:       "Test.RGBColorString",
+			expected: "RGBColorString phải là giá trị RGB color",
+		},
+		{
+			ns:       "Test.RGBAColorString",
+			expected: "RGBAColorString phải là giá trị RGBA color",
+		},
+		{
+			ns:       "Test.HSLColorString",
+			expected: "HSLColorString phải là giá trị HSL color",
+		},
+		{
+			ns:       "Test.HSLAColorString",
+			expected: "HSLAColorString phải là giá trị HSLA color",
+		},
+		{
+			ns:       "Test.HexadecimalString",
+			expected: "HexadecimalString phải là giá trị hexadecimal",
+		},
+		{
+			ns:       "Test.HexColorString",
+			expected: "HexColorString phải là giá trị HEX color",
+		},
+		{
+			ns:       "Test.NumberString",
+			expected: "NumberString chỉ được chứa giá trị số",
+		},
+		{
+			ns:       "Test.NumericString",
+			expected: "NumericString chỉ được chứa giá trị số hoặc số dưới dạng chữ",
+		},
+		{
+			ns:       "Test.AlphanumString",
+			expected: "AlphanumString chỉ được chứa ký tự dạng alphanumeric",
+		},
+		{
+			ns:       "Test.AlphaString",
+			expected: "AlphaString chỉ được chứa ký tự dạng alphabetic",
+		},
+		{
+			ns:       "Test.LtFieldString",
+			expected: "LtFieldString chỉ được nhỏ hơn MaxString",
+		},
+		{
+			ns:       "Test.LteFieldString",
+			expected: "LteFieldString chỉ được nhỏ hơn hoặc bằng MaxString",
+		},
+		{
+			ns:       "Test.GtFieldString",
+			expected: "GtFieldString phải lớn hơn MaxString",
+		},
+		{
+			ns:       "Test.GteFieldString",
+			expected: "GteFieldString phải lớn hơn hoặc bằng MaxString",
+		},
+		{
+			ns:       "Test.NeFieldString",
+			expected: "NeFieldString không được phép bằng EqFieldString",
+		},
+		{
+			ns:       "Test.LtCSFieldString",
+			expected: "LtCSFieldString chỉ được nhỏ hơn Inner.LtCSFieldString",
+		},
+		{
+			ns:       "Test.LteCSFieldString",
+			expected: "LteCSFieldString chỉ được nhỏ hơn hoặc bằng Inner.LteCSFieldString",
+		},
+		{
+			ns:       "Test.GtCSFieldString",
+			expected: "GtCSFieldString phải lớn hơn Inner.GtCSFieldString",
+		},
+		{
+			ns:       "Test.GteCSFieldString",
+			expected: "GteCSFieldString phải lớn hơn hoặc bằng Inner.GteCSFieldString",
+		},
+		{
+			ns:       "Test.NeCSFieldString",
+			expected: "NeCSFieldString không được phép bằng Inner.NeCSFieldString",
+		},
+		{
+			ns:       "Test.EqCSFieldString",
+			expected: "EqCSFieldString phải bằng Inner.EqCSFieldString",
+		},
+		{
+			ns:       "Test.EqFieldString",
+			expected: "EqFieldString phải bằng MaxString",
+		},
+		{
+			ns:       "Test.GteString",
+			expected: "GteString phải có độ dài ít nhất 3 ký tự",
+		},
+		{
+			ns:       "Test.GteNumber",
+			expected: "GteNumber phải là 5,56 hoặc lớn hơn",
+		},
+		{
+			ns:       "Test.GteMultiple",
+			expected: "GteMultiple phải chứa ít nhất 2 phần tử",
+		},
+		{
+			ns:       "Test.GteTime",
+			expected: "GteTime phải lớn hơn hoặc bằng Ngày & Giờ hiện tại",
+		},
+		{
+			ns:       "Test.GtString",
+			expected: "GtString phải có độ dài lớn hơn 3 ký tự",
+		},
+		{
+			ns:       "Test.GtNumber",
+			expected: "GtNumber phải lớn hơn 5,56",
+		},
+		{
+			ns:       "Test.GtMultiple",
+			expected: "GtMultiple phải chứa nhiều hơn 2 phần tử",
+		},
+		{
+			ns:       "Test.GtTime",
+			expected: "GtTime phải lớn hơn Ngày & Giờ hiện tại",
+		},
+		{
+			ns:       "Test.LteString",
+			expected: "LteString chỉ được có độ dài tối đa là 3 ký tự",
+		},
+		{
+			ns:       "Test.LteNumber",
+			expected: "LteNumber phải là 5,56 hoặc nhỏ hơn",
+		},
+		{
+			ns:       "Test.LteMultiple",
+			expected: "LteMultiple chỉ được chứa nhiều nhất 2 phần tử",
+		},
+		{
+			ns:       "Test.LteTime",
+			expected: "LteTime chỉ được nhỏ hơn hoặc bằng Ngày & Giờ hiện tại",
+		},
+		{
+			ns:       "Test.LtString",
+			expected: "LtString phải có độ dài nhỏ hơn 3 ký tự",
+		},
+		{
+			ns:       "Test.LtNumber",
+			expected: "LtNumber phải nhỏ hơn 5,56",
+		},
+		{
+			ns:       "Test.LtMultiple",
+			expected: "LtMultiple chỉ được chứa ít hơn 2 phần tử",
+		},
+		{
+			ns:       "Test.LtTime",
+			expected: "LtTime phải nhỏ hơn Ngày & Giờ hiện tại",
+		},
+		{
+			ns:       "Test.NeString",
+			expected: "NeString không được bằng ",
+		},
+		{
+			ns:       "Test.NeNumber",
+			expected: "NeNumber không được bằng 0.00",
+		},
+		{
+			ns:       "Test.NeMultiple",
+			expected: "NeMultiple không được bằng 0",
+		},
+		{
+			ns:       "Test.EqString",
+			expected: "EqString không bằng 3",
+		},
+		{
+			ns:       "Test.EqNumber",
+			expected: "EqNumber không bằng 2.33",
+		},
+		{
+			ns:       "Test.EqMultiple",
+			expected: "EqMultiple không bằng 7",
+		},
+		{
+			ns:       "Test.MaxString",
+			expected: "MaxString chỉ được chứa tối đa 3 ký tự",
+		},
+		{
+			ns:       "Test.MaxNumber",
+			expected: "MaxNumber phải là 1.113,00 hoặc nhỏ hơn",
+		},
+		{
+			ns:       "Test.MaxMultiple",
+			expected: "MaxMultiple chỉ được chứa tối đa 7 phần tử",
+		},
+		{
+			ns:       "Test.MinString",
+			expected: "MinString phải chứa ít nhất 1 ký tự",
+		},
+		{
+			ns:       "Test.MinNumber",
+			expected: "MinNumber phải bằng 1.113,00 hoặc lớn hơn",
+		},
+		{
+			ns:       "Test.MinMultiple",
+			expected: "MinMultiple phải chứa ít nhất 7 phần tử",
+		},
+		{
+			ns:       "Test.LenString",
+			expected: "LenString phải có độ dài là 1 ký tự",
+		},
+		{
+			ns:       "Test.LenNumber",
+			expected: "LenNumber phải bằng 1.113,00",
+		},
+		{
+			ns:       "Test.LenMultiple",
+			expected: "LenMultiple phải chứa 7 phần tử",
+		},
+		{
+			ns:       "Test.RequiredString",
+			expected: "RequiredString không được bỏ trống",
+		},
+		{
+			ns:       "Test.RequiredNumber",
+			expected: "RequiredNumber không được bỏ trống",
+		},
+		{
+			ns:       "Test.RequiredMultiple",
+			expected: "RequiredMultiple không được bỏ trống",
+		},
+		{
+			ns:       "Test.StrPtrMinLen",
+			expected: "StrPtrMinLen phải chứa ít nhất 10 ký tự",
+		},
+		{
+			ns:       "Test.StrPtrMaxLen",
+			expected: "StrPtrMaxLen chỉ được chứa tối đa 1 ký tự",
+		},
+		{
+			ns:       "Test.StrPtrLen",
+			expected: "StrPtrLen phải có độ dài là 2 ký tự",
+		},
+		{
+			ns:       "Test.StrPtrLt",
+			expected: "StrPtrLt phải có độ dài nhỏ hơn 1 ký tự",
+		},
+		{
+			ns:       "Test.StrPtrLte",
+			expected: "StrPtrLte chỉ được có độ dài tối đa là 1 ký tự",
+		},
+		{
+			ns:       "Test.StrPtrGt",
+			expected: "StrPtrGt phải có độ dài lớn hơn 10 ký tự",
+		},
+		{
+			ns:       "Test.StrPtrGte",
+			expected: "StrPtrGte phải có độ dài ít nhất 10 ký tự",
+		},
+		{
+			ns:       "Test.OneOfString",
+			expected: "OneOfString phải là trong những giá trị [red green]",
+		},
+		{
+			ns:       "Test.OneOfInt",
+			expected: "OneOfInt phải là trong những giá trị [5 63]",
+		},
+		{
+			ns:       "Test.UniqueSlice",
+			expected: "UniqueSlice chỉ được chứa những giá trị không trùng lặp",
+		},
+		{
+			ns:       "Test.UniqueArray",
+			expected: "UniqueArray chỉ được chứa những giá trị không trùng lặp",
+		},
+		{
+			ns:       "Test.UniqueMap",
+			expected: "UniqueMap chỉ được chứa những giá trị không trùng lặp",
+		},
+		{
+			ns:       "Test.JSONString",
+			expected: "JSONString phải là một chuỗi json hợp lệ",
+		},
+		{
+			ns:       "Test.JWTString",
+			expected: "JWTString phải là một chuỗi jwt hợp lệ",
+		},
+		{
+			ns:       "Test.LowercaseString",
+			expected: "LowercaseString phải được viết thường",
+		},
+		{
+			ns:       "Test.UppercaseString",
+			expected: "UppercaseString phải được viết hoa",
+		},
+		{
+			ns:       "Test.Datetime",
+			expected: "Datetime không trùng định dạng ngày tháng 2006-01-02",
+		},
+		{
+			ns:       "Test.PostCode",
+			expected: "PostCode sai định dạng postcode của quốc gia SG",
+		},
+		{
+			ns:       "Test.PostCodeByField",
+			expected: "PostCodeByField sai định dạng postcode của quốc gia tương ứng thuộc trường PostCodeCountry",
+		},
+	}
+
+	for _, tt := range tests {
+
+		var fe validator.FieldError
+
+		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 3730fb9..1ebdea5 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -4309,6 +4309,365 @@ func TestULIDValidation(t *testing.T) {
 	}
 }
 
+func TestMD4Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "md4")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d MD4 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d MD4 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "md4" {
+					t.Fatalf("Index: %d MD4 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestMD5Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "md5")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d MD5 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d MD5 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "md5" {
+					t.Fatalf("Index: %d MD5 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestSHA256Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "sha256")
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d SHA256 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d SHA256 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "sha256" {
+					t.Fatalf("Index: %d SHA256 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestSHA384Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "sha384")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d SHA384 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d SHA384 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "sha384" {
+					t.Fatalf("Index: %d SHA384 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestSHA512Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc46f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "sha512")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d SHA512 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d SHA512 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "sha512" {
+					t.Fatalf("Index: %d SHA512 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestRIPEMD128Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "ripemd128")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d RIPEMD128 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d RIPEMD128 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "ripemd128" {
+					t.Fatalf("Index: %d RIPEMD128 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestRIPEMD160Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "ripemd160")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d RIPEMD160 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d RIPEMD160 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "ripemd160" {
+					t.Fatalf("Index: %d RIPEMD160 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestTIGER128Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "tiger128")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d TIGER128 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d TIGER128 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "tiger128" {
+					t.Fatalf("Index: %d TIGER128 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestTIGER160Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "tiger160")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d TIGER160 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d TIGER160 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "tiger160" {
+					t.Fatalf("Index: %d TIGER160 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestTIGER192Validation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"6f5902ac237024bd6f5902ac237024bdd0c176cb93063dc4", true},
+		{"6f5902ac237024bd6f5902ac237024bdd0c176cb93063dc-", false},
+		{"6f5902ac237024bd6f5902ac237024bdd0c176cb93063dc41", false},
+		{"6f5902ac237024bd6f5902ac237024bdd0c176cb93063dcC", false},
+		{"6f5902ac237024bd6f5902ac237024bdd0c176cb93063dc", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "tiger192")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d TIGER192 failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d TIGER192 failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "tiger192" {
+					t.Fatalf("Index: %d TIGER192 failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
 func TestISBNValidation(t *testing.T) {
 	tests := []struct {
 		param    string
@@ -5021,6 +5380,28 @@ func TestIsEqFieldValidation(t *testing.T) {
 	Equal(t, errs, nil)
 }
 
+func TestIsEqFieldValidationWithAliasTime(t *testing.T) {
+	var errs error
+	validate := New()
+
+	type CustomTime time.Time
+
+	type Test struct {
+		Start CustomTime `validate:"eqfield=End"`
+		End   *time.Time
+	}
+
+	now := time.Now().UTC()
+
+	sv := &Test{
+		Start: CustomTime(now),
+		End:   &now,
+	}
+
+	errs = validate.Struct(sv)
+	Equal(t, errs, nil)
+}
+
 func TestIsEqValidation(t *testing.T) {
 	var errs error
 	validate := New()
@@ -9151,6 +9532,7 @@ func TestHostnameRFC1123Validation(t *testing.T) {
 		{"test.example24.com.", false},
 		{"test24.example24.com.", false},
 		{"example.", false},
+		{"test_example", false},
 		{"192.168.0.1", true},
 		{"email@example.com", false},
 		{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
@@ -9199,6 +9581,7 @@ func TestHostnameRFC1123AliasValidation(t *testing.T) {
 		{"test.example24.com.", false},
 		{"test24.example24.com.", false},
 		{"example.", false},
+		{"test_example", false},
 		{"192.168.0.1", true},
 		{"email@example.com", false},
 		{"2001:cdba:0000:0000:0000:0000:3257:9652", false},
@@ -10675,6 +11058,145 @@ func TestRequiredWithoutAll(t *testing.T) {
 	AssertError(t, errs, "Field2", "Field2", "Field2", "Field2", "required_without_all")
 }
 
+func TestExcludedIf(t *testing.T) {
+	validate := New()
+	type Inner struct {
+		Field *string
+	}
+
+	test1 := struct {
+		FieldE  string  `validate:"omitempty" json:"field_e"`
+		FieldER *string `validate:"excluded_if=FieldE test" json:"field_er"`
+	}{
+		FieldE: "test",
+	}
+	errs := validate.Struct(test1)
+	Equal(t, errs, nil)
+
+	test2 := struct {
+		FieldE  string `validate:"omitempty" json:"field_e"`
+		FieldER string `validate:"excluded_if=FieldE test" json:"field_er"`
+	}{
+		FieldE: "notest",
+	}
+	errs = validate.Struct(test2)
+	NotEqual(t, errs, nil)
+	ve := errs.(ValidationErrors)
+	Equal(t, len(ve), 1)
+	AssertError(t, errs, "FieldER", "FieldER", "FieldER", "FieldER", "excluded_if")
+
+	shouldError := "shouldError"
+	test3 := struct {
+		Inner  *Inner
+		FieldE string `validate:"omitempty" json:"field_e"`
+		Field1 int    `validate:"excluded_if=Inner.Field test" json:"field_1"`
+	}{
+		Inner: &Inner{Field: &shouldError},
+	}
+	errs = validate.Struct(test3)
+	NotEqual(t, errs, nil)
+	ve = errs.(ValidationErrors)
+	Equal(t, len(ve), 1)
+	AssertError(t, errs, "Field1", "Field1", "Field1", "Field1", "excluded_if")
+
+	shouldPass := "test"
+	test4 := struct {
+		Inner  *Inner
+		FieldE string `validate:"omitempty" json:"field_e"`
+		Field1 int    `validate:"excluded_if=Inner.Field test" json:"field_1"`
+	}{
+		Inner: &Inner{Field: &shouldPass},
+	}
+	errs = validate.Struct(test4)
+	Equal(t, errs, nil)
+
+	// Checks number of params in struct tag is correct
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("panicTest should have panicked!")
+		}
+	}()
+	fieldVal := "panicTest"
+	panicTest := struct {
+		Inner  *Inner
+		Field1 string `validate:"excluded_if=Inner.Field" json:"field_1"`
+	}{
+		Inner: &Inner{Field: &fieldVal},
+	}
+	_ = validate.Struct(panicTest)
+}
+
+func TestExcludedUnless(t *testing.T) {
+	validate := New()
+	type Inner struct {
+		Field *string
+	}
+
+	fieldVal := "test"
+	test := struct {
+		FieldE  string `validate:"omitempty" json:"field_e"`
+		FieldER string `validate:"excluded_unless=FieldE test" json:"field_er"`
+	}{
+		FieldE:  "notest",
+		FieldER: "filled",
+	}
+	errs := validate.Struct(test)
+	Equal(t, errs, nil)
+
+	test2 := struct {
+		FieldE  string `validate:"omitempty" json:"field_e"`
+		FieldER string `validate:"excluded_unless=FieldE test" json:"field_er"`
+	}{
+		FieldE:  "test",
+		FieldER: "filled",
+	}
+	errs = validate.Struct(test2)
+	NotEqual(t, errs, nil)
+	ve := errs.(ValidationErrors)
+	Equal(t, len(ve), 1)
+	AssertError(t, errs, "FieldER", "FieldER", "FieldER", "FieldER", "excluded_unless")
+
+	shouldError := "test"
+	test3 := struct {
+		Inner  *Inner
+		Field1 string `validate:"excluded_unless=Inner.Field test" json:"field_1"`
+	}{
+		Inner:  &Inner{Field: &shouldError},
+		Field1: "filled",
+	}
+	errs = validate.Struct(test3)
+	NotEqual(t, errs, nil)
+	ve = errs.(ValidationErrors)
+	Equal(t, len(ve), 1)
+	AssertError(t, errs, "Field1", "Field1", "Field1", "Field1", "excluded_unless")
+
+	shouldPass := "shouldPass"
+	test4 := struct {
+		Inner  *Inner
+		FieldE string `validate:"omitempty" json:"field_e"`
+		Field1 string `validate:"excluded_unless=Inner.Field test" json:"field_1"`
+	}{
+		Inner:  &Inner{Field: &shouldPass},
+		Field1: "filled",
+	}
+	errs = validate.Struct(test4)
+	Equal(t, errs, nil)
+
+	// Checks number of params in struct tag is correct
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("panicTest should have panicked!")
+		}
+	}()
+	panicTest := struct {
+		Inner  *Inner
+		Field1 string `validate:"excluded_unless=Inner.Field" json:"field_1"`
+	}{
+		Inner: &Inner{Field: &fieldVal},
+	}
+	_ = validate.Struct(panicTest)
+}
+
 func TestLookup(t *testing.T) {
 	type Lookup struct {
 		FieldA *string `json:"fieldA,omitempty" validate:"required_without=FieldB"`
@@ -11460,7 +11982,7 @@ func TestSemverFormatValidation(t *testing.T) {
 		}
 	}
 }
-  
+
 func TestRFC1035LabelFormatValidation(t *testing.T) {
 	tests := []struct {
 		value    string `validate:"dns_rfc1035_label"`
@@ -11611,3 +12133,156 @@ func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) {
 	_ = New().Struct(test{"ABC", 123, false})
 	t.Errorf("Didn't panic as expected")
 }
+
+func TestValidate_ValidateMapCtx(t *testing.T) {
+
+	type args struct {
+		data  map[string]interface{}
+		rules map[string]interface{}
+	}
+	tests := []struct {
+		name string
+		args args
+		want int
+	}{
+		{
+			name: "test nested map in slice",
+			args: args{
+				data: map[string]interface{}{
+					"Test_A": map[string]interface{}{
+						"Test_B": "Test_B",
+						"Test_C": []map[string]interface{}{
+							{
+								"Test_D": "Test_D",
+							},
+						},
+						"Test_E": map[string]interface{}{
+							"Test_F": "Test_F",
+						},
+					},
+				},
+				rules: map[string]interface{}{
+					"Test_A": map[string]interface{}{
+						"Test_B": "min=2",
+						"Test_C": map[string]interface{}{
+							"Test_D": "min=2",
+						},
+						"Test_E": map[string]interface{}{
+							"Test_F": "min=2",
+						},
+					},
+				},
+			},
+			want: 0,
+		},
+
+		{
+			name: "test nested map error",
+			args: args{
+				data: map[string]interface{}{
+					"Test_A": map[string]interface{}{
+						"Test_B": "Test_B",
+						"Test_C": []interface{}{"Test_D"},
+						"Test_E": map[string]interface{}{
+							"Test_F": "Test_F",
+						},
+						"Test_G": "Test_G",
+						"Test_I": []map[string]interface{}{
+							{
+								"Test_J": "Test_J",
+							},
+						},
+					},
+				},
+				rules: map[string]interface{}{
+					"Test_A": map[string]interface{}{
+						"Test_B": "min=2",
+						"Test_C": map[string]interface{}{
+							"Test_D": "min=2",
+						},
+						"Test_E": map[string]interface{}{
+							"Test_F": "min=100",
+						},
+						"Test_G": map[string]interface{}{
+							"Test_H": "min=2",
+						},
+						"Test_I": map[string]interface{}{
+							"Test_J": "min=100",
+						},
+					},
+				},
+			},
+			want: 1,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			validate := New()
+			if got := validate.ValidateMapCtx(context.Background(), tt.args.data, tt.args.rules); len(got) != tt.want {
+				t.Errorf("ValidateMapCtx() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestCreditCardFormatValidation(t *testing.T) {
+	tests := []struct {
+		value    string `validate:"credit_card"`
+		tag      string
+		expected bool
+	}{
+		{"586824160825533338", "credit_card", true},
+		{"586824160825533328", "credit_card", false},
+		{"4624748233249780", "credit_card", true},
+		{"4624748233349780", "credit_card", false},
+		{"378282246310005", "credit_card", true},
+		{"378282146310005", "credit_card", false},
+		{"4624 7482 3324 9780", "credit_card", true},
+		{"4624 7482 3324  9780", "credit_card", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+		errs := validate.Var(test.value, test.tag)
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d credit_card failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d credit_card failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "credit_card" {
+					t.Fatalf("Index: %d credit_card failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestMultiOrOperatorGroup(t *testing.T) {
+ 	tests := []struct {
+ 		Value    int `validate:"eq=1|gte=5,eq=1|lt=7"`
+ 		expected bool
+ 	}{
+ 		{1, true}, {2, false}, {5, true}, {6, true}, {8, false},
+ 	}
+
+ 	validate := New()
+
+ 	for i, test := range tests {
+ 		errs := validate.Struct(test)
+ 		if test.expected {
+ 			if !IsEqual(errs, nil) {
+ 				t.Fatalf("Index: %d multi_group_of_OR_operators failed Error: %s", i, errs)
+ 			}
+ 		} else {
+ 			if IsEqual(errs, nil) {
+ 				t.Fatalf("Index: %d multi_group_of_OR_operators should have errs", i)
+ 			}
+ 		}
+ 	}
+ }