Repository: go-playground/validator
Pull request #824 (2021-09-02 07:22:32)

Updated `endsnotwith` description in Readme
In the strings section, `endsnotwith` has the same description as `endswith`.

## Fixes Or Enhances


**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.
_(Readme update - PR does not require tests.)_

@go-playground/validator-maintainers

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

Coverage remained the same at 75.1% when pulling **7d5c452a9cea3f548659265d59687a2fc23aa714 on ciprian-cimpan:patch-1** into **ce34f361cca51e25715399ab801c5e1c01d02d89 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 f56cff1..0201880 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 Package validator
 =================
 <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-![Project status](https://img.shields.io/badge/version-10.9.0-green.svg)
+![Project status](https://img.shields.io/badge/version-10.10.1-green.svg)
 [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator)
 [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
 [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
@@ -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,8 @@ Baked-in Validations
 | uuid5 | Universally Unique Identifier UUID v5 |
 | uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
 | uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
+| semver | Semantic Versioning 2.0.0 |
+| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
 
 ### Comparisons:
 | Tag | Description |
@@ -217,6 +220,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/baked_in.go b/baked_in.go
index f5fd239..bc638f2 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,
@@ -148,6 +150,7 @@ var (
 		"uuid3_rfc4122":                 isUUID3RFC4122,
 		"uuid4_rfc4122":                 isUUID4RFC4122,
 		"uuid5_rfc4122":                 isUUID5RFC4122,
+		"ulid":                          isULID,
 		"ascii":                         isASCII,
 		"printascii":                    isPrintableASCII,
 		"multibyte":                     hasMultiByteCharacter,
@@ -198,6 +201,9 @@ var (
 		"postcode_iso3166_alpha2":       isPostcodeByIso3166Alpha2,
 		"postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
 		"bic":                           isIsoBicFormat,
+		"semver":                        isSemverFormat,
+		"dns_rfc1035_label":             isDnsRFC1035LabelFormat,
+		"credit_card":                   isCreditCard,
 	}
 )
 
@@ -498,6 +504,11 @@ func isUUIDRFC4122(fl FieldLevel) bool {
 	return uUIDRFC4122Regex.MatchString(fl.Field().String())
 }
 
+// isULID is the validation function for validating if the field's value is a valid ULID.
+func isULID(fl FieldLevel) bool {
+	return uLIDRegex.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)
@@ -808,12 +819,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)
@@ -821,6 +827,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:
@@ -861,18 +871,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.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) || fieldTime.Equal(topTime)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -909,18 +919,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 == 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)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -956,18 +966,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:
@@ -1003,18 +1013,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 == 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)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != topField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -1053,18 +1063,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 == timeType {
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(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:
@@ -1103,18 +1113,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 == timeType {
+		if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(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:
@@ -1153,19 +1163,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.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.Equal(t)
 		}
 
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String:
@@ -1534,6 +1543,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 {
@@ -1550,6 +1575,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 {
@@ -1669,18 +1709,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
@@ -1716,18 +1756,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
@@ -1769,10 +1809,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)
 		}
@@ -1815,9 +1855,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())
 		}
 	}
 
@@ -1895,18 +1935,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.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) || fieldTime.Equal(t)
 		}
+
+		// Not Same underlying type i.e. struct and time
+		if fieldType != currentField.Type() {
+			return false
+		}
 	}
 
 	// default reflect.String
@@ -1942,18 +1982,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
@@ -1995,10 +2035,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)
 		}
@@ -2042,9 +2082,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())
 		}
 	}
 
@@ -2351,6 +2391,12 @@ func isIso3166AlphaNumeric(fl FieldLevel) bool {
 
 	var code int
 	switch field.Kind() {
+	case reflect.String:
+		i, err := strconv.Atoi(field.String())
+		if err != nil {
+			return false
+		}
+		code = i % 1000
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		code = int(field.Int() % 1000)
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
@@ -2407,3 +2453,56 @@ func isIsoBicFormat(fl FieldLevel) bool {
 
 	return bicRegex.MatchString(bicString)
 }
+
+// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0
+func isSemverFormat(fl FieldLevel) bool {
+	semverString := fl.Field().String()
+
+	return semverRegex.MatchString(semverString)
+}
+
+// isDnsRFC1035LabelFormat is the validation function
+// for validating if the current field's value is
+// a valid dns RFC 1035 label, defined in RFC 1035.
+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/doc.go b/doc.go
index 8c25847..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
@@ -1007,6 +1041,12 @@ This validates that a string value contains a valid version 5 UUID.  Uppercase U
 
 	Usage: uuid5
 
+Universally Unique Lexicographically Sortable Identifier ULID
+
+This validates that a string value contains a valid ULID value.
+
+	Usage: ulid
+
 ASCII
 
 This validates that a string value contains only ASCII characters.
@@ -1255,6 +1295,13 @@ More information on https://www.iso.org/standard/60390.html
 
 	Usage: bic
 
+RFC 1035 label
+
+This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035.
+More information on https://datatracker.ietf.org/doc/html/rfc1035
+
+	Usage: dns_rfc1035_label
+
 TimeZone
 
 This validates that a string value is a valid time zone based on the time zone database present on the system.
@@ -1263,6 +1310,18 @@ More information on https://golang.org/pkg/time/#LoadLocation
 
 	Usage: timezone
 
+Semantic Version
+
+This validates that a string value is a valid semver version, defined in Semantic Versioning 2.0.0.
+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
 
diff --git a/go.mod b/go.mod
index ddecff6..e281ec0 100644
--- a/go.mod
+++ b/go.mod
@@ -11,9 +11,9 @@ require (
 	github.com/leodido/go-urn v1.2.1
 	github.com/rogpeppe/go-internal v1.8.0 // indirect
 	github.com/stretchr/testify v1.7.0 // indirect
-	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
+	golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
 	golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
-	golang.org/x/text v0.3.6
+	golang.org/x/text v0.3.7
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 )
diff --git a/go.sum b/go.sum
index 5750093..a1c43c3 100644
--- a/go.sum
+++ b/go.sum
@@ -28,17 +28,19 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/regexes.go b/regexes.go
index df00c4e..a8668f8 100644
--- a/regexes.go
+++ b/regexes.go
@@ -10,7 +10,7 @@ const (
 	numericRegexString               = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
 	numberRegexString                = "^[0-9]+$"
 	hexadecimalRegexString           = "^(0[xX])?[0-9a-fA-F]+$"
-	hexColorRegexString              = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
+	hexColorRegexString              = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
 	rgbRegexString                   = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$"
 	rgbaRegexString                  = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
 	hslRegexString                   = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$"
@@ -29,6 +29,7 @@ const (
 	uUID4RFC4122RegexString          = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
 	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}$"
 	aSCIIRegexString                 = "^[\x00-\x7F]*$"
 	printableASCIIRegexString        = "^[\x20-\x7E]*$"
 	multibyteRegexString             = "[^\x00-\x7F]"
@@ -36,12 +37,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}$`
@@ -51,6 +52,8 @@ const (
 	jWTRegexString                   = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
 	splitParamsRegexString           = `'[^']*'|\S+`
 	bicRegexString                   = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
+	semverRegexString                = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
+	dnsRegexStringRFC1035Label       = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
 )
 
 var (
@@ -80,6 +83,7 @@ var (
 	uUID4RFC4122Regex          = regexp.MustCompile(uUID4RFC4122RegexString)
 	uUID5RFC4122Regex          = regexp.MustCompile(uUID5RFC4122RegexString)
 	uUIDRFC4122Regex           = regexp.MustCompile(uUIDRFC4122RegexString)
+	uLIDRegex                  = regexp.MustCompile(uLIDRegexString)
 	aSCIIRegex                 = regexp.MustCompile(aSCIIRegexString)
 	printableASCIIRegex        = regexp.MustCompile(printableASCIIRegexString)
 	multibyteRegex             = regexp.MustCompile(multibyteRegexString)
@@ -102,4 +106,6 @@ var (
 	jWTRegex                   = regexp.MustCompile(jWTRegexString)
 	splitParamsRegex           = regexp.MustCompile(splitParamsRegexString)
 	bicRegex                   = regexp.MustCompile(bicRegexString)
+	semverRegex                = regexp.MustCompile(semverRegexString)
+	dnsRegexRFC1035Label       = regexp.MustCompile(dnsRegexStringRFC1035Label)
 )
diff --git a/translations/en/en.go b/translations/en/en.go
index b95f7dd..5ed76ae 100644
--- a/translations/en/en.go
+++ b/translations/en/en.go
@@ -1136,6 +1136,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} must be a valid version 5 UUID",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} must be a valid ULID",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} must contain only ascii characters",
diff --git a/translations/es/es.go b/translations/es/es.go
index 2b87f10..2635408 100644
--- a/translations/es/es.go
+++ b/translations/es/es.go
@@ -1178,6 +1178,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} debe ser una versión válida 5 UUID",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} debe ser un ULID válido",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} debe contener sólo caracteres ascii",
diff --git a/translations/fa/fa.go b/translations/fa/fa.go
index fc21aa0..b7c100b 100644
--- a/translations/fa/fa.go
+++ b/translations/fa/fa.go
@@ -1136,6 +1136,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} باید یک UUID نسخه 5 معتبر باشد",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} باید یک ULID معتبر باشد",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} باید فقط شامل کاراکترهای اسکی باشد",
diff --git a/translations/fr/fr.go b/translations/fr/fr.go
index ddebdf9..c455195 100644
--- a/translations/fr/fr.go
+++ b/translations/fr/fr.go
@@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} doit être un UUID version 5 valid",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} doit être une ULID valide",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} ne doit contenir que des caractères ascii",
diff --git a/translations/id/id.go b/translations/id/id.go
index d185dfc..08b6ad5 100644
--- a/translations/id/id.go
+++ b/translations/id/id.go
@@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} harus berupa UUID versi 5 yang valid",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} harus berupa ULID yang valid",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} hanya boleh berisi karakter ascii",
diff --git a/translations/it/it.go b/translations/it/it.go
new file mode 100644
index 0000000..8abd67f
--- /dev/null
+++ b/translations/it/it.go
@@ -0,0 +1,1244 @@
+package en
+
+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: "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 7b887c0..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
 				}
 
@@ -1229,6 +1229,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0}はバージョンが5の正しいUUIDでなければなりません",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0}は正しいULIDでなければなりません",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0}はASCII文字のみを含まなければなりません",
diff --git a/translations/nl/nl.go b/translations/nl/nl.go
index a64815d..ca7c554 100644
--- a/translations/nl/nl.go
+++ b/translations/nl/nl.go
@@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} moet een geldige versie 5 UUID zijn",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} moet een geldige ULID zijn",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} mag alleen ascii karakters bevatten",
diff --git a/translations/pt/pt.go b/translations/pt/pt.go
index 9dbaf5f..4748331 100644
--- a/translations/pt/pt.go
+++ b/translations/pt/pt.go
@@ -1178,6 +1178,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} deve ser um UUID versão 5 válido",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} deve ser um ULID válido",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} deve conter apenas caracteres ascii",
diff --git a/translations/pt_BR/pt_BR.go b/translations/pt_BR/pt_BR.go
index df4fc67..ef04496 100644
--- a/translations/pt_BR/pt_BR.go
+++ b/translations/pt_BR/pt_BR.go
@@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} deve ser um UUID versão 5 válido",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} deve ser uma ULID válida",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} deve conter apenas caracteres ascii",
diff --git a/translations/ru/ru.go b/translations/ru/ru.go
index 7a12bd8..25400c5 100644
--- a/translations/ru/ru.go
+++ b/translations/ru/ru.go
@@ -1291,6 +1291,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} должен быть UUID 5 версии",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} должен быть ULID",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} должен содержать только ascii символы",
diff --git a/translations/tr/tr.go b/translations/tr/tr.go
index 2709e4b..2e88a20 100644
--- a/translations/tr/tr.go
+++ b/translations/tr/tr.go
@@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0} geçerli bir sürüm 5 UUID olmalıdır",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0} geçerli bir ULID olmalıdır",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0} yalnızca ascii karakterler içermelidir",
diff --git a/translations/zh/zh.go b/translations/zh/zh.go
index 5fff6b4..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) {
@@ -1225,6 +1255,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0}必须是一个有效的V5 UUID",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0}必须是一个有效的ULID",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0}必须只包含ascii字符",
diff --git a/translations/zh_tw/zh_tw.go b/translations/zh_tw/zh_tw.go
index 391a010..c39a8d7 100644
--- a/translations/zh_tw/zh_tw.go
+++ b/translations/zh_tw/zh_tw.go
@@ -1166,6 +1166,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
 			translation: "{0}必須是一個有效的V5 UUID",
 			override:    false,
 		},
+		{
+			tag:         "ulid",
+			translation: "{0}必須是一個有效的ULID",
+			override:    false,
+		},
 		{
 			tag:         "ascii",
 			translation: "{0}必須只包含ascii字元",
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..316ffb0 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"
@@ -120,7 +122,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
@@ -169,7 +171,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)
 }
@@ -331,7 +333,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 +378,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 +426,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 +516,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/en/en_test.go b/translations/en/en_test.go
index 0f20768..146c475 100644
--- a/translations/en/en_test.go
+++ b/translations/en/en_test.go
@@ -103,6 +103,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -323,6 +324,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 must be a valid version 5 UUID",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID must be a valid ULID",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN must be a valid ISBN number",
diff --git a/translations/es/es_test.go b/translations/es/es_test.go
index 070e3a8..814f2ab 100644
--- a/translations/es/es_test.go
+++ b/translations/es/es_test.go
@@ -4,9 +4,9 @@ import (
 	"testing"
 	"time"
 
+	. "github.com/go-playground/assert/v2"
 	spanish "github.com/go-playground/locales/es"
 	ut "github.com/go-playground/universal-translator"
-	. "github.com/go-playground/assert/v2"
 	"github.com/go-playground/validator/v10"
 )
 
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -312,6 +313,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 debe ser una versión válida 5 UUID",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID debe ser un ULID válido",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN debe ser un número ISBN válido",
diff --git a/translations/fa/fa_test.go b/translations/fa/fa_test.go
index 611f23e..1acb8cf 100644
--- a/translations/fa/fa_test.go
+++ b/translations/fa/fa_test.go
@@ -103,6 +103,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -322,6 +323,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 باید یک UUID نسخه 5 معتبر باشد",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID باید یک ULID معتبر باشد",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN باید یک شابک معتبر باشد",
diff --git a/translations/fr/fr_test.go b/translations/fr/fr_test.go
index c2c88d0..f1ba280 100644
--- a/translations/fr/fr_test.go
+++ b/translations/fr/fr_test.go
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 doit être un UUID version 5 valid",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID doit être une ULID valide",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN doit être un numéro ISBN valid",
diff --git a/translations/id/id_test.go b/translations/id/id_test.go
index 83a72aa..5d80940 100644
--- a/translations/id/id_test.go
+++ b/translations/id/id_test.go
@@ -4,9 +4,9 @@ import (
 	"testing"
 	"time"
 
+	. "github.com/go-playground/assert/v2"
 	indonesia "github.com/go-playground/locales/id"
 	ut "github.com/go-playground/universal-translator"
-	. "github.com/go-playground/assert/v2"
 	"github.com/go-playground/validator/v10"
 )
 
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 harus berupa UUID versi 5 yang valid",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID harus berupa ULID yang valid",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN harus berupa nomor ISBN yang valid",
diff --git a/translations/it/it_test.go b/translations/it/it_test.go
new file mode 100644
index 0000000..301e8c1
--- /dev/null
+++ b/translations/it/it_test.go
@@ -0,0 +1,724 @@
+package en
+
+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) {
+	it := italian.New()
+	uni := ut.New(it, it)
+	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"`
+		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 eaa2743..7950251 100644
--- a/translations/ja/ja_test.go
+++ b/translations/ja/ja_test.go
@@ -4,9 +4,9 @@ import (
 	"testing"
 	"time"
 
+	. "github.com/go-playground/assert/v2"
 	ja_locale "github.com/go-playground/locales/ja"
 	ut "github.com/go-playground/universal-translator"
-	. "github.com/go-playground/assert/v2"
 	"github.com/go-playground/validator/v10"
 )
 
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5はバージョンが5の正しいUUIDでなければなりません",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULIDは正しいULIDでなければなりません",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBNは正しいISBN番号でなければなりません",
@@ -448,7 +453,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.GteNumber",
-			expected: "GteNumberは5.56かより大きくなければなりません",
+			expected: "GteNumberは5.56より大きくなければなりません",
 		},
 		{
 			ns:       "Test.GteMultiple",
@@ -480,7 +485,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.LteNumber",
-			expected: "LteNumberは5.56かより小さくなければなりません",
+			expected: "LteNumberは5.56より小さくなければなりません",
 		},
 		{
 			ns:       "Test.LteMultiple",
@@ -536,7 +541,7 @@ func TestTranslations(t *testing.T) {
 		},
 		{
 			ns:       "Test.MaxNumber",
-			expected: "MaxNumberは1,113.00かより小さくなければなりません",
+			expected: "MaxNumberは1,113.00より小さくなければなりません",
 		},
 		{
 			ns:       "Test.MaxMultiple",
@@ -548,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/nl/nl_test.go b/translations/nl/nl_test.go
index 55f5048..137e0c4 100644
--- a/translations/nl/nl_test.go
+++ b/translations/nl/nl_test.go
@@ -4,9 +4,9 @@ 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/assert/v2"
 	"github.com/go-playground/validator/v10"
 )
 
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 moet een geldige versie 5 UUID zijn",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID moet een geldige ULID zijn",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN moet een geldig ISBN nummer zijn",
diff --git a/translations/pt/pt_test.go b/translations/pt/pt_test.go
index ceec15f..0422ab0 100644
--- a/translations/pt/pt_test.go
+++ b/translations/pt/pt_test.go
@@ -105,6 +105,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -321,6 +322,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 deve ser um UUID versão 5 válido",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID deve ser um ULID válido",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN deve ser um número de ISBN válido",
diff --git a/translations/pt_BR/pt_BR_test.go b/translations/pt_BR/pt_BR_test.go
index 32125f6..c8a6482 100644
--- a/translations/pt_BR/pt_BR_test.go
+++ b/translations/pt_BR/pt_BR_test.go
@@ -4,10 +4,10 @@ import (
 	"testing"
 	"time"
 
+	. "github.com/go-playground/assert/v2"
 	brazilian_portuguese "github.com/go-playground/locales/pt_BR"
 	ut "github.com/go-playground/universal-translator"
 	"github.com/go-playground/validator/v10"
-	. "github.com/go-playground/assert/v2"
 )
 
 func TestTranslations(t *testing.T) {
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 deve ser um UUID versão 5 válido",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID deve ser uma ULID válida",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN deve ser um número ISBN válido",
diff --git a/translations/ru/ru_test.go b/translations/ru/ru_test.go
index e1a1069..c74f0d5 100644
--- a/translations/ru/ru_test.go
+++ b/translations/ru/ru_test.go
@@ -120,6 +120,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -340,6 +341,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 должен быть UUID 5 версии",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID должен быть ULID",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN должен быть ISBN номером",
diff --git a/translations/tr/tr_test.go b/translations/tr/tr_test.go
index 7cfa5a4..b72329e 100644
--- a/translations/tr/tr_test.go
+++ b/translations/tr/tr_test.go
@@ -4,9 +4,9 @@ import (
 	"testing"
 	"time"
 
+	. "github.com/go-playground/assert/v2"
 	turkish "github.com/go-playground/locales/tr"
 	ut "github.com/go-playground/universal-translator"
-	. "github.com/go-playground/assert/v2"
 	"github.com/go-playground/validator/v10"
 )
 
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -312,6 +313,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5 geçerli bir sürüm 5 UUID olmalıdır",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID geçerli bir ULID olmalıdır",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN geçerli bir ISBN numarası olmalıdır",
diff --git a/translations/zh/zh_test.go b/translations/zh/zh_test.go
index 1d73c65..cf76590 100644
--- a/translations/zh/zh_test.go
+++ b/translations/zh/zh_test.go
@@ -109,6 +109,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -327,6 +328,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5必须是一个有效的V5 UUID",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID必须是一个有效的ULID",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN必须是一个有效的ISBN编号",
diff --git a/translations/zh_tw/zh_tw_test.go b/translations/zh_tw/zh_tw_test.go
index cf60d1d..129c51a 100644
--- a/translations/zh_tw/zh_tw_test.go
+++ b/translations/zh_tw/zh_tw_test.go
@@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
 		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"`
@@ -309,6 +310,10 @@ func TestTranslations(t *testing.T) {
 			ns:       "Test.UUID5",
 			expected: "UUID5必須是一個有效的V5 UUID",
 		},
+		{
+			ns:       "Test.ULID",
+			expected: "ULID必須是一個有效的ULID",
+		},
 		{
 			ns:       "Test.ISBN",
 			expected: "ISBN必須是一個有效的ISBN編號",
diff --git a/validator_test.go b/validator_test.go
index f694203..8abe0ce 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -4269,6 +4269,46 @@ func TestUUIDRFC4122Validation(t *testing.T) {
 	}
 }
 
+func TestULIDValidation(t *testing.T) {
+	tests := []struct {
+		param    string
+		expected bool
+	}{
+		{"", false},
+		{"01BX5ZZKBKACT-V9WEVGEMMVRZ", false},
+		{"01bx5zzkbkactav9wevgemmvrz", false},
+		{"a987Fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false},
+		{"01BX5ZZKBKACTAV9WEVGEMMVRZABC", false},
+		{"01BX5ZZKBKACTAV9WEVGEMMVRZABC", false},
+		{"0IBX5ZZKBKACTAV9WEVGEMMVRZ", false},
+		{"O1BX5ZZKBKACTAV9WEVGEMMVRZ", false},
+		{"01BX5ZZKBKACTAVLWEVGEMMVRZ", false},
+		{"01BX5ZZKBKACTAV9WEVGEMMVRZ", true},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.param, "ulid")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d ULID failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d ULID failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "ulid" {
+					t.Fatalf("Index: %d ULID failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
 func TestISBNValidation(t *testing.T) {
 	tests := []struct {
 		param    string
@@ -4981,6 +5021,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()
@@ -9111,6 +9173,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},
@@ -9159,6 +9222,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},
@@ -10635,6 +10699,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"`
@@ -11053,12 +11256,15 @@ func TestIsIso3166Alpha3Validation(t *testing.T) {
 
 func TestIsIso3166AlphaNumericValidation(t *testing.T) {
 	tests := []struct {
-		value    int
+		value    interface{}
 		expected bool
 	}{
 		{248, true},
+		{"248", true},
 		{0, false},
 		{1, false},
+		{"1", false},
+		{"invalid_int", false},
 	}
 
 	validate := New()
@@ -11079,8 +11285,41 @@ func TestIsIso3166AlphaNumericValidation(t *testing.T) {
 	}
 
 	PanicMatches(t, func() {
-		_ = validate.Var("1", "iso3166_1_alpha_numeric")
-	}, "Bad field type string")
+		_ = validate.Var([]string{"1"}, "iso3166_1_alpha_numeric")
+	}, "Bad field type []string")
+}
+
+func TestCountryCodeValidation(t *testing.T) {
+	tests := []struct {
+		value    interface{}
+		expected bool
+	}{
+		{248, true},
+		{0, false},
+		{1, false},
+		{"POL", true},
+		{"NO", true},
+		{"248", true},
+		{"1", false},
+		{"0", false},
+	}
+
+	validate := New()
+
+	for i, test := range tests {
+
+		errs := validate.Var(test.value, "country_code")
+
+		if test.expected {
+			if !IsEqual(errs, nil) {
+				t.Fatalf("Index: %d country_code failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d country_code failed Error: %s", i, errs)
+			}
+		}
+	}
 }
 
 func TestIsIso4217Validation(t *testing.T) {
@@ -11307,6 +11546,123 @@ func TestBicIsoFormatValidation(t *testing.T) {
 	}
 }
 
+func TestSemverFormatValidation(t *testing.T) {
+	tests := []struct {
+		value    string `validate:"semver"`
+		tag      string
+		expected bool
+	}{
+		{"1.2.3", "semver", true},
+		{"10.20.30", "semver", true},
+		{"1.1.2-prerelease+meta", "semver", true},
+		{"1.1.2+meta", "semver", true},
+		{"1.1.2+meta-valid", "semver", true},
+		{"1.0.0-alpha", "semver", true},
+		{"1.0.0-alpha.1", "semver", true},
+		{"1.0.0-alpha.beta", "semver", true},
+		{"1.0.0-alpha.beta.1", "semver", true},
+		{"1.0.0-alpha0.valid", "semver", true},
+		{"1.0.0-alpha.0valid", "semver", true},
+		{"1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay", "semver", true},
+		{"1.0.0-rc.1+build.1", "semver", true},
+		{"1.0.0-rc.1+build.123", "semver", true},
+		{"1.2.3-beta", "semver", true},
+		{"1.2.3-DEV-SNAPSHOT", "semver", true},
+		{"1.2.3-SNAPSHOT-123", "semver", true},
+		{"2.0.0+build.1848", "semver", true},
+		{"2.0.1-alpha.1227", "semver", true},
+		{"1.0.0-alpha+beta", "semver", true},
+		{"1.2.3----RC-SNAPSHOT.12.9.1--.12+788", "semver", true},
+		{"1.2.3----R-S.12.9.1--.12+meta", "semver", true},
+		{"1.2.3----RC-SNAPSHOT.12.9.1--.12", "semver", true},
+		{"1.0.0+0.build.1-rc.10000aaa-kk-0.1", "semver", true},
+		{"99999999999999999999999.999999999999999999.99999999999999999", "semver", true},
+		{"1.0.0-0A.is.legal", "semver", true},
+		{"1", "semver", false},
+		{"1.2", "semver", false},
+		{"1.2.3-0123", "semver", false},
+		{"1.2.3-0123.0123", "semver", false},
+		{"1.1.2+.123", "semver", false},
+		{"+invalid", "semver", false},
+		{"-invalid", "semver", false},
+		{"-invalid+invalid", "semver", false},
+		{"alpha", "semver", false},
+		{"alpha.beta.1", "semver", false},
+		{"alpha.1", "semver", false},
+		{"1.0.0-alpha_beta", "semver", false},
+		{"1.0.0-alpha_beta", "semver", false},
+		{"1.0.0-alpha...1", "semver", false},
+		{"01.1.1", "semver", false},
+		{"1.01.1", "semver", false},
+		{"1.1.01", "semver", false},
+		{"1.2", "semver", false},
+		{"1.2.Dev", "semver", false},
+		{"1.2.3.Dev", "semver", false},
+		{"1.2-SNAPSHOT", "semver", 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 semver failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d semver failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "semver" {
+					t.Fatalf("Index: %d semver failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
+func TestRFC1035LabelFormatValidation(t *testing.T) {
+	tests := []struct {
+		value    string `validate:"dns_rfc1035_label"`
+		tag      string
+		expected bool
+	}{
+		{"abc", "dns_rfc1035_label", true},
+		{"abc-", "dns_rfc1035_label", false},
+		{"abc-123", "dns_rfc1035_label", true},
+		{"ABC", "dns_rfc1035_label", false},
+		{"ABC-123", "dns_rfc1035_label", false},
+		{"abc-abc", "dns_rfc1035_label", true},
+		{"ABC-ABC", "dns_rfc1035_label", false},
+		{"123-abc", "dns_rfc1035_label", false},
+		{"", "dns_rfc1035_label", 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 dns_rfc1035_label failed Error: %s", i, errs)
+			}
+		} else {
+			if IsEqual(errs, nil) {
+				t.Fatalf("Index: %d dns_rfc1035_label failed Error: %s", i, errs)
+			} else {
+				val := getError(errs, "", "")
+				if val.Tag() != "dns_rfc1035_label" {
+					t.Fatalf("Index: %d dns_rfc1035_label failed Error: %s", i, errs)
+				}
+			}
+		}
+	}
+}
+
 func TestPostCodeByIso3166Alpha2(t *testing.T) {
 	tests := map[string][]struct {
 		value    string
@@ -11418,3 +11774,65 @@ func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) {
 	_ = New().Struct(test{"ABC", 123, false})
 	t.Errorf("Didn't panic as expected")
 }
+
+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)
+ 			}
+ 		}
+ 	}
+ }