diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..24b80ce --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @go-playground/validator-maintainers \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6d3811c..7cad4db 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Quality Standard -To ensure the continued stability of this package, tests are required to be written or already exist in order for a pull request to be merged. +To ensure the continued stability of this package, tests are required that cover the change in order for a pull request to be merged. ## Reporting issues diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 8afb259..40b774a 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,7 @@ -### Package version eg. v8, v9: +- [ ] I have looked at the documentation [here](https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation) first? +- [ ] I have looked at the examples provided that may showcase my question [here](/_examples)? + +### Package version eg. v9, v10: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7bebde3..d99afdb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,13 +1,7 @@ -Fixes Or Enhances # . +## Fixes Or Enhances + **Make sure that you've checked the boxes below before you submit PR:** - [ ] Tests exist or have been written that cover this particular change. -Change Details: - -- -- -- - - -@go-playground/admins \ No newline at end of file +@go-playground/validator-maintainers \ No newline at end of file diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..acf873d --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,48 @@ +on: + push: + branches: + - master + pull_request: +name: Test +jobs: + test: + strategy: + matrix: + go-version: [1.15.x, 1.16.x] + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Restore Cache + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-v1-go- + + - name: Test + run: go test -race -covermode=atomic -coverprofile="profile.cov" ./... + + - name: Send Coverage + if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.16.x' + uses: shogo82148/actions-goveralls@v1 + with: + path-to-profile: profile.cov + + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: v1.39 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 85a7be3..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: go -go: - - 1.15.2 - - tip -matrix: - allow_failures: - - go: tip - -notifications: - email: - recipients: dean.karn@gmail.com - on_success: change - on_failure: always - -before_install: - - go install github.com/mattn/goveralls - - mkdir -p $GOPATH/src/gopkg.in - - ln -s $GOPATH/src/github.com/$TRAVIS_REPO_SLUG $GOPATH/src/gopkg.in/validator.v9 - -# Only clone the most recent commit. -git: - depth: 1 - -script: - - go test -v -race -covermode=atomic -coverprofile=coverage.coverprofile ./... - -after_success: | - [ $TRAVIS_GO_VERSION = 1.15.2 ] && - goveralls -coverprofile=coverage.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000..b809c4c --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,16 @@ +## Maintainers Guide + +### Semantic Versioning +Semantic versioning as defined [here](https://semver.org) must be strictly adhered to. + +### External Dependencies +Any new external dependencies MUST: +- Have a compatible LICENSE present. +- Be actively maintained. +- Be approved by @go-playground/admins + +### PR Merge Requirements +- Up-to-date branch. +- Passing tests and linting. +- CODEOWNERS approval. +- Tests that cover both the Happy and Unhappy paths. \ No newline at end of file diff --git a/Makefile b/Makefile index 19c91ed..164e8bb 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ linters-install: @golangci-lint --version >/dev/null 2>&1 || { \ echo "installing linting tools..."; \ - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.21.0; \ + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.39.0; \ } lint: linters-install - $(PWD)/bin/golangci-lint run + golangci-lint run test: $(GOCMD) test -cover -race ./... diff --git a/README.md b/README.md index 04fbb3c..28975a6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Package validator -================ +================= [![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.4.1-green.svg) +![Project status](https://img.shields.io/badge/version-10.7.0-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) @@ -27,11 +27,11 @@ Use go get. - go get github.com/go-playground/validator/v10 + go get github.com/go-playground/validator Then import the validator package into your own code. - import "github.com/go-playground/validator/v10" + import "github.com/go-playground/validator" Error Return Value ------- @@ -43,7 +43,7 @@ * http://stackoverflow.com/a/29138676/3158232 * https://github.com/go-playground/validator/issues/134 -Validator only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: +Validator returns only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so: ```go err := validate.Struct(mystruct) @@ -53,7 +53,7 @@ Usage and documentation ------ -Please see https://godoc.org/github.com/go-playground/validator for detailed usage docs. +Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs. ##### Examples: @@ -295,5 +295,10 @@ Make a pull request... License ------- +------- Distributed under MIT License, please see license file within the code for more details. + +Maintainers +----------- +This project has grown large enough that more than one person is required to properly support the community. +If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn diff --git a/_examples/map-validation/main.go b/_examples/map-validation/main.go new file mode 100644 index 0000000..92e282f --- /dev/null +++ b/_examples/map-validation/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "fmt" + "github.com/go-playground/validator/v10" +) + +var validate *validator.Validate + +func main() { + validate = validator.New() + + validateMap() + validateNestedMap() +} + +func validateMap() { + user := map[string]interface{}{"name": "Arshiya Kiani", "email": "zytel3301@gmail.com"} + + // Every rule will be applied to the item of the data that the offset of rule is pointing to. + // So if you have a field "email": "omitempty,required,email", the validator will apply these + // rules to offset of email in user data + rules := map[string]interface{}{"name": "required,min=8,max=32", "email": "omitempty,required,email"} + + // ValidateMap will return map[string]error. + // The offset of every item in errs is the name of invalid field and the value + // is the message of error. If there was no error, ValidateMap method will + // return an EMPTY map of errors, not nil. If you want to check that + // if there was an error or not, you must check the length of the return value + errs := validate.ValidateMap(user, rules) + + if len(errs) > 0 { + fmt.Println(errs) + // The user is invalid + } + + // The user is valid +} + +func validateNestedMap() { + + data := map[string]interface{}{ + "name": "Arshiya Kiani", + "email": "zytel3301@gmail.com", + "details": map[string]interface{}{ + "family_members": map[string]interface{}{ + "father_name": "Micheal", + "mother_name": "Hannah", + }, + "salary": "1000", + }, + } + + // Rules must be set as the structure as the data itself. If you want to dive into the + // map, just declare its rules as a map + rules := map[string]interface{}{ + "name": "min=4,max=32", + "email": "required,email", + "details": map[string]interface{}{ + "family_members": map[string]interface{}{ + "father_name": "required,min=4,max=32", + "mother_name": "required,min=4,max=32", + }, + "salary": "number", + }, + } + + if len(validate.ValidateMap(data, rules)) == 0 { + // Data is valid + } + + // Data is invalid +} diff --git a/_examples/struct-level/main.go b/_examples/struct-level/main.go index 3231a81..6002a3b 100644 --- a/_examples/struct-level/main.go +++ b/_examples/struct-level/main.go @@ -44,7 +44,7 @@ // register validation for 'User' // NOTE: only have to register a non-pointer type for 'User', validator - // interanlly dereferences during it's type checks. + // internally dereferences during it's type checks. validate.RegisterStructValidation(UserStructLevelValidation, User{}) // build 'User' info, normally posted data etc... diff --git a/baked_in.go b/baked_in.go index 6ce762d..224a1c2 100644 --- a/baked_in.go +++ b/baked_in.go @@ -18,6 +18,7 @@ "unicode/utf8" "golang.org/x/crypto/sha3" + "golang.org/x/text/language" urn "github.com/leodido/go-urn" ) @@ -67,127 +68,132 @@ // you can add, remove or even replace items to suite your needs, // or even disregard and use your own map if so desired. bakedInValidators = map[string]Func{ - "required": hasValue, - "required_if": requiredIf, - "required_unless": requiredUnless, - "required_with": requiredWith, - "required_with_all": requiredWithAll, - "required_without": requiredWithout, - "required_without_all": requiredWithoutAll, - "excluded_with": excludedWith, - "excluded_with_all": excludedWithAll, - "excluded_without": excludedWithout, - "excluded_without_all": excludedWithoutAll, - "isdefault": isDefault, - "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, - "eq": isEq, - "ne": isNe, - "lt": isLt, - "lte": isLte, - "gt": isGt, - "gte": isGte, - "eqfield": isEqField, - "eqcsfield": isEqCrossStructField, - "necsfield": isNeCrossStructField, - "gtcsfield": isGtCrossStructField, - "gtecsfield": isGteCrossStructField, - "ltcsfield": isLtCrossStructField, - "ltecsfield": isLteCrossStructField, - "nefield": isNeField, - "gtefield": isGteField, - "gtfield": isGtField, - "ltefield": isLteField, - "ltfield": isLtField, - "fieldcontains": fieldContains, - "fieldexcludes": fieldExcludes, - "alpha": isAlpha, - "alphanum": isAlphanum, - "alphaunicode": isAlphaUnicode, - "alphanumunicode": isAlphanumUnicode, - "numeric": isNumeric, - "number": isNumber, - "hexadecimal": isHexadecimal, - "hexcolor": isHEXColor, - "rgb": isRGB, - "rgba": isRGBA, - "hsl": isHSL, - "hsla": isHSLA, - "e164": isE164, - "email": isEmail, - "url": isURL, - "uri": isURI, - "urn_rfc2141": isUrnRFC2141, // RFC 2141 - "file": isFile, - "base64": isBase64, - "base64url": isBase64URL, - "contains": contains, - "containsany": containsAny, - "containsrune": containsRune, - "excludes": excludes, - "excludesall": excludesAll, - "excludesrune": excludesRune, - "startswith": startsWith, - "endswith": endsWith, - "startsnotwith": startsNotWith, - "endsnotwith": endsNotWith, - "isbn": isISBN, - "isbn10": isISBN10, - "isbn13": isISBN13, - "eth_addr": isEthereumAddress, - "btc_addr": isBitcoinAddress, - "btc_addr_bech32": isBitcoinBech32Address, - "uuid": isUUID, - "uuid3": isUUID3, - "uuid4": isUUID4, - "uuid5": isUUID5, - "uuid_rfc4122": isUUIDRFC4122, - "uuid3_rfc4122": isUUID3RFC4122, - "uuid4_rfc4122": isUUID4RFC4122, - "uuid5_rfc4122": isUUID5RFC4122, - "ascii": isASCII, - "printascii": isPrintableASCII, - "multibyte": hasMultiByteCharacter, - "datauri": isDataURI, - "latitude": isLatitude, - "longitude": isLongitude, - "ssn": isSSN, - "ipv4": isIPv4, - "ipv6": isIPv6, - "ip": isIP, - "cidrv4": isCIDRv4, - "cidrv6": isCIDRv6, - "cidr": isCIDR, - "tcp4_addr": isTCP4AddrResolvable, - "tcp6_addr": isTCP6AddrResolvable, - "tcp_addr": isTCPAddrResolvable, - "udp4_addr": isUDP4AddrResolvable, - "udp6_addr": isUDP6AddrResolvable, - "udp_addr": isUDPAddrResolvable, - "ip4_addr": isIP4AddrResolvable, - "ip6_addr": isIP6AddrResolvable, - "ip_addr": isIPAddrResolvable, - "unix_addr": isUnixAddrResolvable, - "mac": isMAC, - "hostname": isHostnameRFC952, // RFC 952 - "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 - "fqdn": isFQDN, - "unique": isUnique, - "oneof": isOneOf, - "html": isHTML, - "html_encoded": isHTMLEncoded, - "url_encoded": isURLEncoded, - "dir": isDir, - "json": isJSON, - "hostname_port": isHostnamePort, - "lowercase": isLowercase, - "uppercase": isUppercase, - "datetime": isDatetime, - "timezone": isTimeZone, - "iso3166_1_alpha2": isIso3166Alpha2, - "iso3166_1_alpha3": isIso3166Alpha3, - "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, + "required": hasValue, + "required_if": requiredIf, + "required_unless": requiredUnless, + "required_with": requiredWith, + "required_with_all": requiredWithAll, + "required_without": requiredWithout, + "required_without_all": requiredWithoutAll, + "excluded_with": excludedWith, + "excluded_with_all": excludedWithAll, + "excluded_without": excludedWithout, + "excluded_without_all": excludedWithoutAll, + "isdefault": isDefault, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, + "eq": isEq, + "ne": isNe, + "lt": isLt, + "lte": isLte, + "gt": isGt, + "gte": isGte, + "eqfield": isEqField, + "eqcsfield": isEqCrossStructField, + "necsfield": isNeCrossStructField, + "gtcsfield": isGtCrossStructField, + "gtecsfield": isGteCrossStructField, + "ltcsfield": isLtCrossStructField, + "ltecsfield": isLteCrossStructField, + "nefield": isNeField, + "gtefield": isGteField, + "gtfield": isGtField, + "ltefield": isLteField, + "ltfield": isLtField, + "fieldcontains": fieldContains, + "fieldexcludes": fieldExcludes, + "alpha": isAlpha, + "alphanum": isAlphanum, + "alphaunicode": isAlphaUnicode, + "alphanumunicode": isAlphanumUnicode, + "numeric": isNumeric, + "number": isNumber, + "hexadecimal": isHexadecimal, + "hexcolor": isHEXColor, + "rgb": isRGB, + "rgba": isRGBA, + "hsl": isHSL, + "hsla": isHSLA, + "e164": isE164, + "email": isEmail, + "url": isURL, + "uri": isURI, + "urn_rfc2141": isUrnRFC2141, // RFC 2141 + "file": isFile, + "base64": isBase64, + "base64url": isBase64URL, + "contains": contains, + "containsany": containsAny, + "containsrune": containsRune, + "excludes": excludes, + "excludesall": excludesAll, + "excludesrune": excludesRune, + "startswith": startsWith, + "endswith": endsWith, + "startsnotwith": startsNotWith, + "endsnotwith": endsNotWith, + "isbn": isISBN, + "isbn10": isISBN10, + "isbn13": isISBN13, + "eth_addr": isEthereumAddress, + "btc_addr": isBitcoinAddress, + "btc_addr_bech32": isBitcoinBech32Address, + "uuid": isUUID, + "uuid3": isUUID3, + "uuid4": isUUID4, + "uuid5": isUUID5, + "uuid_rfc4122": isUUIDRFC4122, + "uuid3_rfc4122": isUUID3RFC4122, + "uuid4_rfc4122": isUUID4RFC4122, + "uuid5_rfc4122": isUUID5RFC4122, + "ascii": isASCII, + "printascii": isPrintableASCII, + "multibyte": hasMultiByteCharacter, + "datauri": isDataURI, + "latitude": isLatitude, + "longitude": isLongitude, + "ssn": isSSN, + "ipv4": isIPv4, + "ipv6": isIPv6, + "ip": isIP, + "cidrv4": isCIDRv4, + "cidrv6": isCIDRv6, + "cidr": isCIDR, + "tcp4_addr": isTCP4AddrResolvable, + "tcp6_addr": isTCP6AddrResolvable, + "tcp_addr": isTCPAddrResolvable, + "udp4_addr": isUDP4AddrResolvable, + "udp6_addr": isUDP6AddrResolvable, + "udp_addr": isUDPAddrResolvable, + "ip4_addr": isIP4AddrResolvable, + "ip6_addr": isIP6AddrResolvable, + "ip_addr": isIPAddrResolvable, + "unix_addr": isUnixAddrResolvable, + "mac": isMAC, + "hostname": isHostnameRFC952, // RFC 952 + "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 + "fqdn": isFQDN, + "unique": isUnique, + "oneof": isOneOf, + "html": isHTML, + "html_encoded": isHTMLEncoded, + "url_encoded": isURLEncoded, + "dir": isDir, + "json": isJSON, + "hostname_port": isHostnamePort, + "lowercase": isLowercase, + "uppercase": isUppercase, + "datetime": isDatetime, + "timezone": isTimeZone, + "iso3166_1_alpha2": isIso3166Alpha2, + "iso3166_1_alpha3": isIso3166Alpha3, + "iso3166_1_alpha_numeric": isIso3166AlphaNumeric, + "iso3166_2": isIso31662, + "bcp47_language_tag": isBCP47LanguageTag, + "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2, + "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field, + "bic": isIsoBicFormat, } ) @@ -547,7 +553,7 @@ return false } - if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { + if ethAddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) { return true } @@ -791,6 +797,9 @@ case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) != int64(currentField.Len()) + case reflect.Bool: + return field.Bool() != currentField.Bool() + case reflect.Struct: fieldType := field.Type() @@ -1033,6 +1042,9 @@ case reflect.Slice, reflect.Map, reflect.Array: return int64(topField.Len()) != int64(field.Len()) + case reflect.Bool: + return topField.Bool() != field.Bool() + case reflect.Struct: fieldType := field.Type() @@ -1080,6 +1092,9 @@ case reflect.Slice, reflect.Map, reflect.Array: return int64(topField.Len()) == int64(field.Len()) + case reflect.Bool: + return topField.Bool() == field.Bool() + case reflect.Struct: fieldType := field.Type() @@ -1127,6 +1142,9 @@ case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) == int64(currentField.Len()) + case reflect.Bool: + return field.Bool() == currentField.Bool() + case reflect.Struct: fieldType := field.Type() @@ -1188,6 +1206,47 @@ } panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2 +// example: `postcode_iso3166_alpha2=US` +func isPostcodeByIso3166Alpha2(fl FieldLevel) bool { + field := fl.Field() + param := fl.Param() + + reg, found := postCodeRegexDict[param] + if !found { + return false + } + + return reg.MatchString(field.String()) +} + +// isPostcodeByIso3166Alpha2 validates by field which represents for a value of country code in iso 3166 alpha 2 +// example: `postcode_iso3166_alpha2_field=CountryCode` +func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool { + field := fl.Field() + params := parseOneOfParam2(fl.Param()) + + if len(params) != 1 { + return false + } + + currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0]) + if !found { + return false + } + + if kind != reflect.String { + panic(fmt.Sprintf("Bad field type %T", currentField.Interface())) + } + + reg, found := postCodeRegexDict[currentField.String()] + if !found { + return false + } + + return reg.MatchString(field.String()) } // IsBase64 is the validation function for validating if the current field's value is a valid base 64. @@ -1330,7 +1389,7 @@ // IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. func isHEXColor(fl FieldLevel) bool { - return hexcolorRegex.MatchString(fl.Field().String()) + return hexColorRegex.MatchString(fl.Field().String()) } // IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. @@ -1441,6 +1500,9 @@ case reflect.Slice, reflect.Map, reflect.Array: return int64(field.Len()) == asInt(value) + + case reflect.Bool: + return field.Bool() == asBool(value) } // default reflect.String: @@ -1544,7 +1606,7 @@ return true } -// RequiredWithoutAll is the validation function +// ExcludedWithoutAll is the validation function // The field under validation must not be present or is empty when all of the other specified fields are not present. func excludedWithoutAll(fl FieldLevel) bool { params := parseOneOfParam2(fl.Param()) @@ -2283,3 +2345,28 @@ } return iso3166_1_alpha_numeric[code] } + +// isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code. +func isIso31662(fl FieldLevel) bool { + val := fl.Field().String() + return iso3166_2[val] +} + +// isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse +func isBCP47LanguageTag(fl FieldLevel) bool { + field := fl.Field() + + if field.Kind() == reflect.String { + _, err := language.Parse(field.String()) + return err == nil + } + + panic(fmt.Sprintf("Bad field type %T", field.Interface())) +} + +// isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 +func isIsoBicFormat(fl FieldLevel) bool { + bicString := fl.Field().String() + + return bicRegex.MatchString(bicString) +} diff --git a/country_codes.go b/country_codes.go index ef81ead..0d9eda0 100644 --- a/country_codes.go +++ b/country_codes.go @@ -160,3 +160,973 @@ 704: true, 92: true, 850: true, 876: true, 732: true, 887: true, 894: true, 716: true, 248: true, } + +var iso3166_2 = map[string]bool{ + "AD-02" : true, "AD-03" : true, "AD-04" : true, "AD-05" : true, "AD-06" : true, + "AD-07" : true, "AD-08" : true, "AE-AJ" : true, "AE-AZ" : true, "AE-DU" : true, + "AE-FU" : true, "AE-RK" : true, "AE-SH" : true, "AE-UQ" : true, "AF-BAL" : true, + "AF-BAM" : true, "AF-BDG" : true, "AF-BDS" : true, "AF-BGL" : true, "AF-DAY" : true, + "AF-FRA" : true, "AF-FYB" : true, "AF-GHA" : true, "AF-GHO" : true, "AF-HEL" : true, + "AF-HER" : true, "AF-JOW" : true, "AF-KAB" : true, "AF-KAN" : true, "AF-KAP" : true, + "AF-KDZ" : true, "AF-KHO" : true, "AF-KNR" : true, "AF-LAG" : true, "AF-LOG" : true, + "AF-NAN" : true, "AF-NIM" : true, "AF-NUR" : true, "AF-PAN" : true, "AF-PAR" : true, + "AF-PIA" : true, "AF-PKA" : true, "AF-SAM" : true, "AF-SAR" : true, "AF-TAK" : true, + "AF-URU" : true, "AF-WAR" : true, "AF-ZAB" : true, "AG-03" : true, "AG-04" : true, + "AG-05" : true, "AG-06" : true, "AG-07" : true, "AG-08" : true, "AG-10" : true, + "AG-11" : true, "AL-01" : true, "AL-02" : true, "AL-03" : true, "AL-04" : true, + "AL-05" : true, "AL-06" : true, "AL-07" : true, "AL-08" : true, "AL-09" : true, + "AL-10" : true, "AL-11" : true, "AL-12" : true, "AL-BR" : true, "AL-BU" : true, + "AL-DI" : true, "AL-DL" : true, "AL-DR" : true, "AL-DV" : true, "AL-EL" : true, + "AL-ER" : true, "AL-FR" : true, "AL-GJ" : true, "AL-GR" : true, "AL-HA" : true, + "AL-KA" : true, "AL-KB" : true, "AL-KC" : true, "AL-KO" : true, "AL-KR" : true, + "AL-KU" : true, "AL-LB" : true, "AL-LE" : true, "AL-LU" : true, "AL-MK" : true, + "AL-MM" : true, "AL-MR" : true, "AL-MT" : true, "AL-PG" : true, "AL-PQ" : true, + "AL-PR" : true, "AL-PU" : true, "AL-SH" : true, "AL-SK" : true, "AL-SR" : true, + "AL-TE" : true, "AL-TP" : true, "AL-TR" : true, "AL-VL" : true, "AM-AG" : true, + "AM-AR" : true, "AM-AV" : true, "AM-ER" : true, "AM-GR" : true, "AM-KT" : true, + "AM-LO" : true, "AM-SH" : true, "AM-SU" : true, "AM-TV" : true, "AM-VD" : true, + "AO-BGO" : true, "AO-BGU" : true, "AO-BIE" : true, "AO-CAB" : true, "AO-CCU" : true, + "AO-CNN" : true, "AO-CNO" : true, "AO-CUS" : true, "AO-HUA" : true, "AO-HUI" : true, + "AO-LNO" : true, "AO-LSU" : true, "AO-LUA" : true, "AO-MAL" : true, "AO-MOX" : true, + "AO-NAM" : true, "AO-UIG" : true, "AO-ZAI" : true, "AR-A" : true, "AR-B" : true, + "AR-C" : true, "AR-D" : true, "AR-E" : true, "AR-G" : true, "AR-H" : true, + "AR-J" : true, "AR-K" : true, "AR-L" : true, "AR-M" : true, "AR-N" : true, + "AR-P" : true, "AR-Q" : true, "AR-R" : true, "AR-S" : true, "AR-T" : true, + "AR-U" : true, "AR-V" : true, "AR-W" : true, "AR-X" : true, "AR-Y" : true, + "AR-Z" : true, "AT-1" : true, "AT-2" : true, "AT-3" : true, "AT-4" : true, + "AT-5" : true, "AT-6" : true, "AT-7" : true, "AT-8" : true, "AT-9" : true, + "AU-ACT" : true, "AU-NSW" : true, "AU-NT" : true, "AU-QLD" : true, "AU-SA" : true, + "AU-TAS" : true, "AU-VIC" : true, "AU-WA" : true, "AZ-ABS" : true, "AZ-AGA" : true, + "AZ-AGC" : true, "AZ-AGM" : true, "AZ-AGS" : true, "AZ-AGU" : true, "AZ-AST" : true, + "AZ-BA" : true, "AZ-BAB" : true, "AZ-BAL" : true, "AZ-BAR" : true, "AZ-BEY" : true, + "AZ-BIL" : true, "AZ-CAB" : true, "AZ-CAL" : true, "AZ-CUL" : true, "AZ-DAS" : true, + "AZ-FUZ" : true, "AZ-GA" : true, "AZ-GAD" : true, "AZ-GOR" : true, "AZ-GOY" : true, + "AZ-GYG" : true, "AZ-HAC" : true, "AZ-IMI" : true, "AZ-ISM" : true, "AZ-KAL" : true, + "AZ-KAN" : true, "AZ-KUR" : true, "AZ-LA" : true, "AZ-LAC" : true, "AZ-LAN" : true, + "AZ-LER" : true, "AZ-MAS" : true, "AZ-MI" : true, "AZ-NA" : true, "AZ-NEF" : true, + "AZ-NV" : true, "AZ-NX" : true, "AZ-OGU" : true, "AZ-ORD" : true, "AZ-QAB" : true, + "AZ-QAX" : true, "AZ-QAZ" : true, "AZ-QBA" : true, "AZ-QBI" : true, "AZ-QOB" : true, + "AZ-QUS" : true, "AZ-SA" : true, "AZ-SAB" : true, "AZ-SAD" : true, "AZ-SAH" : true, + "AZ-SAK" : true, "AZ-SAL" : true, "AZ-SAR" : true, "AZ-SAT" : true, "AZ-SBN" : true, + "AZ-SIY" : true, "AZ-SKR" : true, "AZ-SM" : true, "AZ-SMI" : true, "AZ-SMX" : true, + "AZ-SR" : true, "AZ-SUS" : true, "AZ-TAR" : true, "AZ-TOV" : true, "AZ-UCA" : true, + "AZ-XA" : true, "AZ-XAC" : true, "AZ-XCI" : true, "AZ-XIZ" : true, "AZ-XVD" : true, + "AZ-YAR" : true, "AZ-YE" : true, "AZ-YEV" : true, "AZ-ZAN" : true, "AZ-ZAQ" : true, + "AZ-ZAR" : true, "BA-01" : true, "BA-02" : true, "BA-03" : true, "BA-04" : true, + "BA-05" : true, "BA-06" : true, "BA-07" : true, "BA-08" : true, "BA-09" : true, + "BA-10" : true, "BA-BIH" : true, "BA-BRC" : true, "BA-SRP" : true, "BB-01" : true, + "BB-02" : true, "BB-03" : true, "BB-04" : true, "BB-05" : true, "BB-06" : true, + "BB-07" : true, "BB-08" : true, "BB-09" : true, "BB-10" : true, "BB-11" : true, + "BD-01" : true, "BD-02" : true, "BD-03" : true, "BD-04" : true, "BD-05" : true, + "BD-06" : true, "BD-07" : true, "BD-08" : true, "BD-09" : true, "BD-10" : true, + "BD-11" : true, "BD-12" : true, "BD-13" : true, "BD-14" : true, "BD-15" : true, + "BD-16" : true, "BD-17" : true, "BD-18" : true, "BD-19" : true, "BD-20" : true, + "BD-21" : true, "BD-22" : true, "BD-23" : true, "BD-24" : true, "BD-25" : true, + "BD-26" : true, "BD-27" : true, "BD-28" : true, "BD-29" : true, "BD-30" : true, + "BD-31" : true, "BD-32" : true, "BD-33" : true, "BD-34" : true, "BD-35" : true, + "BD-36" : true, "BD-37" : true, "BD-38" : true, "BD-39" : true, "BD-40" : true, + "BD-41" : true, "BD-42" : true, "BD-43" : true, "BD-44" : true, "BD-45" : true, + "BD-46" : true, "BD-47" : true, "BD-48" : true, "BD-49" : true, "BD-50" : true, + "BD-51" : true, "BD-52" : true, "BD-53" : true, "BD-54" : true, "BD-55" : true, + "BD-56" : true, "BD-57" : true, "BD-58" : true, "BD-59" : true, "BD-60" : true, + "BD-61" : true, "BD-62" : true, "BD-63" : true, "BD-64" : true, "BD-A" : true, + "BD-B" : true, "BD-C" : true, "BD-D" : true, "BD-E" : true, "BD-F" : true, + "BD-G" : true, "BE-BRU" : true, "BE-VAN" : true, "BE-VBR" : true, "BE-VLG" : true, + "BE-VLI" : true, "BE-VOV" : true, "BE-VWV" : true, "BE-WAL" : true, "BE-WBR" : true, + "BE-WHT" : true, "BE-WLG" : true, "BE-WLX" : true, "BE-WNA" : true, "BF-01" : true, + "BF-02" : true, "BF-03" : true, "BF-04" : true, "BF-05" : true, "BF-06" : true, + "BF-07" : true, "BF-08" : true, "BF-09" : true, "BF-10" : true, "BF-11" : true, + "BF-12" : true, "BF-13" : true, "BF-BAL" : true, "BF-BAM" : true, "BF-BAN" : true, + "BF-BAZ" : true, "BF-BGR" : true, "BF-BLG" : true, "BF-BLK" : true, "BF-COM" : true, + "BF-GAN" : true, "BF-GNA" : true, "BF-GOU" : true, "BF-HOU" : true, "BF-IOB" : true, + "BF-KAD" : true, "BF-KEN" : true, "BF-KMD" : true, "BF-KMP" : true, "BF-KOP" : true, + "BF-KOS" : true, "BF-KOT" : true, "BF-KOW" : true, "BF-LER" : true, "BF-LOR" : true, + "BF-MOU" : true, "BF-NAM" : true, "BF-NAO" : true, "BF-NAY" : true, "BF-NOU" : true, + "BF-OUB" : true, "BF-OUD" : true, "BF-PAS" : true, "BF-PON" : true, "BF-SEN" : true, + "BF-SIS" : true, "BF-SMT" : true, "BF-SNG" : true, "BF-SOM" : true, "BF-SOR" : true, + "BF-TAP" : true, "BF-TUI" : true, "BF-YAG" : true, "BF-YAT" : true, "BF-ZIR" : true, + "BF-ZON" : true, "BF-ZOU" : true, "BG-01" : true, "BG-02" : true, "BG-03" : true, + "BG-04" : true, "BG-05" : true, "BG-06" : true, "BG-07" : true, "BG-08" : true, + "BG-09" : true, "BG-10" : true, "BG-11" : true, "BG-12" : true, "BG-13" : true, + "BG-14" : true, "BG-15" : true, "BG-16" : true, "BG-17" : true, "BG-18" : true, + "BG-19" : true, "BG-20" : true, "BG-21" : true, "BG-22" : true, "BG-23" : true, + "BG-24" : true, "BG-25" : true, "BG-26" : true, "BG-27" : true, "BG-28" : true, + "BH-13" : true, "BH-14" : true, "BH-15" : true, "BH-16" : true, "BH-17" : true, + "BI-BB" : true, "BI-BL" : true, "BI-BM" : true, "BI-BR" : true, "BI-CA" : true, + "BI-CI" : true, "BI-GI" : true, "BI-KI" : true, "BI-KR" : true, "BI-KY" : true, + "BI-MA" : true, "BI-MU" : true, "BI-MW" : true, "BI-NG" : true, "BI-RT" : true, + "BI-RY" : true, "BJ-AK" : true, "BJ-AL" : true, "BJ-AQ" : true, "BJ-BO" : true, + "BJ-CO" : true, "BJ-DO" : true, "BJ-KO" : true, "BJ-LI" : true, "BJ-MO" : true, + "BJ-OU" : true, "BJ-PL" : true, "BJ-ZO" : true, "BN-BE" : true, "BN-BM" : true, + "BN-TE" : true, "BN-TU" : true, "BO-B" : true, "BO-C" : true, "BO-H" : true, + "BO-L" : true, "BO-N" : true, "BO-O" : true, "BO-P" : true, "BO-S" : true, + "BO-T" : true, "BQ-BO" : true, "BQ-SA" : true, "BQ-SE" : true, "BR-AC" : true, + "BR-AL" : true, "BR-AM" : true, "BR-AP" : true, "BR-BA" : true, "BR-CE" : true, + "BR-DF" : true, "BR-ES" : true, "BR-FN" : true, "BR-GO" : true, "BR-MA" : true, + "BR-MG" : true, "BR-MS" : true, "BR-MT" : true, "BR-PA" : true, "BR-PB" : true, + "BR-PE" : true, "BR-PI" : true, "BR-PR" : true, "BR-RJ" : true, "BR-RN" : true, + "BR-RO" : true, "BR-RR" : true, "BR-RS" : true, "BR-SC" : true, "BR-SE" : true, + "BR-SP" : true, "BR-TO" : true, "BS-AK" : true, "BS-BI" : true, "BS-BP" : true, + "BS-BY" : true, "BS-CE" : true, "BS-CI" : true, "BS-CK" : true, "BS-CO" : true, + "BS-CS" : true, "BS-EG" : true, "BS-EX" : true, "BS-FP" : true, "BS-GC" : true, + "BS-HI" : true, "BS-HT" : true, "BS-IN" : true, "BS-LI" : true, "BS-MC" : true, + "BS-MG" : true, "BS-MI" : true, "BS-NE" : true, "BS-NO" : true, "BS-NS" : true, + "BS-RC" : true, "BS-RI" : true, "BS-SA" : true, "BS-SE" : true, "BS-SO" : true, + "BS-SS" : true, "BS-SW" : true, "BS-WG" : true, "BT-11" : true, "BT-12" : true, + "BT-13" : true, "BT-14" : true, "BT-15" : true, "BT-21" : true, "BT-22" : true, + "BT-23" : true, "BT-24" : true, "BT-31" : true, "BT-32" : true, "BT-33" : true, + "BT-34" : true, "BT-41" : true, "BT-42" : true, "BT-43" : true, "BT-44" : true, + "BT-45" : true, "BT-GA" : true, "BT-TY" : true, "BW-CE" : true, "BW-GH" : true, + "BW-KG" : true, "BW-KL" : true, "BW-KW" : true, "BW-NE" : true, "BW-NW" : true, + "BW-SE" : true, "BW-SO" : true, "BY-BR" : true, "BY-HM" : true, "BY-HO" : true, + "BY-HR" : true, "BY-MA" : true, "BY-MI" : true, "BY-VI" : true, "BZ-BZ" : true, + "BZ-CY" : true, "BZ-CZL" : true, "BZ-OW" : true, "BZ-SC" : true, "BZ-TOL" : true, + "CA-AB" : true, "CA-BC" : true, "CA-MB" : true, "CA-NB" : true, "CA-NL" : true, + "CA-NS" : true, "CA-NT" : true, "CA-NU" : true, "CA-ON" : true, "CA-PE" : true, + "CA-QC" : true, "CA-SK" : true, "CA-YT" : true, "CD-BC" : true, "CD-BN" : true, + "CD-EQ" : true, "CD-KA" : true, "CD-KE" : true, "CD-KN" : true, "CD-KW" : true, + "CD-MA" : true, "CD-NK" : true, "CD-OR" : true, "CD-SK" : true, "CF-AC" : true, + "CF-BB" : true, "CF-BGF" : true, "CF-BK" : true, "CF-HK" : true, "CF-HM" : true, + "CF-HS" : true, "CF-KB" : true, "CF-KG" : true, "CF-LB" : true, "CF-MB" : true, + "CF-MP" : true, "CF-NM" : true, "CF-OP" : true, "CF-SE" : true, "CF-UK" : true, + "CF-VK" : true, "CG-11" : true, "CG-12" : true, "CG-13" : true, "CG-14" : true, + "CG-15" : true, "CG-2" : true, "CG-5" : true, "CG-7" : true, "CG-8" : true, + "CG-9" : true, "CG-BZV" : true, "CH-AG" : true, "CH-AI" : true, "CH-AR" : true, + "CH-BE" : true, "CH-BL" : true, "CH-BS" : true, "CH-FR" : true, "CH-GE" : true, + "CH-GL" : true, "CH-GR" : true, "CH-JU" : true, "CH-LU" : true, "CH-NE" : true, + "CH-NW" : true, "CH-OW" : true, "CH-SG" : true, "CH-SH" : true, "CH-SO" : true, + "CH-SZ" : true, "CH-TG" : true, "CH-TI" : true, "CH-UR" : true, "CH-VD" : true, + "CH-VS" : true, "CH-ZG" : true, "CH-ZH" : true, "CI-01" : true, "CI-02" : true, + "CI-03" : true, "CI-04" : true, "CI-05" : true, "CI-06" : true, "CI-07" : true, + "CI-08" : true, "CI-09" : true, "CI-10" : true, "CI-11" : true, "CI-12" : true, + "CI-13" : true, "CI-14" : true, "CI-15" : true, "CI-16" : true, "CI-17" : true, + "CI-18" : true, "CI-19" : true, "CL-AI" : true, "CL-AN" : true, "CL-AP" : true, + "CL-AR" : true, "CL-AT" : true, "CL-BI" : true, "CL-CO" : true, "CL-LI" : true, + "CL-LL" : true, "CL-LR" : true, "CL-MA" : true, "CL-ML" : true, "CL-RM" : true, + "CL-TA" : true, "CL-VS" : true, "CM-AD" : true, "CM-CE" : true, "CM-EN" : true, + "CM-ES" : true, "CM-LT" : true, "CM-NO" : true, "CM-NW" : true, "CM-OU" : true, + "CM-SU" : true, "CM-SW" : true, "CN-11" : true, "CN-12" : true, "CN-13" : true, + "CN-14" : true, "CN-15" : true, "CN-21" : true, "CN-22" : true, "CN-23" : true, + "CN-31" : true, "CN-32" : true, "CN-33" : true, "CN-34" : true, "CN-35" : true, + "CN-36" : true, "CN-37" : true, "CN-41" : true, "CN-42" : true, "CN-43" : true, + "CN-44" : true, "CN-45" : true, "CN-46" : true, "CN-50" : true, "CN-51" : true, + "CN-52" : true, "CN-53" : true, "CN-54" : true, "CN-61" : true, "CN-62" : true, + "CN-63" : true, "CN-64" : true, "CN-65" : true, "CN-71" : true, "CN-91" : true, + "CN-92" : true, "CO-AMA" : true, "CO-ANT" : true, "CO-ARA" : true, "CO-ATL" : true, + "CO-BOL" : true, "CO-BOY" : true, "CO-CAL" : true, "CO-CAQ" : true, "CO-CAS" : true, + "CO-CAU" : true, "CO-CES" : true, "CO-CHO" : true, "CO-COR" : true, "CO-CUN" : true, + "CO-DC" : true, "CO-GUA" : true, "CO-GUV" : true, "CO-HUI" : true, "CO-LAG" : true, + "CO-MAG" : true, "CO-MET" : true, "CO-NAR" : true, "CO-NSA" : true, "CO-PUT" : true, + "CO-QUI" : true, "CO-RIS" : true, "CO-SAN" : true, "CO-SAP" : true, "CO-SUC" : true, + "CO-TOL" : true, "CO-VAC" : true, "CO-VAU" : true, "CO-VID" : true, "CR-A" : true, + "CR-C" : true, "CR-G" : true, "CR-H" : true, "CR-L" : true, "CR-P" : true, + "CR-SJ" : true, "CU-01" : true, "CU-02" : true, "CU-03" : true, "CU-04" : true, + "CU-05" : true, "CU-06" : true, "CU-07" : true, "CU-08" : true, "CU-09" : true, + "CU-10" : true, "CU-11" : true, "CU-12" : true, "CU-13" : true, "CU-14" : true, + "CU-99" : true, "CV-B" : true, "CV-BR" : true, "CV-BV" : true, "CV-CA" : true, + "CV-CF" : true, "CV-CR" : true, "CV-MA" : true, "CV-MO" : true, "CV-PA" : true, + "CV-PN" : true, "CV-PR" : true, "CV-RB" : true, "CV-RG" : true, "CV-RS" : true, + "CV-S" : true, "CV-SD" : true, "CV-SF" : true, "CV-SL" : true, "CV-SM" : true, + "CV-SO" : true, "CV-SS" : true, "CV-SV" : true, "CV-TA" : true, "CV-TS" : true, + "CY-01" : true, "CY-02" : true, "CY-03" : true, "CY-04" : true, "CY-05" : true, + "CY-06" : true, "CZ-10" : true, "CZ-101" : true, "CZ-102" : true, "CZ-103" : true, + "CZ-104" : true, "CZ-105" : true, "CZ-106" : true, "CZ-107" : true, "CZ-108" : true, + "CZ-109" : true, "CZ-110" : true, "CZ-111" : true, "CZ-112" : true, "CZ-113" : true, + "CZ-114" : true, "CZ-115" : true, "CZ-116" : true, "CZ-117" : true, "CZ-118" : true, + "CZ-119" : true, "CZ-120" : true, "CZ-121" : true, "CZ-122" : true, "CZ-20" : true, + "CZ-201" : true, "CZ-202" : true, "CZ-203" : true, "CZ-204" : true, "CZ-205" : true, + "CZ-206" : true, "CZ-207" : true, "CZ-208" : true, "CZ-209" : true, "CZ-20A" : true, + "CZ-20B" : true, "CZ-20C" : true, "CZ-31" : true, "CZ-311" : true, "CZ-312" : true, + "CZ-313" : true, "CZ-314" : true, "CZ-315" : true, "CZ-316" : true, "CZ-317" : true, + "CZ-32" : true, "CZ-321" : true, "CZ-322" : true, "CZ-323" : true, "CZ-324" : true, + "CZ-325" : true, "CZ-326" : true, "CZ-327" : true, "CZ-41" : true, "CZ-411" : true, + "CZ-412" : true, "CZ-413" : true, "CZ-42" : true, "CZ-421" : true, "CZ-422" : true, + "CZ-423" : true, "CZ-424" : true, "CZ-425" : true, "CZ-426" : true, "CZ-427" : true, + "CZ-51" : true, "CZ-511" : true, "CZ-512" : true, "CZ-513" : true, "CZ-514" : true, + "CZ-52" : true, "CZ-521" : true, "CZ-522" : true, "CZ-523" : true, "CZ-524" : true, + "CZ-525" : true, "CZ-53" : true, "CZ-531" : true, "CZ-532" : true, "CZ-533" : true, + "CZ-534" : true, "CZ-63" : true, "CZ-631" : true, "CZ-632" : true, "CZ-633" : true, + "CZ-634" : true, "CZ-635" : true, "CZ-64" : true, "CZ-641" : true, "CZ-642" : true, + "CZ-643" : true, "CZ-644" : true, "CZ-645" : true, "CZ-646" : true, "CZ-647" : true, + "CZ-71" : true, "CZ-711" : true, "CZ-712" : true, "CZ-713" : true, "CZ-714" : true, + "CZ-715" : true, "CZ-72" : true, "CZ-721" : true, "CZ-722" : true, "CZ-723" : true, + "CZ-724" : true, "CZ-80" : true, "CZ-801" : true, "CZ-802" : true, "CZ-803" : true, + "CZ-804" : true, "CZ-805" : true, "CZ-806" : true, "DE-BB" : true, "DE-BE" : true, + "DE-BW" : true, "DE-BY" : true, "DE-HB" : true, "DE-HE" : true, "DE-HH" : true, + "DE-MV" : true, "DE-NI" : true, "DE-NW" : true, "DE-RP" : true, "DE-SH" : true, + "DE-SL" : true, "DE-SN" : true, "DE-ST" : true, "DE-TH" : true, "DJ-AR" : true, + "DJ-AS" : true, "DJ-DI" : true, "DJ-DJ" : true, "DJ-OB" : true, "DJ-TA" : true, + "DK-81" : true, "DK-82" : true, "DK-83" : true, "DK-84" : true, "DK-85" : true, + "DM-01" : true, "DM-02" : true, "DM-03" : true, "DM-04" : true, "DM-05" : true, + "DM-06" : true, "DM-07" : true, "DM-08" : true, "DM-09" : true, "DM-10" : true, + "DO-01" : true, "DO-02" : true, "DO-03" : true, "DO-04" : true, "DO-05" : true, + "DO-06" : true, "DO-07" : true, "DO-08" : true, "DO-09" : true, "DO-10" : true, + "DO-11" : true, "DO-12" : true, "DO-13" : true, "DO-14" : true, "DO-15" : true, + "DO-16" : true, "DO-17" : true, "DO-18" : true, "DO-19" : true, "DO-20" : true, + "DO-21" : true, "DO-22" : true, "DO-23" : true, "DO-24" : true, "DO-25" : true, + "DO-26" : true, "DO-27" : true, "DO-28" : true, "DO-29" : true, "DO-30" : true, + "DZ-01" : true, "DZ-02" : true, "DZ-03" : true, "DZ-04" : true, "DZ-05" : true, + "DZ-06" : true, "DZ-07" : true, "DZ-08" : true, "DZ-09" : true, "DZ-10" : true, + "DZ-11" : true, "DZ-12" : true, "DZ-13" : true, "DZ-14" : true, "DZ-15" : true, + "DZ-16" : true, "DZ-17" : true, "DZ-18" : true, "DZ-19" : true, "DZ-20" : true, + "DZ-21" : true, "DZ-22" : true, "DZ-23" : true, "DZ-24" : true, "DZ-25" : true, + "DZ-26" : true, "DZ-27" : true, "DZ-28" : true, "DZ-29" : true, "DZ-30" : true, + "DZ-31" : true, "DZ-32" : true, "DZ-33" : true, "DZ-34" : true, "DZ-35" : true, + "DZ-36" : true, "DZ-37" : true, "DZ-38" : true, "DZ-39" : true, "DZ-40" : true, + "DZ-41" : true, "DZ-42" : true, "DZ-43" : true, "DZ-44" : true, "DZ-45" : true, + "DZ-46" : true, "DZ-47" : true, "DZ-48" : true, "EC-A" : true, "EC-B" : true, + "EC-C" : true, "EC-D" : true, "EC-E" : true, "EC-F" : true, "EC-G" : true, + "EC-H" : true, "EC-I" : true, "EC-L" : true, "EC-M" : true, "EC-N" : true, + "EC-O" : true, "EC-P" : true, "EC-R" : true, "EC-S" : true, "EC-SD" : true, + "EC-SE" : true, "EC-T" : true, "EC-U" : true, "EC-W" : true, "EC-X" : true, + "EC-Y" : true, "EC-Z" : true, "EE-37" : true, "EE-39" : true, "EE-44" : true, + "EE-49" : true, "EE-51" : true, "EE-57" : true, "EE-59" : true, "EE-65" : true, + "EE-67" : true, "EE-70" : true, "EE-74" : true, "EE-78" : true, "EE-82" : true, + "EE-84" : true, "EE-86" : true, "EG-ALX" : true, "EG-ASN" : true, "EG-AST" : true, + "EG-BA" : true, "EG-BH" : true, "EG-BNS" : true, "EG-C" : true, "EG-DK" : true, + "EG-DT" : true, "EG-FYM" : true, "EG-GH" : true, "EG-GZ" : true, "EG-HU" : true, + "EG-IS" : true, "EG-JS" : true, "EG-KB" : true, "EG-KFS" : true, "EG-KN" : true, + "EG-MN" : true, "EG-MNF" : true, "EG-MT" : true, "EG-PTS" : true, "EG-SHG" : true, + "EG-SHR" : true, "EG-SIN" : true, "EG-SU" : true, "EG-SUZ" : true, "EG-WAD" : true, + "ER-AN" : true, "ER-DK" : true, "ER-DU" : true, "ER-GB" : true, "ER-MA" : true, + "ER-SK" : true, "ES-A" : true, "ES-AB" : true, "ES-AL" : true, "ES-AN" : true, + "ES-AR" : true, "ES-AS" : true, "ES-AV" : true, "ES-B" : true, "ES-BA" : true, + "ES-BI" : true, "ES-BU" : true, "ES-C" : true, "ES-CA" : true, "ES-CB" : true, + "ES-CC" : true, "ES-CE" : true, "ES-CL" : true, "ES-CM" : true, "ES-CN" : true, + "ES-CO" : true, "ES-CR" : true, "ES-CS" : true, "ES-CT" : true, "ES-CU" : true, + "ES-EX" : true, "ES-GA" : true, "ES-GC" : true, "ES-GI" : true, "ES-GR" : true, + "ES-GU" : true, "ES-H" : true, "ES-HU" : true, "ES-IB" : true, "ES-J" : true, + "ES-L" : true, "ES-LE" : true, "ES-LO" : true, "ES-LU" : true, "ES-M" : true, + "ES-MA" : true, "ES-MC" : true, "ES-MD" : true, "ES-ML" : true, "ES-MU" : true, + "ES-NA" : true, "ES-NC" : true, "ES-O" : true, "ES-OR" : true, "ES-P" : true, + "ES-PM" : true, "ES-PO" : true, "ES-PV" : true, "ES-RI" : true, "ES-S" : true, + "ES-SA" : true, "ES-SE" : true, "ES-SG" : true, "ES-SO" : true, "ES-SS" : true, + "ES-T" : true, "ES-TE" : true, "ES-TF" : true, "ES-TO" : true, "ES-V" : true, + "ES-VA" : true, "ES-VC" : true, "ES-VI" : true, "ES-Z" : true, "ES-ZA" : true, + "ET-AA" : true, "ET-AF" : true, "ET-AM" : true, "ET-BE" : true, "ET-DD" : true, + "ET-GA" : true, "ET-HA" : true, "ET-OR" : true, "ET-SN" : true, "ET-SO" : true, + "ET-TI" : true, "FI-01" : true, "FI-02" : true, "FI-03" : true, "FI-04" : true, + "FI-05" : true, "FI-06" : true, "FI-07" : true, "FI-08" : true, "FI-09" : true, + "FI-10" : true, "FI-11" : true, "FI-12" : true, "FI-13" : true, "FI-14" : true, + "FI-15" : true, "FI-16" : true, "FI-17" : true, "FI-18" : true, "FI-19" : true, + "FJ-C" : true, "FJ-E" : true, "FJ-N" : true, "FJ-R" : true, "FJ-W" : true, + "FM-KSA" : true, "FM-PNI" : true, "FM-TRK" : true, "FM-YAP" : true, "FR-01" : true, + "FR-02" : true, "FR-03" : true, "FR-04" : true, "FR-05" : true, "FR-06" : true, + "FR-07" : true, "FR-08" : true, "FR-09" : true, "FR-10" : true, "FR-11" : true, + "FR-12" : true, "FR-13" : true, "FR-14" : true, "FR-15" : true, "FR-16" : true, + "FR-17" : true, "FR-18" : true, "FR-19" : true, "FR-21" : true, "FR-22" : true, + "FR-23" : true, "FR-24" : true, "FR-25" : true, "FR-26" : true, "FR-27" : true, + "FR-28" : true, "FR-29" : true, "FR-2A" : true, "FR-2B" : true, "FR-30" : true, + "FR-31" : true, "FR-32" : true, "FR-33" : true, "FR-34" : true, "FR-35" : true, + "FR-36" : true, "FR-37" : true, "FR-38" : true, "FR-39" : true, "FR-40" : true, + "FR-41" : true, "FR-42" : true, "FR-43" : true, "FR-44" : true, "FR-45" : true, + "FR-46" : true, "FR-47" : true, "FR-48" : true, "FR-49" : true, "FR-50" : true, + "FR-51" : true, "FR-52" : true, "FR-53" : true, "FR-54" : true, "FR-55" : true, + "FR-56" : true, "FR-57" : true, "FR-58" : true, "FR-59" : true, "FR-60" : true, + "FR-61" : true, "FR-62" : true, "FR-63" : true, "FR-64" : true, "FR-65" : true, + "FR-66" : true, "FR-67" : true, "FR-68" : true, "FR-69" : true, "FR-70" : true, + "FR-71" : true, "FR-72" : true, "FR-73" : true, "FR-74" : true, "FR-75" : true, + "FR-76" : true, "FR-77" : true, "FR-78" : true, "FR-79" : true, "FR-80" : true, + "FR-81" : true, "FR-82" : true, "FR-83" : true, "FR-84" : true, "FR-85" : true, + "FR-86" : true, "FR-87" : true, "FR-88" : true, "FR-89" : true, "FR-90" : true, + "FR-91" : true, "FR-92" : true, "FR-93" : true, "FR-94" : true, "FR-95" : true, + "FR-ARA" : true, "FR-BFC" : true, "FR-BL" : true, "FR-BRE" : true, "FR-COR" : true, + "FR-CP" : true, "FR-CVL" : true, "FR-GES" : true, "FR-GF" : true, "FR-GP" : true, + "FR-GUA" : true, "FR-HDF" : true, "FR-IDF" : true, "FR-LRE" : true, "FR-MAY" : true, + "FR-MF" : true, "FR-MQ" : true, "FR-NAQ" : true, "FR-NC" : true, "FR-NOR" : true, + "FR-OCC" : true, "FR-PAC" : true, "FR-PDL" : true, "FR-PF" : true, "FR-PM" : true, + "FR-RE" : true, "FR-TF" : true, "FR-WF" : true, "FR-YT" : true, "GA-1" : true, + "GA-2" : true, "GA-3" : true, "GA-4" : true, "GA-5" : true, "GA-6" : true, + "GA-7" : true, "GA-8" : true, "GA-9" : true, "GB-ABC" : true, "GB-ABD" : true, + "GB-ABE" : true, "GB-AGB" : true, "GB-AGY" : true, "GB-AND" : true, "GB-ANN" : true, + "GB-ANS" : true, "GB-BAS" : true, "GB-BBD" : true, "GB-BDF" : true, "GB-BDG" : true, + "GB-BEN" : true, "GB-BEX" : true, "GB-BFS" : true, "GB-BGE" : true, "GB-BGW" : true, + "GB-BIR" : true, "GB-BKM" : true, "GB-BMH" : true, "GB-BNE" : true, "GB-BNH" : true, + "GB-BNS" : true, "GB-BOL" : true, "GB-BPL" : true, "GB-BRC" : true, "GB-BRD" : true, + "GB-BRY" : true, "GB-BST" : true, "GB-BUR" : true, "GB-CAM" : true, "GB-CAY" : true, + "GB-CBF" : true, "GB-CCG" : true, "GB-CGN" : true, "GB-CHE" : true, "GB-CHW" : true, + "GB-CLD" : true, "GB-CLK" : true, "GB-CMA" : true, "GB-CMD" : true, "GB-CMN" : true, + "GB-CON" : true, "GB-COV" : true, "GB-CRF" : true, "GB-CRY" : true, "GB-CWY" : true, + "GB-DAL" : true, "GB-DBY" : true, "GB-DEN" : true, "GB-DER" : true, "GB-DEV" : true, + "GB-DGY" : true, "GB-DNC" : true, "GB-DND" : true, "GB-DOR" : true, "GB-DRS" : true, + "GB-DUD" : true, "GB-DUR" : true, "GB-EAL" : true, "GB-EAW" : true, "GB-EAY" : true, + "GB-EDH" : true, "GB-EDU" : true, "GB-ELN" : true, "GB-ELS" : true, "GB-ENF" : true, + "GB-ENG" : true, "GB-ERW" : true, "GB-ERY" : true, "GB-ESS" : true, "GB-ESX" : true, + "GB-FAL" : true, "GB-FIF" : true, "GB-FLN" : true, "GB-FMO" : true, "GB-GAT" : true, + "GB-GBN" : true, "GB-GLG" : true, "GB-GLS" : true, "GB-GRE" : true, "GB-GWN" : true, + "GB-HAL" : true, "GB-HAM" : true, "GB-HAV" : true, "GB-HCK" : true, "GB-HEF" : true, + "GB-HIL" : true, "GB-HLD" : true, "GB-HMF" : true, "GB-HNS" : true, "GB-HPL" : true, + "GB-HRT" : true, "GB-HRW" : true, "GB-HRY" : true, "GB-IOS" : true, "GB-IOW" : true, + "GB-ISL" : true, "GB-IVC" : true, "GB-KEC" : true, "GB-KEN" : true, "GB-KHL" : true, + "GB-KIR" : true, "GB-KTT" : true, "GB-KWL" : true, "GB-LAN" : true, "GB-LBC" : true, + "GB-LBH" : true, "GB-LCE" : true, "GB-LDS" : true, "GB-LEC" : true, "GB-LEW" : true, + "GB-LIN" : true, "GB-LIV" : true, "GB-LND" : true, "GB-LUT" : true, "GB-MAN" : true, + "GB-MDB" : true, "GB-MDW" : true, "GB-MEA" : true, "GB-MIK" : true, "GD-01" : true, + "GB-MLN" : true, "GB-MON" : true, "GB-MRT" : true, "GB-MRY" : true, "GB-MTY" : true, + "GB-MUL" : true, "GB-NAY" : true, "GB-NBL" : true, "GB-NEL" : true, "GB-NET" : true, + "GB-NFK" : true, "GB-NGM" : true, "GB-NIR" : true, "GB-NLK" : true, "GB-NLN" : true, + "GB-NMD" : true, "GB-NSM" : true, "GB-NTH" : true, "GB-NTL" : true, "GB-NTT" : true, + "GB-NTY" : true, "GB-NWM" : true, "GB-NWP" : true, "GB-NYK" : true, "GB-OLD" : true, + "GB-ORK" : true, "GB-OXF" : true, "GB-PEM" : true, "GB-PKN" : true, "GB-PLY" : true, + "GB-POL" : true, "GB-POR" : true, "GB-POW" : true, "GB-PTE" : true, "GB-RCC" : true, + "GB-RCH" : true, "GB-RCT" : true, "GB-RDB" : true, "GB-RDG" : true, "GB-RFW" : true, + "GB-RIC" : true, "GB-ROT" : true, "GB-RUT" : true, "GB-SAW" : true, "GB-SAY" : true, + "GB-SCB" : true, "GB-SCT" : true, "GB-SFK" : true, "GB-SFT" : true, "GB-SGC" : true, + "GB-SHF" : true, "GB-SHN" : true, "GB-SHR" : true, "GB-SKP" : true, "GB-SLF" : true, + "GB-SLG" : true, "GB-SLK" : true, "GB-SND" : true, "GB-SOL" : true, "GB-SOM" : true, + "GB-SOS" : true, "GB-SRY" : true, "GB-STE" : true, "GB-STG" : true, "GB-STH" : true, + "GB-STN" : true, "GB-STS" : true, "GB-STT" : true, "GB-STY" : true, "GB-SWA" : true, + "GB-SWD" : true, "GB-SWK" : true, "GB-TAM" : true, "GB-TFW" : true, "GB-THR" : true, + "GB-TOB" : true, "GB-TOF" : true, "GB-TRF" : true, "GB-TWH" : true, "GB-UKM" : true, + "GB-VGL" : true, "GB-WAR" : true, "GB-WBK" : true, "GB-WDU" : true, "GB-WFT" : true, + "GB-WGN" : true, "GB-WIL" : true, "GB-WKF" : true, "GB-WLL" : true, "GB-WLN" : true, + "GB-WLS" : true, "GB-WLV" : true, "GB-WND" : true, "GB-WNM" : true, "GB-WOK" : true, + "GB-WOR" : true, "GB-WRL" : true, "GB-WRT" : true, "GB-WRX" : true, "GB-WSM" : true, + "GB-WSX" : true, "GB-YOR" : true, "GB-ZET" : true, "GD-02" : true, "GD-03" : true, + "GD-04" : true, "GD-05" : true, "GD-06" : true, "GD-10" : true, "GE-AB" : true, + "GE-AJ" : true, "GE-GU" : true, "GE-IM" : true, "GE-KA" : true, "GE-KK" : true, + "GE-MM" : true, "GE-RL" : true, "GE-SJ" : true, "GE-SK" : true, "GE-SZ" : true, + "GE-TB" : true, "GH-AA" : true, "GH-AH" : true, "GH-BA" : true, "GH-CP" : true, + "GH-EP" : true, "GH-NP" : true, "GH-TV" : true, "GH-UE" : true, "GH-UW" : true, + "GH-WP" : true, "GL-KU" : true, "GL-QA" : true, "GL-QE" : true, "GL-SM" : true, + "GM-B" : true, "GM-L" : true, "GM-M" : true, "GM-N" : true, "GM-U" : true, + "GM-W" : true, "GN-B" : true, "GN-BE" : true, "GN-BF" : true, "GN-BK" : true, + "GN-C" : true, "GN-CO" : true, "GN-D" : true, "GN-DB" : true, "GN-DI" : true, + "GN-DL" : true, "GN-DU" : true, "GN-F" : true, "GN-FA" : true, "GN-FO" : true, + "GN-FR" : true, "GN-GA" : true, "GN-GU" : true, "GN-K" : true, "GN-KA" : true, + "GN-KB" : true, "GN-KD" : true, "GN-KE" : true, "GN-KN" : true, "GN-KO" : true, + "GN-KS" : true, "GN-L" : true, "GN-LA" : true, "GN-LE" : true, "GN-LO" : true, + "GN-M" : true, "GN-MC" : true, "GN-MD" : true, "GN-ML" : true, "GN-MM" : true, + "GN-N" : true, "GN-NZ" : true, "GN-PI" : true, "GN-SI" : true, "GN-TE" : true, + "GN-TO" : true, "GN-YO" : true, "GQ-AN" : true, "GQ-BN" : true, "GQ-BS" : true, + "GQ-C" : true, "GQ-CS" : true, "GQ-I" : true, "GQ-KN" : true, "GQ-LI" : true, + "GQ-WN" : true, "GR-01" : true, "GR-03" : true, "GR-04" : true, "GR-05" : true, + "GR-06" : true, "GR-07" : true, "GR-11" : true, "GR-12" : true, "GR-13" : true, + "GR-14" : true, "GR-15" : true, "GR-16" : true, "GR-17" : true, "GR-21" : true, + "GR-22" : true, "GR-23" : true, "GR-24" : true, "GR-31" : true, "GR-32" : true, + "GR-33" : true, "GR-34" : true, "GR-41" : true, "GR-42" : true, "GR-43" : true, + "GR-44" : true, "GR-51" : true, "GR-52" : true, "GR-53" : true, "GR-54" : true, + "GR-55" : true, "GR-56" : true, "GR-57" : true, "GR-58" : true, "GR-59" : true, + "GR-61" : true, "GR-62" : true, "GR-63" : true, "GR-64" : true, "GR-69" : true, + "GR-71" : true, "GR-72" : true, "GR-73" : true, "GR-81" : true, "GR-82" : true, + "GR-83" : true, "GR-84" : true, "GR-85" : true, "GR-91" : true, "GR-92" : true, + "GR-93" : true, "GR-94" : true, "GR-A" : true, "GR-A1" : true, "GR-B" : true, + "GR-C" : true, "GR-D" : true, "GR-E" : true, "GR-F" : true, "GR-G" : true, + "GR-H" : true, "GR-I" : true, "GR-J" : true, "GR-K" : true, "GR-L" : true, + "GR-M" : true, "GT-AV" : true, "GT-BV" : true, "GT-CM" : true, "GT-CQ" : true, + "GT-ES" : true, "GT-GU" : true, "GT-HU" : true, "GT-IZ" : true, "GT-JA" : true, + "GT-JU" : true, "GT-PE" : true, "GT-PR" : true, "GT-QC" : true, "GT-QZ" : true, + "GT-RE" : true, "GT-SA" : true, "GT-SM" : true, "GT-SO" : true, "GT-SR" : true, + "GT-SU" : true, "GT-TO" : true, "GT-ZA" : true, "GW-BA" : true, "GW-BL" : true, + "GW-BM" : true, "GW-BS" : true, "GW-CA" : true, "GW-GA" : true, "GW-L" : true, + "GW-N" : true, "GW-OI" : true, "GW-QU" : true, "GW-S" : true, "GW-TO" : true, + "GY-BA" : true, "GY-CU" : true, "GY-DE" : true, "GY-EB" : true, "GY-ES" : true, + "GY-MA" : true, "GY-PM" : true, "GY-PT" : true, "GY-UD" : true, "GY-UT" : true, + "HN-AT" : true, "HN-CH" : true, "HN-CL" : true, "HN-CM" : true, "HN-CP" : true, + "HN-CR" : true, "HN-EP" : true, "HN-FM" : true, "HN-GD" : true, "HN-IB" : true, + "HN-IN" : true, "HN-LE" : true, "HN-LP" : true, "HN-OC" : true, "HN-OL" : true, + "HN-SB" : true, "HN-VA" : true, "HN-YO" : true, "HR-01" : true, "HR-02" : true, + "HR-03" : true, "HR-04" : true, "HR-05" : true, "HR-06" : true, "HR-07" : true, + "HR-08" : true, "HR-09" : true, "HR-10" : true, "HR-11" : true, "HR-12" : true, + "HR-13" : true, "HR-14" : true, "HR-15" : true, "HR-16" : true, "HR-17" : true, + "HR-18" : true, "HR-19" : true, "HR-20" : true, "HR-21" : true, "HT-AR" : true, + "HT-CE" : true, "HT-GA" : true, "HT-ND" : true, "HT-NE" : true, "HT-NO" : true, + "HT-OU" : true, "HT-SD" : true, "HT-SE" : true, "HU-BA" : true, "HU-BC" : true, + "HU-BE" : true, "HU-BK" : true, "HU-BU" : true, "HU-BZ" : true, "HU-CS" : true, + "HU-DE" : true, "HU-DU" : true, "HU-EG" : true, "HU-ER" : true, "HU-FE" : true, + "HU-GS" : true, "HU-GY" : true, "HU-HB" : true, "HU-HE" : true, "HU-HV" : true, + "HU-JN" : true, "HU-KE" : true, "HU-KM" : true, "HU-KV" : true, "HU-MI" : true, + "HU-NK" : true, "HU-NO" : true, "HU-NY" : true, "HU-PE" : true, "HU-PS" : true, + "HU-SD" : true, "HU-SF" : true, "HU-SH" : true, "HU-SK" : true, "HU-SN" : true, + "HU-SO" : true, "HU-SS" : true, "HU-ST" : true, "HU-SZ" : true, "HU-TB" : true, + "HU-TO" : true, "HU-VA" : true, "HU-VE" : true, "HU-VM" : true, "HU-ZA" : true, + "HU-ZE" : true, "ID-AC" : true, "ID-BA" : true, "ID-BB" : true, "ID-BE" : true, + "ID-BT" : true, "ID-GO" : true, "ID-IJ" : true, "ID-JA" : true, "ID-JB" : true, + "ID-JI" : true, "ID-JK" : true, "ID-JT" : true, "ID-JW" : true, "ID-KA" : true, + "ID-KB" : true, "ID-KI" : true, "ID-KR" : true, "ID-KS" : true, "ID-KT" : true, + "ID-LA" : true, "ID-MA" : true, "ID-ML" : true, "ID-MU" : true, "ID-NB" : true, + "ID-NT" : true, "ID-NU" : true, "ID-PA" : true, "ID-PB" : true, "ID-RI" : true, + "ID-SA" : true, "ID-SB" : true, "ID-SG" : true, "ID-SL" : true, "ID-SM" : true, + "ID-SN" : true, "ID-SR" : true, "ID-SS" : true, "ID-ST" : true, "ID-SU" : true, + "ID-YO" : true, "IE-C" : true, "IE-CE" : true, "IE-CN" : true, "IE-CO" : true, + "IE-CW" : true, "IE-D" : true, "IE-DL" : true, "IE-G" : true, "IE-KE" : true, + "IE-KK" : true, "IE-KY" : true, "IE-L" : true, "IE-LD" : true, "IE-LH" : true, + "IE-LK" : true, "IE-LM" : true, "IE-LS" : true, "IE-M" : true, "IE-MH" : true, + "IE-MN" : true, "IE-MO" : true, "IE-OY" : true, "IE-RN" : true, "IE-SO" : true, + "IE-TA" : true, "IE-U" : true, "IE-WD" : true, "IE-WH" : true, "IE-WW" : true, + "IE-WX" : true, "IL-D" : true, "IL-HA" : true, "IL-JM" : true, "IL-M" : true, + "IL-TA" : true, "IL-Z" : true, "IN-AN" : true, "IN-AP" : true, "IN-AR" : true, + "IN-AS" : true, "IN-BR" : true, "IN-CH" : true, "IN-CT" : true, "IN-DD" : true, + "IN-DL" : true, "IN-DN" : true, "IN-GA" : true, "IN-GJ" : true, "IN-HP" : true, + "IN-HR" : true, "IN-JH" : true, "IN-JK" : true, "IN-KA" : true, "IN-KL" : true, + "IN-LD" : true, "IN-MH" : true, "IN-ML" : true, "IN-MN" : true, "IN-MP" : true, + "IN-MZ" : true, "IN-NL" : true, "IN-OR" : true, "IN-PB" : true, "IN-PY" : true, + "IN-RJ" : true, "IN-SK" : true, "IN-TN" : true, "IN-TR" : true, "IN-UP" : true, + "IN-UT" : true, "IN-WB" : true, "IQ-AN" : true, "IQ-AR" : true, "IQ-BA" : true, + "IQ-BB" : true, "IQ-BG" : true, "IQ-DA" : true, "IQ-DI" : true, "IQ-DQ" : true, + "IQ-KA" : true, "IQ-MA" : true, "IQ-MU" : true, "IQ-NA" : true, "IQ-NI" : true, + "IQ-QA" : true, "IQ-SD" : true, "IQ-SW" : true, "IQ-TS" : true, "IQ-WA" : true, + "IR-01" : true, "IR-02" : true, "IR-03" : true, "IR-04" : true, "IR-05" : true, + "IR-06" : true, "IR-07" : true, "IR-08" : true, "IR-10" : true, "IR-11" : true, + "IR-12" : true, "IR-13" : true, "IR-14" : true, "IR-15" : true, "IR-16" : true, + "IR-17" : true, "IR-18" : true, "IR-19" : true, "IR-20" : true, "IR-21" : true, + "IR-22" : true, "IR-23" : true, "IR-24" : true, "IR-25" : true, "IR-26" : true, + "IR-27" : true, "IR-28" : true, "IR-29" : true, "IR-30" : true, "IR-31" : true, + "IS-0" : true, "IS-1" : true, "IS-2" : true, "IS-3" : true, "IS-4" : true, + "IS-5" : true, "IS-6" : true, "IS-7" : true, "IS-8" : true, "IT-21" : true, + "IT-23" : true, "IT-25" : true, "IT-32" : true, "IT-34" : true, "IT-36" : true, + "IT-42" : true, "IT-45" : true, "IT-52" : true, "IT-55" : true, "IT-57" : true, + "IT-62" : true, "IT-65" : true, "IT-67" : true, "IT-72" : true, "IT-75" : true, + "IT-77" : true, "IT-78" : true, "IT-82" : true, "IT-88" : true, "IT-AG" : true, + "IT-AL" : true, "IT-AN" : true, "IT-AO" : true, "IT-AP" : true, "IT-AQ" : true, + "IT-AR" : true, "IT-AT" : true, "IT-AV" : true, "IT-BA" : true, "IT-BG" : true, + "IT-BI" : true, "IT-BL" : true, "IT-BN" : true, "IT-BO" : true, "IT-BR" : true, + "IT-BS" : true, "IT-BT" : true, "IT-BZ" : true, "IT-CA" : true, "IT-CB" : true, + "IT-CE" : true, "IT-CH" : true, "IT-CI" : true, "IT-CL" : true, "IT-CN" : true, + "IT-CO" : true, "IT-CR" : true, "IT-CS" : true, "IT-CT" : true, "IT-CZ" : true, + "IT-EN" : true, "IT-FC" : true, "IT-FE" : true, "IT-FG" : true, "IT-FI" : true, + "IT-FM" : true, "IT-FR" : true, "IT-GE" : true, "IT-GO" : true, "IT-GR" : true, + "IT-IM" : true, "IT-IS" : true, "IT-KR" : true, "IT-LC" : true, "IT-LE" : true, + "IT-LI" : true, "IT-LO" : true, "IT-LT" : true, "IT-LU" : true, "IT-MB" : true, + "IT-MC" : true, "IT-ME" : true, "IT-MI" : true, "IT-MN" : true, "IT-MO" : true, + "IT-MS" : true, "IT-MT" : true, "IT-NA" : true, "IT-NO" : true, "IT-NU" : true, + "IT-OG" : true, "IT-OR" : true, "IT-OT" : true, "IT-PA" : true, "IT-PC" : true, + "IT-PD" : true, "IT-PE" : true, "IT-PG" : true, "IT-PI" : true, "IT-PN" : true, + "IT-PO" : true, "IT-PR" : true, "IT-PT" : true, "IT-PU" : true, "IT-PV" : true, + "IT-PZ" : true, "IT-RA" : true, "IT-RC" : true, "IT-RE" : true, "IT-RG" : true, + "IT-RI" : true, "IT-RM" : true, "IT-RN" : true, "IT-RO" : true, "IT-SA" : true, + "IT-SI" : true, "IT-SO" : true, "IT-SP" : true, "IT-SR" : true, "IT-SS" : true, + "IT-SV" : true, "IT-TA" : true, "IT-TE" : true, "IT-TN" : true, "IT-TO" : true, + "IT-TP" : true, "IT-TR" : true, "IT-TS" : true, "IT-TV" : true, "IT-UD" : true, + "IT-VA" : true, "IT-VB" : true, "IT-VC" : true, "IT-VE" : true, "IT-VI" : true, + "IT-VR" : true, "IT-VS" : true, "IT-VT" : true, "IT-VV" : true, "JM-01" : true, + "JM-02" : true, "JM-03" : true, "JM-04" : true, "JM-05" : true, "JM-06" : true, + "JM-07" : true, "JM-08" : true, "JM-09" : true, "JM-10" : true, "JM-11" : true, + "JM-12" : true, "JM-13" : true, "JM-14" : true, "JO-AJ" : true, "JO-AM" : true, + "JO-AQ" : true, "JO-AT" : true, "JO-AZ" : true, "JO-BA" : true, "JO-IR" : true, + "JO-JA" : true, "JO-KA" : true, "JO-MA" : true, "JO-MD" : true, "JO-MN" : true, + "JP-01" : true, "JP-02" : true, "JP-03" : true, "JP-04" : true, "JP-05" : true, + "JP-06" : true, "JP-07" : true, "JP-08" : true, "JP-09" : true, "JP-10" : true, + "JP-11" : true, "JP-12" : true, "JP-13" : true, "JP-14" : true, "JP-15" : true, + "JP-16" : true, "JP-17" : true, "JP-18" : true, "JP-19" : true, "JP-20" : true, + "JP-21" : true, "JP-22" : true, "JP-23" : true, "JP-24" : true, "JP-25" : true, + "JP-26" : true, "JP-27" : true, "JP-28" : true, "JP-29" : true, "JP-30" : true, + "JP-31" : true, "JP-32" : true, "JP-33" : true, "JP-34" : true, "JP-35" : true, + "JP-36" : true, "JP-37" : true, "JP-38" : true, "JP-39" : true, "JP-40" : true, + "JP-41" : true, "JP-42" : true, "JP-43" : true, "JP-44" : true, "JP-45" : true, + "JP-46" : true, "JP-47" : true, "KE-110" : true, "KE-200" : true, "KE-300" : true, + "KE-400" : true, "KE-500" : true, "KE-700" : true, "KE-800" : true, "KG-B" : true, + "KG-C" : true, "KG-GB" : true, "KG-J" : true, "KG-N" : true, "KG-O" : true, + "KG-T" : true, "KG-Y" : true, "KH-1" : true, "KH-10" : true, "KH-11" : true, + "KH-12" : true, "KH-13" : true, "KH-14" : true, "KH-15" : true, "KH-16" : true, + "KH-17" : true, "KH-18" : true, "KH-19" : true, "KH-2" : true, "KH-20" : true, + "KH-21" : true, "KH-22" : true, "KH-23" : true, "KH-24" : true, "KH-3" : true, + "KH-4" : true, "KH-5" : true, "KH-6" : true, "KH-7" : true, "KH-8" : true, + "KH-9" : true, "KI-G" : true, "KI-L" : true, "KI-P" : true, "KM-A" : true, + "KM-G" : true, "KM-M" : true, "KN-01" : true, "KN-02" : true, "KN-03" : true, + "KN-04" : true, "KN-05" : true, "KN-06" : true, "KN-07" : true, "KN-08" : true, + "KN-09" : true, "KN-10" : true, "KN-11" : true, "KN-12" : true, "KN-13" : true, + "KN-15" : true, "KN-K" : true, "KN-N" : true, "KP-01" : true, "KP-02" : true, + "KP-03" : true, "KP-04" : true, "KP-05" : true, "KP-06" : true, "KP-07" : true, + "KP-08" : true, "KP-09" : true, "KP-10" : true, "KP-13" : true, "KR-11" : true, + "KR-26" : true, "KR-27" : true, "KR-28" : true, "KR-29" : true, "KR-30" : true, + "KR-31" : true, "KR-41" : true, "KR-42" : true, "KR-43" : true, "KR-44" : true, + "KR-45" : true, "KR-46" : true, "KR-47" : true, "KR-48" : true, "KR-49" : true, + "KW-AH" : true, "KW-FA" : true, "KW-HA" : true, "KW-JA" : true, "KW-KU" : true, + "KW-MU" : true, "KZ-AKM" : true, "KZ-AKT" : true, "KZ-ALA" : true, "KZ-ALM" : true, + "KZ-AST" : true, "KZ-ATY" : true, "KZ-KAR" : true, "KZ-KUS" : true, "KZ-KZY" : true, + "KZ-MAN" : true, "KZ-PAV" : true, "KZ-SEV" : true, "KZ-VOS" : true, "KZ-YUZ" : true, + "KZ-ZAP" : true, "KZ-ZHA" : true, "LA-AT" : true, "LA-BK" : true, "LA-BL" : true, + "LA-CH" : true, "LA-HO" : true, "LA-KH" : true, "LA-LM" : true, "LA-LP" : true, + "LA-OU" : true, "LA-PH" : true, "LA-SL" : true, "LA-SV" : true, "LA-VI" : true, + "LA-VT" : true, "LA-XA" : true, "LA-XE" : true, "LA-XI" : true, "LA-XS" : true, + "LB-AK" : true, "LB-AS" : true, "LB-BA" : true, "LB-BH" : true, "LB-BI" : true, + "LB-JA" : true, "LB-JL" : true, "LB-NA" : true, "LI-01" : true, "LI-02" : true, + "LI-03" : true, "LI-04" : true, "LI-05" : true, "LI-06" : true, "LI-07" : true, + "LI-08" : true, "LI-09" : true, "LI-10" : true, "LI-11" : true, "LK-1" : true, + "LK-11" : true, "LK-12" : true, "LK-13" : true, "LK-2" : true, "LK-21" : true, + "LK-22" : true, "LK-23" : true, "LK-3" : true, "LK-31" : true, "LK-32" : true, + "LK-33" : true, "LK-4" : true, "LK-41" : true, "LK-42" : true, "LK-43" : true, + "LK-44" : true, "LK-45" : true, "LK-5" : true, "LK-51" : true, "LK-52" : true, + "LK-53" : true, "LK-6" : true, "LK-61" : true, "LK-62" : true, "LK-7" : true, + "LK-71" : true, "LK-72" : true, "LK-8" : true, "LK-81" : true, "LK-82" : true, + "LK-9" : true, "LK-91" : true, "LK-92" : true, "LR-BG" : true, "LR-BM" : true, + "LR-CM" : true, "LR-GB" : true, "LR-GG" : true, "LR-GK" : true, "LR-LO" : true, + "LR-MG" : true, "LR-MO" : true, "LR-MY" : true, "LR-NI" : true, "LR-RI" : true, + "LR-SI" : true, "LS-A" : true, "LS-B" : true, "LS-C" : true, "LS-D" : true, + "LS-E" : true, "LS-F" : true, "LS-G" : true, "LS-H" : true, "LS-J" : true, + "LS-K" : true, "LT-AL" : true, "LT-KL" : true, "LT-KU" : true, "LT-MR" : true, + "LT-PN" : true, "LT-SA" : true, "LT-TA" : true, "LT-TE" : true, "LT-UT" : true, + "LT-VL" : true, "LU-D" : true, "LU-G" : true, "LU-L" : true, "LV-001" : true, + "LV-002" : true, "LV-003" : true, "LV-004" : true, "LV-005" : true, "LV-006" : true, + "LV-007" : true, "LV-008" : true, "LV-009" : true, "LV-010" : true, "LV-011" : true, + "LV-012" : true, "LV-013" : true, "LV-014" : true, "LV-015" : true, "LV-016" : true, + "LV-017" : true, "LV-018" : true, "LV-019" : true, "LV-020" : true, "LV-021" : true, + "LV-022" : true, "LV-023" : true, "LV-024" : true, "LV-025" : true, "LV-026" : true, + "LV-027" : true, "LV-028" : true, "LV-029" : true, "LV-030" : true, "LV-031" : true, + "LV-032" : true, "LV-033" : true, "LV-034" : true, "LV-035" : true, "LV-036" : true, + "LV-037" : true, "LV-038" : true, "LV-039" : true, "LV-040" : true, "LV-041" : true, + "LV-042" : true, "LV-043" : true, "LV-044" : true, "LV-045" : true, "LV-046" : true, + "LV-047" : true, "LV-048" : true, "LV-049" : true, "LV-050" : true, "LV-051" : true, + "LV-052" : true, "LV-053" : true, "LV-054" : true, "LV-055" : true, "LV-056" : true, + "LV-057" : true, "LV-058" : true, "LV-059" : true, "LV-060" : true, "LV-061" : true, + "LV-062" : true, "LV-063" : true, "LV-064" : true, "LV-065" : true, "LV-066" : true, + "LV-067" : true, "LV-068" : true, "LV-069" : true, "LV-070" : true, "LV-071" : true, + "LV-072" : true, "LV-073" : true, "LV-074" : true, "LV-075" : true, "LV-076" : true, + "LV-077" : true, "LV-078" : true, "LV-079" : true, "LV-080" : true, "LV-081" : true, + "LV-082" : true, "LV-083" : true, "LV-084" : true, "LV-085" : true, "LV-086" : true, + "LV-087" : true, "LV-088" : true, "LV-089" : true, "LV-090" : true, "LV-091" : true, + "LV-092" : true, "LV-093" : true, "LV-094" : true, "LV-095" : true, "LV-096" : true, + "LV-097" : true, "LV-098" : true, "LV-099" : true, "LV-100" : true, "LV-101" : true, + "LV-102" : true, "LV-103" : true, "LV-104" : true, "LV-105" : true, "LV-106" : true, + "LV-107" : true, "LV-108" : true, "LV-109" : true, "LV-110" : true, "LV-DGV" : true, + "LV-JEL" : true, "LV-JKB" : true, "LV-JUR" : true, "LV-LPX" : true, "LV-REZ" : true, + "LV-RIX" : true, "LV-VEN" : true, "LV-VMR" : true, "LY-BA" : true, "LY-BU" : true, + "LY-DR" : true, "LY-GT" : true, "LY-JA" : true, "LY-JB" : true, "LY-JG" : true, + "LY-JI" : true, "LY-JU" : true, "LY-KF" : true, "LY-MB" : true, "LY-MI" : true, + "LY-MJ" : true, "LY-MQ" : true, "LY-NL" : true, "LY-NQ" : true, "LY-SB" : true, + "LY-SR" : true, "LY-TB" : true, "LY-WA" : true, "LY-WD" : true, "LY-WS" : true, + "LY-ZA" : true, "MA-01" : true, "MA-02" : true, "MA-03" : true, "MA-04" : true, + "MA-05" : true, "MA-06" : true, "MA-07" : true, "MA-08" : true, "MA-09" : true, + "MA-10" : true, "MA-11" : true, "MA-12" : true, "MA-13" : true, "MA-14" : true, + "MA-15" : true, "MA-16" : true, "MA-AGD" : true, "MA-AOU" : true, "MA-ASZ" : true, + "MA-AZI" : true, "MA-BEM" : true, "MA-BER" : true, "MA-BES" : true, "MA-BOD" : true, + "MA-BOM" : true, "MA-CAS" : true, "MA-CHE" : true, "MA-CHI" : true, "MA-CHT" : true, + "MA-ERR" : true, "MA-ESI" : true, "MA-ESM" : true, "MA-FAH" : true, "MA-FES" : true, + "MA-FIG" : true, "MA-GUE" : true, "MA-HAJ" : true, "MA-HAO" : true, "MA-HOC" : true, + "MA-IFR" : true, "MA-INE" : true, "MA-JDI" : true, "MA-JRA" : true, "MA-KEN" : true, + "MA-KES" : true, "MA-KHE" : true, "MA-KHN" : true, "MA-KHO" : true, "MA-LAA" : true, + "MA-LAR" : true, "MA-MED" : true, "MA-MEK" : true, "MA-MMD" : true, "MA-MMN" : true, + "MA-MOH" : true, "MA-MOU" : true, "MA-NAD" : true, "MA-NOU" : true, "MA-OUA" : true, + "MA-OUD" : true, "MA-OUJ" : true, "MA-RAB" : true, "MA-SAF" : true, "MA-SAL" : true, + "MA-SEF" : true, "MA-SET" : true, "MA-SIK" : true, "MA-SKH" : true, "MA-SYB" : true, + "MA-TAI" : true, "MA-TAO" : true, "MA-TAR" : true, "MA-TAT" : true, "MA-TAZ" : true, + "MA-TET" : true, "MA-TIZ" : true, "MA-TNG" : true, "MA-TNT" : true, "MA-ZAG" : true, + "MC-CL" : true, "MC-CO" : true, "MC-FO" : true, "MC-GA" : true, "MC-JE" : true, + "MC-LA" : true, "MC-MA" : true, "MC-MC" : true, "MC-MG" : true, "MC-MO" : true, + "MC-MU" : true, "MC-PH" : true, "MC-SD" : true, "MC-SO" : true, "MC-SP" : true, + "MC-SR" : true, "MC-VR" : true, "MD-AN" : true, "MD-BA" : true, "MD-BD" : true, + "MD-BR" : true, "MD-BS" : true, "MD-CA" : true, "MD-CL" : true, "MD-CM" : true, + "MD-CR" : true, "MD-CS" : true, "MD-CT" : true, "MD-CU" : true, "MD-DO" : true, + "MD-DR" : true, "MD-DU" : true, "MD-ED" : true, "MD-FA" : true, "MD-FL" : true, + "MD-GA" : true, "MD-GL" : true, "MD-HI" : true, "MD-IA" : true, "MD-LE" : true, + "MD-NI" : true, "MD-OC" : true, "MD-OR" : true, "MD-RE" : true, "MD-RI" : true, + "MD-SD" : true, "MD-SI" : true, "MD-SN" : true, "MD-SO" : true, "MD-ST" : true, + "MD-SV" : true, "MD-TA" : true, "MD-TE" : true, "MD-UN" : true, "ME-01" : true, + "ME-02" : true, "ME-03" : true, "ME-04" : true, "ME-05" : true, "ME-06" : true, + "ME-07" : true, "ME-08" : true, "ME-09" : true, "ME-10" : true, "ME-11" : true, + "ME-12" : true, "ME-13" : true, "ME-14" : true, "ME-15" : true, "ME-16" : true, + "ME-17" : true, "ME-18" : true, "ME-19" : true, "ME-20" : true, "ME-21" : true, + "MG-A" : true, "MG-D" : true, "MG-F" : true, "MG-M" : true, "MG-T" : true, + "MG-U" : true, "MH-ALK" : true, "MH-ALL" : true, "MH-ARN" : true, "MH-AUR" : true, + "MH-EBO" : true, "MH-ENI" : true, "MH-JAB" : true, "MH-JAL" : true, "MH-KIL" : true, + "MH-KWA" : true, "MH-L" : true, "MH-LAE" : true, "MH-LIB" : true, "MH-LIK" : true, + "MH-MAJ" : true, "MH-MAL" : true, "MH-MEJ" : true, "MH-MIL" : true, "MH-NMK" : true, + "MH-NMU" : true, "MH-RON" : true, "MH-T" : true, "MH-UJA" : true, "MH-UTI" : true, + "MH-WTJ" : true, "MH-WTN" : true, "MK-01" : true, "MK-02" : true, "MK-03" : true, + "MK-04" : true, "MK-05" : true, "MK-06" : true, "MK-07" : true, "MK-08" : true, + "MK-09" : true, "MK-10" : true, "MK-11" : true, "MK-12" : true, "MK-13" : true, + "MK-14" : true, "MK-15" : true, "MK-16" : true, "MK-17" : true, "MK-18" : true, + "MK-19" : true, "MK-20" : true, "MK-21" : true, "MK-22" : true, "MK-23" : true, + "MK-24" : true, "MK-25" : true, "MK-26" : true, "MK-27" : true, "MK-28" : true, + "MK-29" : true, "MK-30" : true, "MK-31" : true, "MK-32" : true, "MK-33" : true, + "MK-34" : true, "MK-35" : true, "MK-36" : true, "MK-37" : true, "MK-38" : true, + "MK-39" : true, "MK-40" : true, "MK-41" : true, "MK-42" : true, "MK-43" : true, + "MK-44" : true, "MK-45" : true, "MK-46" : true, "MK-47" : true, "MK-48" : true, + "MK-49" : true, "MK-50" : true, "MK-51" : true, "MK-52" : true, "MK-53" : true, + "MK-54" : true, "MK-55" : true, "MK-56" : true, "MK-57" : true, "MK-58" : true, + "MK-59" : true, "MK-60" : true, "MK-61" : true, "MK-62" : true, "MK-63" : true, + "MK-64" : true, "MK-65" : true, "MK-66" : true, "MK-67" : true, "MK-68" : true, + "MK-69" : true, "MK-70" : true, "MK-71" : true, "MK-72" : true, "MK-73" : true, + "MK-74" : true, "MK-75" : true, "MK-76" : true, "MK-77" : true, "MK-78" : true, + "MK-79" : true, "MK-80" : true, "MK-81" : true, "MK-82" : true, "MK-83" : true, + "MK-84" : true, "ML-1" : true, "ML-2" : true, "ML-3" : true, "ML-4" : true, + "ML-5" : true, "ML-6" : true, "ML-7" : true, "ML-8" : true, "ML-BK0" : true, + "MM-01" : true, "MM-02" : true, "MM-03" : true, "MM-04" : true, "MM-05" : true, + "MM-06" : true, "MM-07" : true, "MM-11" : true, "MM-12" : true, "MM-13" : true, + "MM-14" : true, "MM-15" : true, "MM-16" : true, "MM-17" : true, "MN-035" : true, + "MN-037" : true, "MN-039" : true, "MN-041" : true, "MN-043" : true, "MN-046" : true, + "MN-047" : true, "MN-049" : true, "MN-051" : true, "MN-053" : true, "MN-055" : true, + "MN-057" : true, "MN-059" : true, "MN-061" : true, "MN-063" : true, "MN-064" : true, + "MN-065" : true, "MN-067" : true, "MN-069" : true, "MN-071" : true, "MN-073" : true, + "MN-1" : true, "MR-01" : true, "MR-02" : true, "MR-03" : true, "MR-04" : true, + "MR-05" : true, "MR-06" : true, "MR-07" : true, "MR-08" : true, "MR-09" : true, + "MR-10" : true, "MR-11" : true, "MR-12" : true, "MR-NKC" : true, "MT-01" : true, + "MT-02" : true, "MT-03" : true, "MT-04" : true, "MT-05" : true, "MT-06" : true, + "MT-07" : true, "MT-08" : true, "MT-09" : true, "MT-10" : true, "MT-11" : true, + "MT-12" : true, "MT-13" : true, "MT-14" : true, "MT-15" : true, "MT-16" : true, + "MT-17" : true, "MT-18" : true, "MT-19" : true, "MT-20" : true, "MT-21" : true, + "MT-22" : true, "MT-23" : true, "MT-24" : true, "MT-25" : true, "MT-26" : true, + "MT-27" : true, "MT-28" : true, "MT-29" : true, "MT-30" : true, "MT-31" : true, + "MT-32" : true, "MT-33" : true, "MT-34" : true, "MT-35" : true, "MT-36" : true, + "MT-37" : true, "MT-38" : true, "MT-39" : true, "MT-40" : true, "MT-41" : true, + "MT-42" : true, "MT-43" : true, "MT-44" : true, "MT-45" : true, "MT-46" : true, + "MT-47" : true, "MT-48" : true, "MT-49" : true, "MT-50" : true, "MT-51" : true, + "MT-52" : true, "MT-53" : true, "MT-54" : true, "MT-55" : true, "MT-56" : true, + "MT-57" : true, "MT-58" : true, "MT-59" : true, "MT-60" : true, "MT-61" : true, + "MT-62" : true, "MT-63" : true, "MT-64" : true, "MT-65" : true, "MT-66" : true, + "MT-67" : true, "MT-68" : true, "MU-AG" : true, "MU-BL" : true, "MU-BR" : true, + "MU-CC" : true, "MU-CU" : true, "MU-FL" : true, "MU-GP" : true, "MU-MO" : true, + "MU-PA" : true, "MU-PL" : true, "MU-PU" : true, "MU-PW" : true, "MU-QB" : true, + "MU-RO" : true, "MU-RP" : true, "MU-SA" : true, "MU-VP" : true, "MV-00" : true, + "MV-01" : true, "MV-02" : true, "MV-03" : true, "MV-04" : true, "MV-05" : true, + "MV-07" : true, "MV-08" : true, "MV-12" : true, "MV-13" : true, "MV-14" : true, + "MV-17" : true, "MV-20" : true, "MV-23" : true, "MV-24" : true, "MV-25" : true, + "MV-26" : true, "MV-27" : true, "MV-28" : true, "MV-29" : true, "MV-CE" : true, + "MV-MLE" : true, "MV-NC" : true, "MV-NO" : true, "MV-SC" : true, "MV-SU" : true, + "MV-UN" : true, "MV-US" : true, "MW-BA" : true, "MW-BL" : true, "MW-C" : true, + "MW-CK" : true, "MW-CR" : true, "MW-CT" : true, "MW-DE" : true, "MW-DO" : true, + "MW-KR" : true, "MW-KS" : true, "MW-LI" : true, "MW-LK" : true, "MW-MC" : true, + "MW-MG" : true, "MW-MH" : true, "MW-MU" : true, "MW-MW" : true, "MW-MZ" : true, + "MW-N" : true, "MW-NB" : true, "MW-NE" : true, "MW-NI" : true, "MW-NK" : true, + "MW-NS" : true, "MW-NU" : true, "MW-PH" : true, "MW-RU" : true, "MW-S" : true, + "MW-SA" : true, "MW-TH" : true, "MW-ZO" : true, "MX-AGU" : true, "MX-BCN" : true, + "MX-BCS" : true, "MX-CAM" : true, "MX-CHH" : true, "MX-CHP" : true, "MX-COA" : true, + "MX-COL" : true, "MX-DIF" : true, "MX-DUR" : true, "MX-GRO" : true, "MX-GUA" : true, + "MX-HID" : true, "MX-JAL" : true, "MX-MEX" : true, "MX-MIC" : true, "MX-MOR" : true, + "MX-NAY" : true, "MX-NLE" : true, "MX-OAX" : true, "MX-PUE" : true, "MX-QUE" : true, + "MX-ROO" : true, "MX-SIN" : true, "MX-SLP" : true, "MX-SON" : true, "MX-TAB" : true, + "MX-TAM" : true, "MX-TLA" : true, "MX-VER" : true, "MX-YUC" : true, "MX-ZAC" : true, + "MY-01" : true, "MY-02" : true, "MY-03" : true, "MY-04" : true, "MY-05" : true, + "MY-06" : true, "MY-07" : true, "MY-08" : true, "MY-09" : true, "MY-10" : true, + "MY-11" : true, "MY-12" : true, "MY-13" : true, "MY-14" : true, "MY-15" : true, + "MY-16" : true, "MZ-A" : true, "MZ-B" : true, "MZ-G" : true, "MZ-I" : true, + "MZ-L" : true, "MZ-MPM" : true, "MZ-N" : true, "MZ-P" : true, "MZ-Q" : true, + "MZ-S" : true, "MZ-T" : true, "NA-CA" : true, "NA-ER" : true, "NA-HA" : true, + "NA-KA" : true, "NA-KH" : true, "NA-KU" : true, "NA-OD" : true, "NA-OH" : true, + "NA-OK" : true, "NA-ON" : true, "NA-OS" : true, "NA-OT" : true, "NA-OW" : true, + "NE-1" : true, "NE-2" : true, "NE-3" : true, "NE-4" : true, "NE-5" : true, + "NE-6" : true, "NE-7" : true, "NE-8" : true, "NG-AB" : true, "NG-AD" : true, + "NG-AK" : true, "NG-AN" : true, "NG-BA" : true, "NG-BE" : true, "NG-BO" : true, + "NG-BY" : true, "NG-CR" : true, "NG-DE" : true, "NG-EB" : true, "NG-ED" : true, + "NG-EK" : true, "NG-EN" : true, "NG-FC" : true, "NG-GO" : true, "NG-IM" : true, + "NG-JI" : true, "NG-KD" : true, "NG-KE" : true, "NG-KN" : true, "NG-KO" : true, + "NG-KT" : true, "NG-KW" : true, "NG-LA" : true, "NG-NA" : true, "NG-NI" : true, + "NG-OG" : true, "NG-ON" : true, "NG-OS" : true, "NG-OY" : true, "NG-PL" : true, + "NG-RI" : true, "NG-SO" : true, "NG-TA" : true, "NG-YO" : true, "NG-ZA" : true, + "NI-AN" : true, "NI-AS" : true, "NI-BO" : true, "NI-CA" : true, "NI-CI" : true, + "NI-CO" : true, "NI-ES" : true, "NI-GR" : true, "NI-JI" : true, "NI-LE" : true, + "NI-MD" : true, "NI-MN" : true, "NI-MS" : true, "NI-MT" : true, "NI-NS" : true, + "NI-RI" : true, "NI-SJ" : true, "NL-AW" : true, "NL-BQ1" : true, "NL-BQ2" : true, + "NL-BQ3" : true, "NL-CW" : true, "NL-DR" : true, "NL-FL" : true, "NL-FR" : true, + "NL-GE" : true, "NL-GR" : true, "NL-LI" : true, "NL-NB" : true, "NL-NH" : true, + "NL-OV" : true, "NL-SX" : true, "NL-UT" : true, "NL-ZE" : true, "NL-ZH" : true, + "NO-01" : true, "NO-02" : true, "NO-03" : true, "NO-04" : true, "NO-05" : true, + "NO-06" : true, "NO-07" : true, "NO-08" : true, "NO-09" : true, "NO-10" : true, + "NO-11" : true, "NO-12" : true, "NO-14" : true, "NO-15" : true, "NO-16" : true, + "NO-17" : true, "NO-18" : true, "NO-19" : true, "NO-20" : true, "NO-21" : true, + "NO-22" : true, "NP-1" : true, "NP-2" : true, "NP-3" : true, "NP-4" : true, + "NP-5" : true, "NP-BA" : true, "NP-BH" : true, "NP-DH" : true, "NP-GA" : true, + "NP-JA" : true, "NP-KA" : true, "NP-KO" : true, "NP-LU" : true, "NP-MA" : true, + "NP-ME" : true, "NP-NA" : true, "NP-RA" : true, "NP-SA" : true, "NP-SE" : true, + "NR-01" : true, "NR-02" : true, "NR-03" : true, "NR-04" : true, "NR-05" : true, + "NR-06" : true, "NR-07" : true, "NR-08" : true, "NR-09" : true, "NR-10" : true, + "NR-11" : true, "NR-12" : true, "NR-13" : true, "NR-14" : true, "NZ-AUK" : true, + "NZ-BOP" : true, "NZ-CAN" : true, "NZ-CIT" : true, "NZ-GIS" : true, "NZ-HKB" : true, + "NZ-MBH" : true, "NZ-MWT" : true, "NZ-N" : true, "NZ-NSN" : true, "NZ-NTL" : true, + "NZ-OTA" : true, "NZ-S" : true, "NZ-STL" : true, "NZ-TAS" : true, "NZ-TKI" : true, + "NZ-WGN" : true, "NZ-WKO" : true, "NZ-WTC" : true, "OM-BA" : true, "OM-BU" : true, + "OM-DA" : true, "OM-MA" : true, "OM-MU" : true, "OM-SH" : true, "OM-WU" : true, + "OM-ZA" : true, "OM-ZU" : true, "PA-1" : true, "PA-2" : true, "PA-3" : true, + "PA-4" : true, "PA-5" : true, "PA-6" : true, "PA-7" : true, "PA-8" : true, + "PA-9" : true, "PA-EM" : true, "PA-KY" : true, "PA-NB" : true, "PE-AMA" : true, + "PE-ANC" : true, "PE-APU" : true, "PE-ARE" : true, "PE-AYA" : true, "PE-CAJ" : true, + "PE-CAL" : true, "PE-CUS" : true, "PE-HUC" : true, "PE-HUV" : true, "PE-ICA" : true, + "PE-JUN" : true, "PE-LAL" : true, "PE-LAM" : true, "PE-LIM" : true, "PE-LMA" : true, + "PE-LOR" : true, "PE-MDD" : true, "PE-MOQ" : true, "PE-PAS" : true, "PE-PIU" : true, + "PE-PUN" : true, "PE-SAM" : true, "PE-TAC" : true, "PE-TUM" : true, "PE-UCA" : true, + "PG-CPK" : true, "PG-CPM" : true, "PG-EBR" : true, "PG-EHG" : true, "PG-EPW" : true, + "PG-ESW" : true, "PG-GPK" : true, "PG-MBA" : true, "PG-MPL" : true, "PG-MPM" : true, + "PG-MRL" : true, "PG-NCD" : true, "PG-NIK" : true, "PG-NPP" : true, "PG-NSB" : true, + "PG-SAN" : true, "PG-SHM" : true, "PG-WBK" : true, "PG-WHM" : true, "PG-WPD" : true, + "PH-00" : true, "PH-01" : true, "PH-02" : true, "PH-03" : true, "PH-05" : true, + "PH-06" : true, "PH-07" : true, "PH-08" : true, "PH-09" : true, "PH-10" : true, + "PH-11" : true, "PH-12" : true, "PH-13" : true, "PH-14" : true, "PH-15" : true, + "PH-40" : true, "PH-41" : true, "PH-ABR" : true, "PH-AGN" : true, "PH-AGS" : true, + "PH-AKL" : true, "PH-ALB" : true, "PH-ANT" : true, "PH-APA" : true, "PH-AUR" : true, + "PH-BAN" : true, "PH-BAS" : true, "PH-BEN" : true, "PH-BIL" : true, "PH-BOH" : true, + "PH-BTG" : true, "PH-BTN" : true, "PH-BUK" : true, "PH-BUL" : true, "PH-CAG" : true, + "PH-CAM" : true, "PH-CAN" : true, "PH-CAP" : true, "PH-CAS" : true, "PH-CAT" : true, + "PH-CAV" : true, "PH-CEB" : true, "PH-COM" : true, "PH-DAO" : true, "PH-DAS" : true, + "PH-DAV" : true, "PH-DIN" : true, "PH-EAS" : true, "PH-GUI" : true, "PH-IFU" : true, + "PH-ILI" : true, "PH-ILN" : true, "PH-ILS" : true, "PH-ISA" : true, "PH-KAL" : true, + "PH-LAG" : true, "PH-LAN" : true, "PH-LAS" : true, "PH-LEY" : true, "PH-LUN" : true, + "PH-MAD" : true, "PH-MAG" : true, "PH-MAS" : true, "PH-MDC" : true, "PH-MDR" : true, + "PH-MOU" : true, "PH-MSC" : true, "PH-MSR" : true, "PH-NCO" : true, "PH-NEC" : true, + "PH-NER" : true, "PH-NSA" : true, "PH-NUE" : true, "PH-NUV" : true, "PH-PAM" : true, + "PH-PAN" : true, "PH-PLW" : true, "PH-QUE" : true, "PH-QUI" : true, "PH-RIZ" : true, + "PH-ROM" : true, "PH-SAR" : true, "PH-SCO" : true, "PH-SIG" : true, "PH-SLE" : true, + "PH-SLU" : true, "PH-SOR" : true, "PH-SUK" : true, "PH-SUN" : true, "PH-SUR" : true, + "PH-TAR" : true, "PH-TAW" : true, "PH-WSA" : true, "PH-ZAN" : true, "PH-ZAS" : true, + "PH-ZMB" : true, "PH-ZSI" : true, "PK-BA" : true, "PK-GB" : true, "PK-IS" : true, + "PK-JK" : true, "PK-KP" : true, "PK-PB" : true, "PK-SD" : true, "PK-TA" : true, + "PL-DS" : true, "PL-KP" : true, "PL-LB" : true, "PL-LD" : true, "PL-LU" : true, + "PL-MA" : true, "PL-MZ" : true, "PL-OP" : true, "PL-PD" : true, "PL-PK" : true, + "PL-PM" : true, "PL-SK" : true, "PL-SL" : true, "PL-WN" : true, "PL-WP" : true, + "PL-ZP" : true, "PS-BTH" : true, "PS-DEB" : true, "PS-GZA" : true, "PS-HBN" : true, + "PS-JEM" : true, "PS-JEN" : true, "PS-JRH" : true, "PS-KYS" : true, "PS-NBS" : true, + "PS-NGZ" : true, "PS-QQA" : true, "PS-RBH" : true, "PS-RFH" : true, "PS-SLT" : true, + "PS-TBS" : true, "PS-TKM" : true, "PT-01" : true, "PT-02" : true, "PT-03" : true, + "PT-04" : true, "PT-05" : true, "PT-06" : true, "PT-07" : true, "PT-08" : true, + "PT-09" : true, "PT-10" : true, "PT-11" : true, "PT-12" : true, "PT-13" : true, + "PT-14" : true, "PT-15" : true, "PT-16" : true, "PT-17" : true, "PT-18" : true, + "PT-20" : true, "PT-30" : true, "PW-002" : true, "PW-004" : true, "PW-010" : true, + "PW-050" : true, "PW-100" : true, "PW-150" : true, "PW-212" : true, "PW-214" : true, + "PW-218" : true, "PW-222" : true, "PW-224" : true, "PW-226" : true, "PW-227" : true, + "PW-228" : true, "PW-350" : true, "PW-370" : true, "PY-1" : true, "PY-10" : true, + "PY-11" : true, "PY-12" : true, "PY-13" : true, "PY-14" : true, "PY-15" : true, + "PY-16" : true, "PY-19" : true, "PY-2" : true, "PY-3" : true, "PY-4" : true, + "PY-5" : true, "PY-6" : true, "PY-7" : true, "PY-8" : true, "PY-9" : true, + "PY-ASU" : true, "QA-DA" : true, "QA-KH" : true, "QA-MS" : true, "QA-RA" : true, + "QA-US" : true, "QA-WA" : true, "QA-ZA" : true, "RO-AB" : true, "RO-AG" : true, + "RO-AR" : true, "RO-B" : true, "RO-BC" : true, "RO-BH" : true, "RO-BN" : true, + "RO-BR" : true, "RO-BT" : true, "RO-BV" : true, "RO-BZ" : true, "RO-CJ" : true, + "RO-CL" : true, "RO-CS" : true, "RO-CT" : true, "RO-CV" : true, "RO-DB" : true, + "RO-DJ" : true, "RO-GJ" : true, "RO-GL" : true, "RO-GR" : true, "RO-HD" : true, + "RO-HR" : true, "RO-IF" : true, "RO-IL" : true, "RO-IS" : true, "RO-MH" : true, + "RO-MM" : true, "RO-MS" : true, "RO-NT" : true, "RO-OT" : true, "RO-PH" : true, + "RO-SB" : true, "RO-SJ" : true, "RO-SM" : true, "RO-SV" : true, "RO-TL" : true, + "RO-TM" : true, "RO-TR" : true, "RO-VL" : true, "RO-VN" : true, "RO-VS" : true, + "RS-00" : true, "RS-01" : true, "RS-02" : true, "RS-03" : true, "RS-04" : true, + "RS-05" : true, "RS-06" : true, "RS-07" : true, "RS-08" : true, "RS-09" : true, + "RS-10" : true, "RS-11" : true, "RS-12" : true, "RS-13" : true, "RS-14" : true, + "RS-15" : true, "RS-16" : true, "RS-17" : true, "RS-18" : true, "RS-19" : true, + "RS-20" : true, "RS-21" : true, "RS-22" : true, "RS-23" : true, "RS-24" : true, + "RS-25" : true, "RS-26" : true, "RS-27" : true, "RS-28" : true, "RS-29" : true, + "RS-KM" : true, "RS-VO" : true, "RU-AD" : true, "RU-AL" : true, "RU-ALT" : true, + "RU-AMU" : true, "RU-ARK" : true, "RU-AST" : true, "RU-BA" : true, "RU-BEL" : true, + "RU-BRY" : true, "RU-BU" : true, "RU-CE" : true, "RU-CHE" : true, "RU-CHU" : true, + "RU-CU" : true, "RU-DA" : true, "RU-IN" : true, "RU-IRK" : true, "RU-IVA" : true, + "RU-KAM" : true, "RU-KB" : true, "RU-KC" : true, "RU-KDA" : true, "RU-KEM" : true, + "RU-KGD" : true, "RU-KGN" : true, "RU-KHA" : true, "RU-KHM" : true, "RU-KIR" : true, + "RU-KK" : true, "RU-KL" : true, "RU-KLU" : true, "RU-KO" : true, "RU-KOS" : true, + "RU-KR" : true, "RU-KRS" : true, "RU-KYA" : true, "RU-LEN" : true, "RU-LIP" : true, + "RU-MAG" : true, "RU-ME" : true, "RU-MO" : true, "RU-MOS" : true, "RU-MOW" : true, + "RU-MUR" : true, "RU-NEN" : true, "RU-NGR" : true, "RU-NIZ" : true, "RU-NVS" : true, + "RU-OMS" : true, "RU-ORE" : true, "RU-ORL" : true, "RU-PER" : true, "RU-PNZ" : true, + "RU-PRI" : true, "RU-PSK" : true, "RU-ROS" : true, "RU-RYA" : true, "RU-SA" : true, + "RU-SAK" : true, "RU-SAM" : true, "RU-SAR" : true, "RU-SE" : true, "RU-SMO" : true, + "RU-SPE" : true, "RU-STA" : true, "RU-SVE" : true, "RU-TA" : true, "RU-TAM" : true, + "RU-TOM" : true, "RU-TUL" : true, "RU-TVE" : true, "RU-TY" : true, "RU-TYU" : true, + "RU-UD" : true, "RU-ULY" : true, "RU-VGG" : true, "RU-VLA" : true, "RU-VLG" : true, + "RU-VOR" : true, "RU-YAN" : true, "RU-YAR" : true, "RU-YEV" : true, "RU-ZAB" : true, + "RW-01" : true, "RW-02" : true, "RW-03" : true, "RW-04" : true, "RW-05" : true, + "SA-01" : true, "SA-02" : true, "SA-03" : true, "SA-04" : true, "SA-05" : true, + "SA-06" : true, "SA-07" : true, "SA-08" : true, "SA-09" : true, "SA-10" : true, + "SA-11" : true, "SA-12" : true, "SA-14" : true, "SB-CE" : true, "SB-CH" : true, + "SB-CT" : true, "SB-GU" : true, "SB-IS" : true, "SB-MK" : true, "SB-ML" : true, + "SB-RB" : true, "SB-TE" : true, "SB-WE" : true, "SC-01" : true, "SC-02" : true, + "SC-03" : true, "SC-04" : true, "SC-05" : true, "SC-06" : true, "SC-07" : true, + "SC-08" : true, "SC-09" : true, "SC-10" : true, "SC-11" : true, "SC-12" : true, + "SC-13" : true, "SC-14" : true, "SC-15" : true, "SC-16" : true, "SC-17" : true, + "SC-18" : true, "SC-19" : true, "SC-20" : true, "SC-21" : true, "SC-22" : true, + "SC-23" : true, "SC-24" : true, "SC-25" : true, "SD-DC" : true, "SD-DE" : true, + "SD-DN" : true, "SD-DS" : true, "SD-DW" : true, "SD-GD" : true, "SD-GZ" : true, + "SD-KA" : true, "SD-KH" : true, "SD-KN" : true, "SD-KS" : true, "SD-NB" : true, + "SD-NO" : true, "SD-NR" : true, "SD-NW" : true, "SD-RS" : true, "SD-SI" : true, + "SE-AB" : true, "SE-AC" : true, "SE-BD" : true, "SE-C" : true, "SE-D" : true, + "SE-E" : true, "SE-F" : true, "SE-G" : true, "SE-H" : true, "SE-I" : true, + "SE-K" : true, "SE-M" : true, "SE-N" : true, "SE-O" : true, "SE-S" : true, + "SE-T" : true, "SE-U" : true, "SE-W" : true, "SE-X" : true, "SE-Y" : true, + "SE-Z" : true, "SG-01" : true, "SG-02" : true, "SG-03" : true, "SG-04" : true, + "SG-05" : true, "SH-AC" : true, "SH-HL" : true, "SH-TA" : true, "SI-001" : true, + "SI-002" : true, "SI-003" : true, "SI-004" : true, "SI-005" : true, "SI-006" : true, + "SI-007" : true, "SI-008" : true, "SI-009" : true, "SI-010" : true, "SI-011" : true, + "SI-012" : true, "SI-013" : true, "SI-014" : true, "SI-015" : true, "SI-016" : true, + "SI-017" : true, "SI-018" : true, "SI-019" : true, "SI-020" : true, "SI-021" : true, + "SI-022" : true, "SI-023" : true, "SI-024" : true, "SI-025" : true, "SI-026" : true, + "SI-027" : true, "SI-028" : true, "SI-029" : true, "SI-030" : true, "SI-031" : true, + "SI-032" : true, "SI-033" : true, "SI-034" : true, "SI-035" : true, "SI-036" : true, + "SI-037" : true, "SI-038" : true, "SI-039" : true, "SI-040" : true, "SI-041" : true, + "SI-042" : true, "SI-043" : true, "SI-044" : true, "SI-045" : true, "SI-046" : true, + "SI-047" : true, "SI-048" : true, "SI-049" : true, "SI-050" : true, "SI-051" : true, + "SI-052" : true, "SI-053" : true, "SI-054" : true, "SI-055" : true, "SI-056" : true, + "SI-057" : true, "SI-058" : true, "SI-059" : true, "SI-060" : true, "SI-061" : true, + "SI-062" : true, "SI-063" : true, "SI-064" : true, "SI-065" : true, "SI-066" : true, + "SI-067" : true, "SI-068" : true, "SI-069" : true, "SI-070" : true, "SI-071" : true, + "SI-072" : true, "SI-073" : true, "SI-074" : true, "SI-075" : true, "SI-076" : true, + "SI-077" : true, "SI-078" : true, "SI-079" : true, "SI-080" : true, "SI-081" : true, + "SI-082" : true, "SI-083" : true, "SI-084" : true, "SI-085" : true, "SI-086" : true, + "SI-087" : true, "SI-088" : true, "SI-089" : true, "SI-090" : true, "SI-091" : true, + "SI-092" : true, "SI-093" : true, "SI-094" : true, "SI-095" : true, "SI-096" : true, + "SI-097" : true, "SI-098" : true, "SI-099" : true, "SI-100" : true, "SI-101" : true, + "SI-102" : true, "SI-103" : true, "SI-104" : true, "SI-105" : true, "SI-106" : true, + "SI-107" : true, "SI-108" : true, "SI-109" : true, "SI-110" : true, "SI-111" : true, + "SI-112" : true, "SI-113" : true, "SI-114" : true, "SI-115" : true, "SI-116" : true, + "SI-117" : true, "SI-118" : true, "SI-119" : true, "SI-120" : true, "SI-121" : true, + "SI-122" : true, "SI-123" : true, "SI-124" : true, "SI-125" : true, "SI-126" : true, + "SI-127" : true, "SI-128" : true, "SI-129" : true, "SI-130" : true, "SI-131" : true, + "SI-132" : true, "SI-133" : true, "SI-134" : true, "SI-135" : true, "SI-136" : true, + "SI-137" : true, "SI-138" : true, "SI-139" : true, "SI-140" : true, "SI-141" : true, + "SI-142" : true, "SI-143" : true, "SI-144" : true, "SI-146" : true, "SI-147" : true, + "SI-148" : true, "SI-149" : true, "SI-150" : true, "SI-151" : true, "SI-152" : true, + "SI-153" : true, "SI-154" : true, "SI-155" : true, "SI-156" : true, "SI-157" : true, + "SI-158" : true, "SI-159" : true, "SI-160" : true, "SI-161" : true, "SI-162" : true, + "SI-163" : true, "SI-164" : true, "SI-165" : true, "SI-166" : true, "SI-167" : true, + "SI-168" : true, "SI-169" : true, "SI-170" : true, "SI-171" : true, "SI-172" : true, + "SI-173" : true, "SI-174" : true, "SI-175" : true, "SI-176" : true, "SI-177" : true, + "SI-178" : true, "SI-179" : true, "SI-180" : true, "SI-181" : true, "SI-182" : true, + "SI-183" : true, "SI-184" : true, "SI-185" : true, "SI-186" : true, "SI-187" : true, + "SI-188" : true, "SI-189" : true, "SI-190" : true, "SI-191" : true, "SI-192" : true, + "SI-193" : true, "SI-194" : true, "SI-195" : true, "SI-196" : true, "SI-197" : true, + "SI-198" : true, "SI-199" : true, "SI-200" : true, "SI-201" : true, "SI-202" : true, + "SI-203" : true, "SI-204" : true, "SI-205" : true, "SI-206" : true, "SI-207" : true, + "SI-208" : true, "SI-209" : true, "SI-210" : true, "SI-211" : true, "SK-BC" : true, + "SK-BL" : true, "SK-KI" : true, "SK-NI" : true, "SK-PV" : true, "SK-TA" : true, + "SK-TC" : true, "SK-ZI" : true, "SL-E" : true, "SL-N" : true, "SL-S" : true, + "SL-W" : true, "SM-01" : true, "SM-02" : true, "SM-03" : true, "SM-04" : true, + "SM-05" : true, "SM-06" : true, "SM-07" : true, "SM-08" : true, "SM-09" : true, + "SN-DB" : true, "SN-DK" : true, "SN-FK" : true, "SN-KA" : true, "SN-KD" : true, + "SN-KE" : true, "SN-KL" : true, "SN-LG" : true, "SN-MT" : true, "SN-SE" : true, + "SN-SL" : true, "SN-TC" : true, "SN-TH" : true, "SN-ZG" : true, "SO-AW" : true, + "SO-BK" : true, "SO-BN" : true, "SO-BR" : true, "SO-BY" : true, "SO-GA" : true, + "SO-GE" : true, "SO-HI" : true, "SO-JD" : true, "SO-JH" : true, "SO-MU" : true, + "SO-NU" : true, "SO-SA" : true, "SO-SD" : true, "SO-SH" : true, "SO-SO" : true, + "SO-TO" : true, "SO-WO" : true, "SR-BR" : true, "SR-CM" : true, "SR-CR" : true, + "SR-MA" : true, "SR-NI" : true, "SR-PM" : true, "SR-PR" : true, "SR-SA" : true, + "SR-SI" : true, "SR-WA" : true, "SS-BN" : true, "SS-BW" : true, "SS-EC" : true, + "SS-EE8" : true, "SS-EW" : true, "SS-JG" : true, "SS-LK" : true, "SS-NU" : true, + "SS-UY" : true, "SS-WR" : true, "ST-P" : true, "ST-S" : true, "SV-AH" : true, + "SV-CA" : true, "SV-CH" : true, "SV-CU" : true, "SV-LI" : true, "SV-MO" : true, + "SV-PA" : true, "SV-SA" : true, "SV-SM" : true, "SV-SO" : true, "SV-SS" : true, + "SV-SV" : true, "SV-UN" : true, "SV-US" : true, "SY-DI" : true, "SY-DR" : true, + "SY-DY" : true, "SY-HA" : true, "SY-HI" : true, "SY-HL" : true, "SY-HM" : true, + "SY-ID" : true, "SY-LA" : true, "SY-QU" : true, "SY-RA" : true, "SY-RD" : true, + "SY-SU" : true, "SY-TA" : true, "SZ-HH" : true, "SZ-LU" : true, "SZ-MA" : true, + "SZ-SH" : true, "TD-BA" : true, "TD-BG" : true, "TD-BO" : true, "TD-CB" : true, + "TD-EN" : true, "TD-GR" : true, "TD-HL" : true, "TD-KA" : true, "TD-LC" : true, + "TD-LO" : true, "TD-LR" : true, "TD-MA" : true, "TD-MC" : true, "TD-ME" : true, + "TD-MO" : true, "TD-ND" : true, "TD-OD" : true, "TD-SA" : true, "TD-SI" : true, + "TD-TA" : true, "TD-TI" : true, "TD-WF" : true, "TG-C" : true, "TG-K" : true, + "TG-M" : true, "TG-P" : true, "TG-S" : true, "TH-10" : true, "TH-11" : true, + "TH-12" : true, "TH-13" : true, "TH-14" : true, "TH-15" : true, "TH-16" : true, + "TH-17" : true, "TH-18" : true, "TH-19" : true, "TH-20" : true, "TH-21" : true, + "TH-22" : true, "TH-23" : true, "TH-24" : true, "TH-25" : true, "TH-26" : true, + "TH-27" : true, "TH-30" : true, "TH-31" : true, "TH-32" : true, "TH-33" : true, + "TH-34" : true, "TH-35" : true, "TH-36" : true, "TH-37" : true, "TH-39" : true, + "TH-40" : true, "TH-41" : true, "TH-42" : true, "TH-43" : true, "TH-44" : true, + "TH-45" : true, "TH-46" : true, "TH-47" : true, "TH-48" : true, "TH-49" : true, + "TH-50" : true, "TH-51" : true, "TH-52" : true, "TH-53" : true, "TH-54" : true, + "TH-55" : true, "TH-56" : true, "TH-57" : true, "TH-58" : true, "TH-60" : true, + "TH-61" : true, "TH-62" : true, "TH-63" : true, "TH-64" : true, "TH-65" : true, + "TH-66" : true, "TH-67" : true, "TH-70" : true, "TH-71" : true, "TH-72" : true, + "TH-73" : true, "TH-74" : true, "TH-75" : true, "TH-76" : true, "TH-77" : true, + "TH-80" : true, "TH-81" : true, "TH-82" : true, "TH-83" : true, "TH-84" : true, + "TH-85" : true, "TH-86" : true, "TH-90" : true, "TH-91" : true, "TH-92" : true, + "TH-93" : true, "TH-94" : true, "TH-95" : true, "TH-96" : true, "TH-S" : true, + "TJ-GB" : true, "TJ-KT" : true, "TJ-SU" : true, "TL-AL" : true, "TL-AN" : true, + "TL-BA" : true, "TL-BO" : true, "TL-CO" : true, "TL-DI" : true, "TL-ER" : true, + "TL-LA" : true, "TL-LI" : true, "TL-MF" : true, "TL-MT" : true, "TL-OE" : true, + "TL-VI" : true, "TM-A" : true, "TM-B" : true, "TM-D" : true, "TM-L" : true, + "TM-M" : true, "TM-S" : true, "TN-11" : true, "TN-12" : true, "TN-13" : true, + "TN-14" : true, "TN-21" : true, "TN-22" : true, "TN-23" : true, "TN-31" : true, + "TN-32" : true, "TN-33" : true, "TN-34" : true, "TN-41" : true, "TN-42" : true, + "TN-43" : true, "TN-51" : true, "TN-52" : true, "TN-53" : true, "TN-61" : true, + "TN-71" : true, "TN-72" : true, "TN-73" : true, "TN-81" : true, "TN-82" : true, + "TN-83" : true, "TO-01" : true, "TO-02" : true, "TO-03" : true, "TO-04" : true, + "TO-05" : true, "TR-01" : true, "TR-02" : true, "TR-03" : true, "TR-04" : true, + "TR-05" : true, "TR-06" : true, "TR-07" : true, "TR-08" : true, "TR-09" : true, + "TR-10" : true, "TR-11" : true, "TR-12" : true, "TR-13" : true, "TR-14" : true, + "TR-15" : true, "TR-16" : true, "TR-17" : true, "TR-18" : true, "TR-19" : true, + "TR-20" : true, "TR-21" : true, "TR-22" : true, "TR-23" : true, "TR-24" : true, + "TR-25" : true, "TR-26" : true, "TR-27" : true, "TR-28" : true, "TR-29" : true, + "TR-30" : true, "TR-31" : true, "TR-32" : true, "TR-33" : true, "TR-34" : true, + "TR-35" : true, "TR-36" : true, "TR-37" : true, "TR-38" : true, "TR-39" : true, + "TR-40" : true, "TR-41" : true, "TR-42" : true, "TR-43" : true, "TR-44" : true, + "TR-45" : true, "TR-46" : true, "TR-47" : true, "TR-48" : true, "TR-49" : true, + "TR-50" : true, "TR-51" : true, "TR-52" : true, "TR-53" : true, "TR-54" : true, + "TR-55" : true, "TR-56" : true, "TR-57" : true, "TR-58" : true, "TR-59" : true, + "TR-60" : true, "TR-61" : true, "TR-62" : true, "TR-63" : true, "TR-64" : true, + "TR-65" : true, "TR-66" : true, "TR-67" : true, "TR-68" : true, "TR-69" : true, + "TR-70" : true, "TR-71" : true, "TR-72" : true, "TR-73" : true, "TR-74" : true, + "TR-75" : true, "TR-76" : true, "TR-77" : true, "TR-78" : true, "TR-79" : true, + "TR-80" : true, "TR-81" : true, "TT-ARI" : true, "TT-CHA" : true, "TT-CTT" : true, + "TT-DMN" : true, "TT-ETO" : true, "TT-PED" : true, "TT-POS" : true, "TT-PRT" : true, + "TT-PTF" : true, "TT-RCM" : true, "TT-SFO" : true, "TT-SGE" : true, "TT-SIP" : true, + "TT-SJL" : true, "TT-TUP" : true, "TT-WTO" : true, "TV-FUN" : true, "TV-NIT" : true, + "TV-NKF" : true, "TV-NKL" : true, "TV-NMA" : true, "TV-NMG" : true, "TV-NUI" : true, + "TV-VAI" : true, "TW-CHA" : true, "TW-CYI" : true, "TW-CYQ" : true, "TW-HSQ" : true, + "TW-HSZ" : true, "TW-HUA" : true, "TW-ILA" : true, "TW-KEE" : true, "TW-KHH" : true, + "TW-KHQ" : true, "TW-MIA" : true, "TW-NAN" : true, "TW-PEN" : true, "TW-PIF" : true, + "TW-TAO" : true, "TW-TNN" : true, "TW-TNQ" : true, "TW-TPE" : true, "TW-TPQ" : true, + "TW-TTT" : true, "TW-TXG" : true, "TW-TXQ" : true, "TW-YUN" : true, "TZ-01" : true, + "TZ-02" : true, "TZ-03" : true, "TZ-04" : true, "TZ-05" : true, "TZ-06" : true, + "TZ-07" : true, "TZ-08" : true, "TZ-09" : true, "TZ-10" : true, "TZ-11" : true, + "TZ-12" : true, "TZ-13" : true, "TZ-14" : true, "TZ-15" : true, "TZ-16" : true, + "TZ-17" : true, "TZ-18" : true, "TZ-19" : true, "TZ-20" : true, "TZ-21" : true, + "TZ-22" : true, "TZ-23" : true, "TZ-24" : true, "TZ-25" : true, "TZ-26" : true, + "UA-05" : true, "UA-07" : true, "UA-09" : true, "UA-12" : true, "UA-14" : true, + "UA-18" : true, "UA-21" : true, "UA-23" : true, "UA-26" : true, "UA-30" : true, + "UA-32" : true, "UA-35" : true, "UA-40" : true, "UA-43" : true, "UA-46" : true, + "UA-48" : true, "UA-51" : true, "UA-53" : true, "UA-56" : true, "UA-59" : true, + "UA-61" : true, "UA-63" : true, "UA-65" : true, "UA-68" : true, "UA-71" : true, + "UA-74" : true, "UA-77" : true, "UG-101" : true, "UG-102" : true, "UG-103" : true, + "UG-104" : true, "UG-105" : true, "UG-106" : true, "UG-107" : true, "UG-108" : true, + "UG-109" : true, "UG-110" : true, "UG-111" : true, "UG-112" : true, "UG-113" : true, + "UG-114" : true, "UG-115" : true, "UG-116" : true, "UG-201" : true, "UG-202" : true, + "UG-203" : true, "UG-204" : true, "UG-205" : true, "UG-206" : true, "UG-207" : true, + "UG-208" : true, "UG-209" : true, "UG-210" : true, "UG-211" : true, "UG-212" : true, + "UG-213" : true, "UG-214" : true, "UG-215" : true, "UG-216" : true, "UG-217" : true, + "UG-218" : true, "UG-219" : true, "UG-220" : true, "UG-221" : true, "UG-222" : true, + "UG-223" : true, "UG-224" : true, "UG-301" : true, "UG-302" : true, "UG-303" : true, + "UG-304" : true, "UG-305" : true, "UG-306" : true, "UG-307" : true, "UG-308" : true, + "UG-309" : true, "UG-310" : true, "UG-311" : true, "UG-312" : true, "UG-313" : true, + "UG-314" : true, "UG-315" : true, "UG-316" : true, "UG-317" : true, "UG-318" : true, + "UG-319" : true, "UG-320" : true, "UG-321" : true, "UG-401" : true, "UG-402" : true, + "UG-403" : true, "UG-404" : true, "UG-405" : true, "UG-406" : true, "UG-407" : true, + "UG-408" : true, "UG-409" : true, "UG-410" : true, "UG-411" : true, "UG-412" : true, + "UG-413" : true, "UG-414" : true, "UG-415" : true, "UG-416" : true, "UG-417" : true, + "UG-418" : true, "UG-419" : true, "UG-C" : true, "UG-E" : true, "UG-N" : true, + "UG-W" : true, "UM-67" : true, "UM-71" : true, "UM-76" : true, "UM-79" : true, + "UM-81" : true, "UM-84" : true, "UM-86" : true, "UM-89" : true, "UM-95" : true, + "US-AK" : true, "US-AL" : true, "US-AR" : true, "US-AS" : true, "US-AZ" : true, + "US-CA" : true, "US-CO" : true, "US-CT" : true, "US-DC" : true, "US-DE" : true, + "US-FL" : true, "US-GA" : true, "US-GU" : true, "US-HI" : true, "US-IA" : true, + "US-ID" : true, "US-IL" : true, "US-IN" : true, "US-KS" : true, "US-KY" : true, + "US-LA" : true, "US-MA" : true, "US-MD" : true, "US-ME" : true, "US-MI" : true, + "US-MN" : true, "US-MO" : true, "US-MP" : true, "US-MS" : true, "US-MT" : true, + "US-NC" : true, "US-ND" : true, "US-NE" : true, "US-NH" : true, "US-NJ" : true, + "US-NM" : true, "US-NV" : true, "US-NY" : true, "US-OH" : true, "US-OK" : true, + "US-OR" : true, "US-PA" : true, "US-PR" : true, "US-RI" : true, "US-SC" : true, + "US-SD" : true, "US-TN" : true, "US-TX" : true, "US-UM" : true, "US-UT" : true, + "US-VA" : true, "US-VI" : true, "US-VT" : true, "US-WA" : true, "US-WI" : true, + "US-WV" : true, "US-WY" : true, "UY-AR" : true, "UY-CA" : true, "UY-CL" : true, + "UY-CO" : true, "UY-DU" : true, "UY-FD" : true, "UY-FS" : true, "UY-LA" : true, + "UY-MA" : true, "UY-MO" : true, "UY-PA" : true, "UY-RN" : true, "UY-RO" : true, + "UY-RV" : true, "UY-SA" : true, "UY-SJ" : true, "UY-SO" : true, "UY-TA" : true, + "UY-TT" : true, "UZ-AN" : true, "UZ-BU" : true, "UZ-FA" : true, "UZ-JI" : true, + "UZ-NG" : true, "UZ-NW" : true, "UZ-QA" : true, "UZ-QR" : true, "UZ-SA" : true, + "UZ-SI" : true, "UZ-SU" : true, "UZ-TK" : true, "UZ-TO" : true, "UZ-XO" : true, + "VC-01" : true, "VC-02" : true, "VC-03" : true, "VC-04" : true, "VC-05" : true, + "VC-06" : true, "VE-A" : true, "VE-B" : true, "VE-C" : true, "VE-D" : true, + "VE-E" : true, "VE-F" : true, "VE-G" : true, "VE-H" : true, "VE-I" : true, + "VE-J" : true, "VE-K" : true, "VE-L" : true, "VE-M" : true, "VE-N" : true, + "VE-O" : true, "VE-P" : true, "VE-R" : true, "VE-S" : true, "VE-T" : true, + "VE-U" : true, "VE-V" : true, "VE-W" : true, "VE-X" : true, "VE-Y" : true, + "VE-Z" : true, "VN-01" : true, "VN-02" : true, "VN-03" : true, "VN-04" : true, + "VN-05" : true, "VN-06" : true, "VN-07" : true, "VN-09" : true, "VN-13" : true, + "VN-14" : true, "VN-15" : true, "VN-18" : true, "VN-20" : true, "VN-21" : true, + "VN-22" : true, "VN-23" : true, "VN-24" : true, "VN-25" : true, "VN-26" : true, + "VN-27" : true, "VN-28" : true, "VN-29" : true, "VN-30" : true, "VN-31" : true, + "VN-32" : true, "VN-33" : true, "VN-34" : true, "VN-35" : true, "VN-36" : true, + "VN-37" : true, "VN-39" : true, "VN-40" : true, "VN-41" : true, "VN-43" : true, + "VN-44" : true, "VN-45" : true, "VN-46" : true, "VN-47" : true, "VN-49" : true, + "VN-50" : true, "VN-51" : true, "VN-52" : true, "VN-53" : true, "VN-54" : true, + "VN-55" : true, "VN-56" : true, "VN-57" : true, "VN-58" : true, "VN-59" : true, + "VN-61" : true, "VN-63" : true, "VN-66" : true, "VN-67" : true, "VN-68" : true, + "VN-69" : true, "VN-70" : true, "VN-71" : true, "VN-72" : true, "VN-73" : true, + "VN-CT" : true, "VN-DN" : true, "VN-HN" : true, "VN-HP" : true, "VN-SG" : true, + "VU-MAP" : true, "VU-PAM" : true, "VU-SAM" : true, "VU-SEE" : true, "VU-TAE" : true, + "VU-TOB" : true, "WS-AA" : true, "WS-AL" : true, "WS-AT" : true, "WS-FA" : true, + "WS-GE" : true, "WS-GI" : true, "WS-PA" : true, "WS-SA" : true, "WS-TU" : true, + "WS-VF" : true, "WS-VS" : true, "YE-AB" : true, "YE-AD" : true, "YE-AM" : true, + "YE-BA" : true, "YE-DA" : true, "YE-DH" : true, "YE-HD" : true, "YE-HJ" : true, + "YE-IB" : true, "YE-JA" : true, "YE-LA" : true, "YE-MA" : true, "YE-MR" : true, + "YE-MU" : true, "YE-MW" : true, "YE-RA" : true, "YE-SD" : true, "YE-SH" : true, + "YE-SN" : true, "YE-TA" : true, "ZA-EC" : true, "ZA-FS" : true, "ZA-GP" : true, + "ZA-LP" : true, "ZA-MP" : true, "ZA-NC" : true, "ZA-NW" : true, "ZA-WC" : true, + "ZA-ZN" : true, "ZM-01" : true, "ZM-02" : true, "ZM-03" : true, "ZM-04" : true, + "ZM-05" : true, "ZM-06" : true, "ZM-07" : true, "ZM-08" : true, "ZM-09" : true, + "ZW-BU" : true, "ZW-HA" : true, "ZW-MA" : true, "ZW-MC" : true, "ZW-ME" : true, + "ZW-MI" : true, "ZW-MN" : true, "ZW-MS" : true, "ZW-MV" : true, "ZW-MW" : true, +} diff --git a/doc.go b/doc.go index a816c20..eafad0d 100644 --- a/doc.go +++ b/doc.go @@ -1221,6 +1221,20 @@ Usage: iso3166_1_alpha3 +BCP 47 Language Tag + +This validates that a string value is a valid BCP 47 language tag, as parsed by language.Parse. +More information on https://pkg.go.dev/golang.org/x/text/language + + Usage: bcp47_language_tag + +BIC (SWIFT code) + +This validates that a string value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362. +More information on https://www.iso.org/standard/60390.html + + Usage: bic + TimeZone This validates that a string value is a valid time zone based on the time zone database present on the system. @@ -1228,7 +1242,7 @@ More information on https://golang.org/pkg/time/#LoadLocation Usage: timezone - + Alias Validators and Tags diff --git a/errors.go b/errors.go index 63293cf..9a1b1ab 100644 --- a/errors.go +++ b/errors.go @@ -82,7 +82,7 @@ // FieldError contains all functions to get error details type FieldError interface { - // returns the validation tag that failed. if the + // Tag returns the validation tag that failed. if the // validation was an alias, this will return the // alias name and not the underlying tag that failed. // @@ -90,7 +90,7 @@ // will return "iscolor" Tag() string - // returns the validation tag that failed, even if an + // ActualTag returns the validation tag that failed, even if an // alias the actual tag within the alias will be returned. // If an 'or' validation fails the entire or will be returned. // @@ -98,7 +98,7 @@ // will return "hexcolor|rgb|rgba|hsl|hsla" ActualTag() string - // returns the namespace for the field error, with the tag + // Namespace returns the namespace for the field error, with the tag // name taking precedence over the field's actual name. // // eg. JSON name "User.fname" @@ -109,7 +109,7 @@ // using validate.Field(...) as there is no way to extract it's name Namespace() string - // returns the namespace for the field error, with the field's + // StructNamespace returns the namespace for the field error, with the field's // actual name. // // eq. "User.FirstName" see Namespace for comparison @@ -118,24 +118,24 @@ // using validate.Field(...) as there is no way to extract its name StructNamespace() string - // returns the fields name with the tag name taking precedence over the + // Field returns the fields name with the tag name taking precedence over the // field's actual name. // // eq. JSON name "fname" // see StructField for comparison Field() string - // returns the field's actual name from the struct, when able to determine. + // StructField returns the field's actual name from the struct, when able to determine. // // eq. "FirstName" // see Field for comparison StructField() string - // returns the actual field's value in case needed for creating the error + // Value returns the actual field's value in case needed for creating the error // message Value() interface{} - // returns the param value, in string form for comparison; this will also + // Param returns the param value, in string form for comparison; this will also // help with generating an error message Param() string @@ -146,10 +146,10 @@ // Type returns the Field's reflect Type // - // // eg. time.Time's type is time.Time + // eg. time.Time's type is time.Time Type() reflect.Type - // returns the FieldError's translated error + // Translate returns the FieldError's translated error // from the provided 'ut.Translator' and registered 'TranslationFunc' // // NOTE: if no registered translator can be found it returns the same as @@ -221,7 +221,7 @@ // return fld } -// returns the field's actual name from the struct, when able to determine. +// StructField returns the field's actual name from the struct, when able to determine. func (fe *fieldError) StructField() string { // return fe.structField return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] diff --git a/field_level.go b/field_level.go index f0e2a9a..ef35826 100644 --- a/field_level.go +++ b/field_level.go @@ -5,24 +5,25 @@ // FieldLevel contains all the information and helper functions // to validate a field type FieldLevel interface { - // returns the top level struct, if any + + // Top returns the top level struct, if any Top() reflect.Value - // returns the current fields parent struct, if any or + // Parent returns the current fields parent struct, if any or // the comparison value if called 'VarWithValue' Parent() reflect.Value - // returns current field for validation + // Field returns current field for validation Field() reflect.Value - // returns the field's name with the tag + // FieldName returns the field's name with the tag // name taking precedence over the fields actual name. FieldName() string - // returns the struct field's name + // StructFieldName returns the struct field's name StructFieldName() string - // returns param for validation against current field + // Param returns param for validation against current field Param() string // GetTag returns the current validations tag name @@ -33,7 +34,7 @@ // underlying value and it's kind. ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) - // traverses the parent struct to retrieve a specific field denoted by the provided namespace + // GetStructFieldOK traverses the parent struct to retrieve a specific field denoted by the provided namespace // in the param and returns the field, field kind and whether is was successful in retrieving // the field at all. // @@ -49,7 +50,7 @@ // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) - // traverses the parent struct to retrieve a specific field denoted by the provided namespace + // GetStructFieldOK2 traverses the parent struct to retrieve a specific field denoted by the provided namespace // in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving // the field at all. // @@ -57,7 +58,7 @@ // could not be retrieved because it didn't exist. GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) - // GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for + // GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for // the field and namespace allowing more extensibility for validators. GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) } @@ -107,12 +108,12 @@ return current, kind, found } -// GetStructFieldOK returns Param returns param for validation against current field +// GetStructFieldOK2 returns Param returns param for validation against current field func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) { return v.getStructFieldOKInternal(v.slflParent, v.ct.param) } -// GetStructFieldOKAdvanced is the same as GetStructFieldOK except that it accepts the parent struct to start looking for +// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for // the field and namespace allowing more extensibility for validators. func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { return v.getStructFieldOKInternal(val, namespace) diff --git a/go.mod b/go.mod index d457100..53c4820 100644 --- a/go.mod +++ b/go.mod @@ -8,4 +8,5 @@ github.com/go-playground/universal-translator v0.17.0 github.com/leodido/go-urn v1.2.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/text v0.3.2 // indirect ) diff --git a/go.sum b/go.sum index 0152642..4b00cf6 100644 --- a/go.sum +++ b/go.sum @@ -10,17 +10,22 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/postcode_regexes.go b/postcode_regexes.go new file mode 100644 index 0000000..e7e7b68 --- /dev/null +++ b/postcode_regexes.go @@ -0,0 +1,173 @@ +package validator + +import "regexp" + +var postCodePatternDict = map[string]string{ + "GB": `^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$`, + "JE": `^JE\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, + "GG": `^GY\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, + "IM": `^IM\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}$`, + "US": `^\d{5}([ \-]\d{4})?$`, + "CA": `^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ ]?\d[ABCEGHJ-NPRSTV-Z]\d$`, + "DE": `^\d{5}$`, + "JP": `^\d{3}-\d{4}$`, + "FR": `^\d{2}[ ]?\d{3}$`, + "AU": `^\d{4}$`, + "IT": `^\d{5}$`, + "CH": `^\d{4}$`, + "AT": `^\d{4}$`, + "ES": `^\d{5}$`, + "NL": `^\d{4}[ ]?[A-Z]{2}$`, + "BE": `^\d{4}$`, + "DK": `^\d{4}$`, + "SE": `^\d{3}[ ]?\d{2}$`, + "NO": `^\d{4}$`, + "BR": `^\d{5}[\-]?\d{3}$`, + "PT": `^\d{4}([\-]\d{3})?$`, + "FI": `^\d{5}$`, + "AX": `^22\d{3}$`, + "KR": `^\d{3}[\-]\d{3}$`, + "CN": `^\d{6}$`, + "TW": `^\d{3}(\d{2})?$`, + "SG": `^\d{6}$`, + "DZ": `^\d{5}$`, + "AD": `^AD\d{3}$`, + "AR": `^([A-HJ-NP-Z])?\d{4}([A-Z]{3})?$`, + "AM": `^(37)?\d{4}$`, + "AZ": `^\d{4}$`, + "BH": `^((1[0-2]|[2-9])\d{2})?$`, + "BD": `^\d{4}$`, + "BB": `^(BB\d{5})?$`, + "BY": `^\d{6}$`, + "BM": `^[A-Z]{2}[ ]?[A-Z0-9]{2}$`, + "BA": `^\d{5}$`, + "IO": `^BBND 1ZZ$`, + "BN": `^[A-Z]{2}[ ]?\d{4}$`, + "BG": `^\d{4}$`, + "KH": `^\d{5}$`, + "CV": `^\d{4}$`, + "CL": `^\d{7}$`, + "CR": `^\d{4,5}|\d{3}-\d{4}$`, + "HR": `^\d{5}$`, + "CY": `^\d{4}$`, + "CZ": `^\d{3}[ ]?\d{2}$`, + "DO": `^\d{5}$`, + "EC": `^([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?$`, + "EG": `^\d{5}$`, + "EE": `^\d{5}$`, + "FO": `^\d{3}$`, + "GE": `^\d{4}$`, + "GR": `^\d{3}[ ]?\d{2}$`, + "GL": `^39\d{2}$`, + "GT": `^\d{5}$`, + "HT": `^\d{4}$`, + "HN": `^(?:\d{5})?$`, + "HU": `^\d{4}$`, + "IS": `^\d{3}$`, + "IN": `^\d{6}$`, + "ID": `^\d{5}$`, + "IL": `^\d{5}$`, + "JO": `^\d{5}$`, + "KZ": `^\d{6}$`, + "KE": `^\d{5}$`, + "KW": `^\d{5}$`, + "LA": `^\d{5}$`, + "LV": `^\d{4}$`, + "LB": `^(\d{4}([ ]?\d{4})?)?$`, + "LI": `^(948[5-9])|(949[0-7])$`, + "LT": `^\d{5}$`, + "LU": `^\d{4}$`, + "MK": `^\d{4}$`, + "MY": `^\d{5}$`, + "MV": `^\d{5}$`, + "MT": `^[A-Z]{3}[ ]?\d{2,4}$`, + "MU": `^(\d{3}[A-Z]{2}\d{3})?$`, + "MX": `^\d{5}$`, + "MD": `^\d{4}$`, + "MC": `^980\d{2}$`, + "MA": `^\d{5}$`, + "NP": `^\d{5}$`, + "NZ": `^\d{4}$`, + "NI": `^((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?$`, + "NG": `^(\d{6})?$`, + "OM": `^(PC )?\d{3}$`, + "PK": `^\d{5}$`, + "PY": `^\d{4}$`, + "PH": `^\d{4}$`, + "PL": `^\d{2}-\d{3}$`, + "PR": `^00[679]\d{2}([ \-]\d{4})?$`, + "RO": `^\d{6}$`, + "RU": `^\d{6}$`, + "SM": `^4789\d$`, + "SA": `^\d{5}$`, + "SN": `^\d{5}$`, + "SK": `^\d{3}[ ]?\d{2}$`, + "SI": `^\d{4}$`, + "ZA": `^\d{4}$`, + "LK": `^\d{5}$`, + "TJ": `^\d{6}$`, + "TH": `^\d{5}$`, + "TN": `^\d{4}$`, + "TR": `^\d{5}$`, + "TM": `^\d{6}$`, + "UA": `^\d{5}$`, + "UY": `^\d{5}$`, + "UZ": `^\d{6}$`, + "VA": `^00120$`, + "VE": `^\d{4}$`, + "ZM": `^\d{5}$`, + "AS": `^96799$`, + "CC": `^6799$`, + "CK": `^\d{4}$`, + "RS": `^\d{6}$`, + "ME": `^8\d{4}$`, + "CS": `^\d{5}$`, + "YU": `^\d{5}$`, + "CX": `^6798$`, + "ET": `^\d{4}$`, + "FK": `^FIQQ 1ZZ$`, + "NF": `^2899$`, + "FM": `^(9694[1-4])([ \-]\d{4})?$`, + "GF": `^9[78]3\d{2}$`, + "GN": `^\d{3}$`, + "GP": `^9[78][01]\d{2}$`, + "GS": `^SIQQ 1ZZ$`, + "GU": `^969[123]\d([ \-]\d{4})?$`, + "GW": `^\d{4}$`, + "HM": `^\d{4}$`, + "IQ": `^\d{5}$`, + "KG": `^\d{6}$`, + "LR": `^\d{4}$`, + "LS": `^\d{3}$`, + "MG": `^\d{3}$`, + "MH": `^969[67]\d([ \-]\d{4})?$`, + "MN": `^\d{6}$`, + "MP": `^9695[012]([ \-]\d{4})?$`, + "MQ": `^9[78]2\d{2}$`, + "NC": `^988\d{2}$`, + "NE": `^\d{4}$`, + "VI": `^008(([0-4]\d)|(5[01]))([ \-]\d{4})?$`, + "VN": `^[0-9]{1,6}$`, + "PF": `^987\d{2}$`, + "PG": `^\d{3}$`, + "PM": `^9[78]5\d{2}$`, + "PN": `^PCRN 1ZZ$`, + "PW": `^96940$`, + "RE": `^9[78]4\d{2}$`, + "SH": `^(ASCN|STHL) 1ZZ$`, + "SJ": `^\d{4}$`, + "SO": `^\d{5}$`, + "SZ": `^[HLMS]\d{3}$`, + "TC": `^TKCA 1ZZ$`, + "WF": `^986\d{2}$`, + "XK": `^\d{5}$`, + "YT": `^976\d{2}$`, +} + +var postCodeRegexDict = map[string]*regexp.Regexp{} + +func init() { + for countryCode, pattern := range postCodePatternDict { + postCodeRegexDict[countryCode] = regexp.MustCompile(pattern) + } +} diff --git a/regexes.go b/regexes.go index b741f4e..ddcf785 100644 --- a/regexes.go +++ b/regexes.go @@ -10,7 +10,7 @@ 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]{6})$" 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*\\)$" @@ -45,10 +45,11 @@ ethAddressRegexString = `^0x[0-9a-fA-F]{40}$` ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` ethAddressLowerRegexString = `^0x[0-9a-f]{40}$` - uRLEncodedRegexString = `(%[A-Fa-f0-9]{2})` + uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$` hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` splitParamsRegexString = `'[^']*'|\S+` + bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` ) var ( @@ -59,7 +60,7 @@ numericRegex = regexp.MustCompile(numericRegexString) numberRegex = regexp.MustCompile(numberRegexString) hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) - hexcolorRegex = regexp.MustCompile(hexcolorRegexString) + hexColorRegex = regexp.MustCompile(hexColorRegexString) rgbRegex = regexp.MustCompile(rgbRegexString) rgbaRegex = regexp.MustCompile(rgbaRegexString) hslRegex = regexp.MustCompile(hslRegexString) @@ -92,10 +93,11 @@ btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) ethAddressRegex = regexp.MustCompile(ethAddressRegexString) - ethaddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) + ethAddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString) ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString) uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString) splitParamsRegex = regexp.MustCompile(splitParamsRegexString) + bicRegex = regexp.MustCompile(bicRegexString) ) diff --git a/struct_level.go b/struct_level.go index 57691ee..c0d89cf 100644 --- a/struct_level.go +++ b/struct_level.go @@ -23,18 +23,18 @@ // to validate a struct type StructLevel interface { - // returns the main validation object, in case one wants to call validations internally. + // Validator returns the main validation object, in case one wants to call validations internally. // this is so you don't have to use anonymous functions to get access to the validate // instance. Validator() *Validate - // returns the top level struct, if any + // Top returns the top level struct, if any Top() reflect.Value - // returns the current fields parent struct, if any + // Parent returns the current fields parent struct, if any Parent() reflect.Value - // returns the current struct. + // Current returns the current struct. Current() reflect.Value // ExtractType gets the actual underlying type of field value. @@ -42,7 +42,7 @@ // underlying value and its kind. ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) - // reports an error just by passing the field and tag information + // ReportError reports an error just by passing the field and tag information // // NOTES: // @@ -54,7 +54,7 @@ // and process on the flip side it's up to you. ReportError(field interface{}, fieldName, structFieldName string, tag, param string) - // reports an error just by passing ValidationErrors + // ReportValidationErrors reports an error just by passing ValidationErrors // // NOTES: // diff --git a/translations/en/en.go b/translations/en/en.go index 1fdea95..3bbca51 100644 --- a/translations/en/en.go +++ b/translations/en/en.go @@ -16,7 +16,6 @@ // 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 @@ -32,7 +31,6 @@ { tag: "len", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil { return } @@ -61,10 +59,8 @@ } return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string @@ -123,7 +119,6 @@ { tag: "min", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil { return } @@ -152,10 +147,8 @@ } return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string @@ -214,7 +207,6 @@ { tag: "max", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("max-string", "{0} must be a maximum of {1} in length", false); err != nil { return } @@ -243,10 +235,8 @@ } return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string @@ -307,7 +297,6 @@ translation: "{0} is not equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) @@ -322,7 +311,6 @@ translation: "{0} should not be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe) @@ -335,7 +323,6 @@ { tag: "lt", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil { return } @@ -369,10 +356,8 @@ } return - - }, - customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { var err error var t string var f64 float64 @@ -380,7 +365,6 @@ var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -456,7 +440,6 @@ { tag: "lte", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil { return } @@ -492,7 +475,6 @@ return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -500,7 +482,6 @@ var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -576,7 +557,6 @@ { tag: "gt", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil { return } @@ -612,7 +592,6 @@ return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -620,7 +599,6 @@ var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -696,7 +674,6 @@ { tag: "gte", customRegisFunc: func(ut ut.Translator) (err error) { - if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil { return } @@ -732,7 +709,6 @@ return }, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - var err error var t string var f64 float64 @@ -740,7 +716,6 @@ var kind reflect.Kind fn := func() (err error) { - if idx := strings.Index(fe.Param(), "."); idx != -1 { digits = uint64(len(fe.Param()[idx+1:])) } @@ -818,7 +793,6 @@ translation: "{0} must be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -833,7 +807,6 @@ translation: "{0} must be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -848,7 +821,6 @@ translation: "{0} cannot be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -863,7 +835,6 @@ translation: "{0} must be greater than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -878,7 +849,6 @@ translation: "{0} must be greater than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -893,7 +863,6 @@ translation: "{0} must be less than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -908,7 +877,6 @@ translation: "{0} must be less than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -923,7 +891,6 @@ translation: "{0} cannot be equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -938,7 +905,6 @@ translation: "{0} must be greater than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -953,7 +919,6 @@ translation: "{0} must be greater than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -968,7 +933,6 @@ translation: "{0} must be less than {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -983,7 +947,6 @@ translation: "{0} must be less than or equal to {1}", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1073,7 +1036,6 @@ translation: "{0} must contain the text '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1088,7 +1050,6 @@ translation: "{0} must contain at least one of the following characters '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1103,7 +1064,6 @@ translation: "{0} cannot contain the text '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1118,7 +1078,6 @@ translation: "{0} cannot contain any of the following characters '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1133,7 +1092,6 @@ translation: "{0} cannot contain the following '{1}'", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1325,8 +1283,8 @@ tag: "json", translation: "{0} must be a valid json string", override: false, - }, - { + }, + { tag: "lowercase", translation: "{0} must be a lowercase string", override: false, @@ -1341,7 +1299,34 @@ translation: "{0} does not match the {1} format", override: false, customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { - + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "postcode_iso3166_alpha2", + translation: "{0} does not match postcode format of {1} country", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "postcode_iso3166_alpha2_field", + translation: "{0} does not match postcode format of country in {1} field", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) if err != nil { log.Printf("warning: error translating FieldError: %#v", fe) @@ -1356,17 +1341,11 @@ 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) } @@ -1380,21 +1359,16 @@ } 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) diff --git a/translations/en/en_test.go b/translations/en/en_test.go index 2b113c6..fd8df77 100644 --- a/translations/en/en_test.go +++ b/translations/en/en_test.go @@ -11,7 +11,6 @@ ) func TestTranslations(t *testing.T) { - eng := english.New() uni := ut.New(eng, eng) trans, _ := uni.GetTranslator("en") @@ -145,6 +144,9 @@ LowercaseString string `validate:"lowercase"` UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` + PostCode string `validate:"postcode_iso3166_alpha2=SG"` + PostCodeCountry string + PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` } var test Test @@ -655,6 +657,14 @@ { ns: "Test.Datetime", expected: "Datetime does not match the 2006-01-02 format", + }, + { + ns: "Test.PostCode", + expected: "PostCode does not match postcode format of SG country", + }, + { + ns: "Test.PostCodeByField", + expected: "PostCodeByField does not match postcode format of country in PostCodeCountry field", }, } @@ -672,5 +682,4 @@ NotEqual(t, fe, nil) Equal(t, tt.expected, fe.Translate(trans)) } - } diff --git a/translations/fa/fa.go b/translations/fa/fa.go new file mode 100644 index 0000000..fc21aa0 --- /dev/null +++ b/translations/fa/fa.go @@ -0,0 +1,1379 @@ +package fa + +import ( + "fmt" + "log" + "reflect" + "strconv" + "strings" + "time" + + "github.com/go-playground/locales" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" +) + +// RegisterDefaultTranslations registers a set of default translations +// for all built in tag's in validator; you may add your own as desired. +func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) { + translations := []struct { + tag string + translation string + override bool + customRegisFunc validator.RegisterTranslationsFunc + customTransFunc validator.TranslationFunc + }{ + { + tag: "required", + translation: "فیلد {0} اجباری میباشد", + override: false, + }, + { + tag: "len", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("len-string", "طول {0} باید {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("len-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("len-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("len-number", "طول {0} باید برابر {1} باشد", false); err != nil { + return + } + + if err = ut.Add("len-items", "تعداد {0} باید برابر {1} باشد", false); err != nil { + return + } + if err = ut.AddCardinal("len-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("len-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + + var digits uint64 + var kind reflect.Kind + + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err := strconv.ParseFloat(fe.Param(), 64) + if err != nil { + goto END + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + c, err = ut.C("len-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("len-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + c, err = ut.C("len-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("len-items", fe.Field(), c) + + default: + t, err = ut.T("len-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "min", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("min-string", "طول {0} باید حداقل {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("min-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("min-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("min-number", "{0} باید بزرگتر یا برابر {1} باشد", false); err != nil { + return + } + + if err = ut.Add("min-items", "{0} باید شامل حداقل {1} باشد", false); err != nil { + return + } + if err = ut.AddCardinal("min-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("min-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + + var digits uint64 + var kind reflect.Kind + + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err := strconv.ParseFloat(fe.Param(), 64) + if err != nil { + goto END + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + c, err = ut.C("min-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("min-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + c, err = ut.C("min-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("min-items", fe.Field(), c) + + default: + t, err = ut.T("min-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "max", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("max-string", "طول {0} باید حداکثر {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("max-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("max-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("max-number", "{0} باید کمتر یا برابر {1} باشد", false); err != nil { + return + } + + if err = ut.Add("max-items", "{0} باید شامل حداکثر {1} باشد", false); err != nil { + return + } + if err = ut.AddCardinal("max-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("max-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + + var digits uint64 + var kind reflect.Kind + + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err := strconv.ParseFloat(fe.Param(), 64) + if err != nil { + goto END + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + c, err = ut.C("max-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("max-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + c, err = ut.C("max-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("max-items", fe.Field(), c) + + default: + t, err = ut.T("max-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "eq", + translation: "{0} برابر {1} نمیباشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + fmt.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "ne", + translation: "{0} نباید برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + fmt.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "lt", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("lt-string", "طول {0} باید کمتر از {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("lt-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("lt-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("lt-number", "{0} باید کمتر از {1} باشد", false); err != nil { + return + } + + if err = ut.Add("lt-items", "{0} باید دارای کمتر از {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("lt-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("lt-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("lt-datetime", "{0} باید قبل از تاریخ و زمان کنونی باشد", false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var f64 float64 + var digits uint64 + var kind reflect.Kind + + fn := func() (err error) { + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err = strconv.ParseFloat(fe.Param(), 64) + + return + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("lt-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("lt-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("lt-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("lt-items", fe.Field(), c) + + case reflect.Struct: + if fe.Type() != reflect.TypeOf(time.Time{}) { + err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) + goto END + } + + t, err = ut.T("lt-datetime", fe.Field()) + + default: + err = fn() + if err != nil { + goto END + } + + t, err = ut.T("lt-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "lte", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("lte-string", "طول {0} باید حداکثر {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("lte-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("lte-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("lte-number", "{0} باید کمتر یا برابر {1} باشد", false); err != nil { + return + } + + if err = ut.Add("lte-items", "{0} باید حداکثر شامل {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("lte-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("lte-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("lte-datetime", "{0} باید قبل یا برابر تاریخ و زمان کنونی باشد", false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var f64 float64 + var digits uint64 + var kind reflect.Kind + + fn := func() (err error) { + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err = strconv.ParseFloat(fe.Param(), 64) + + return + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("lte-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("lte-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("lte-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("lte-items", fe.Field(), c) + + case reflect.Struct: + if fe.Type() != reflect.TypeOf(time.Time{}) { + err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) + goto END + } + + t, err = ut.T("lte-datetime", fe.Field()) + + default: + err = fn() + if err != nil { + goto END + } + + t, err = ut.T("lte-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "gt", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("gt-string", "طول {0} باید بیشتر از {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("gt-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("gt-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("gt-number", "{0} باید بیشتر از {1} باشد", false); err != nil { + return + } + + if err = ut.Add("gt-items", "{0} باید دارای بیشتر از {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("gt-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("gt-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("gt-datetime", "{0} باید بعد از تاریخ و زمان کنونی باشد", false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var f64 float64 + var digits uint64 + var kind reflect.Kind + + fn := func() (err error) { + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err = strconv.ParseFloat(fe.Param(), 64) + + return + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("gt-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("gt-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("gt-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("gt-items", fe.Field(), c) + + case reflect.Struct: + if fe.Type() != reflect.TypeOf(time.Time{}) { + err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) + goto END + } + + t, err = ut.T("gt-datetime", fe.Field()) + + default: + err = fn() + if err != nil { + goto END + } + + t, err = ut.T("gt-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "gte", + customRegisFunc: func(ut ut.Translator) (err error) { + if err = ut.Add("gte-string", "طول {0} باید حداقل {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("gte-string-character", "{0} کاراکتر", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("gte-string-character", "{0} کاراکتر", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("gte-number", "{0} باید بیشتر یا برابر {1} باشد", false); err != nil { + return + } + + if err = ut.Add("gte-items", "{0} باید شامل حداقل {1} باشد", false); err != nil { + return + } + + if err = ut.AddCardinal("gte-items-item", "{0} آیتم", locales.PluralRuleOne, false); err != nil { + return + } + + if err = ut.AddCardinal("gte-items-item", "{0} آیتم", locales.PluralRuleOther, false); err != nil { + return + } + + if err = ut.Add("gte-datetime", "{0} باید بعد یا برابر تاریخ و زمان کنونی باشد", false); err != nil { + return + } + + return + }, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + var err error + var t string + var f64 float64 + var digits uint64 + var kind reflect.Kind + + fn := func() (err error) { + if idx := strings.Index(fe.Param(), "."); idx != -1 { + digits = uint64(len(fe.Param()[idx+1:])) + } + + f64, err = strconv.ParseFloat(fe.Param(), 64) + + return + } + + kind = fe.Kind() + if kind == reflect.Ptr { + kind = fe.Type().Elem().Kind() + } + + switch kind { + case reflect.String: + + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("gte-string-character", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("gte-string", fe.Field(), c) + + case reflect.Slice, reflect.Map, reflect.Array: + var c string + + err = fn() + if err != nil { + goto END + } + + c, err = ut.C("gte-items-item", f64, digits, ut.FmtNumber(f64, digits)) + if err != nil { + goto END + } + + t, err = ut.T("gte-items", fe.Field(), c) + + case reflect.Struct: + if fe.Type() != reflect.TypeOf(time.Time{}) { + err = fmt.Errorf("tag '%s' cannot be used on a struct type", fe.Tag()) + goto END + } + + t, err = ut.T("gte-datetime", fe.Field()) + + default: + err = fn() + if err != nil { + goto END + } + + t, err = ut.T("gte-number", fe.Field(), ut.FmtNumber(f64, digits)) + } + + END: + if err != nil { + fmt.Printf("warning: error translating FieldError: %s", err) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "eqfield", + translation: "{0} باید برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "eqcsfield", + translation: "{0} باید برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "necsfield", + translation: "{0} نمیتواند برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "gtcsfield", + translation: "طول {0} باید بیشتر از {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "gtecsfield", + translation: "طول {0} باید بیشتر یا برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "ltcsfield", + translation: "طول {0} باید کمتر از {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "ltecsfield", + translation: "طول {0} باید کمتر یا برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "nefield", + translation: "{0} نمیتواند برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "gtfield", + translation: "طول {0} باید بیشتر از {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "gtefield", + translation: "طول {0} باید بیشتر یا برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "ltfield", + translation: "طول {0} باید کمتر از {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "ltefield", + translation: "طول {0} باید کمتر یا برابر {1} باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "alpha", + translation: "{0} میتواند فقط شامل حروف باشد", + override: false, + }, + { + tag: "alphanum", + translation: "{0} میتواند فقط شامل حروف و اعداد باشد", + override: false, + }, + { + tag: "numeric", + translation: "{0} باید یک عدد معتبر باشد", + override: false, + }, + { + tag: "number", + translation: "{0} باید یک عدد معتبر باشد", + override: false, + }, + { + tag: "hexadecimal", + translation: "{0} باید یک عدد درمبنای16 باشد", + override: false, + }, + { + tag: "hexcolor", + translation: "{0} باید یک کد رنگ HEX باشد", + override: false, + }, + { + tag: "rgb", + translation: "{0} باید یک کد رنگ RGB باشد", + override: false, + }, + { + tag: "rgba", + translation: "{0} باید یک کد رنگ RGBA باشد", + override: false, + }, + { + tag: "hsl", + translation: "{0} باید یک کد رنگ HSL باشد", + override: false, + }, + { + tag: "hsla", + translation: "{0} باید یک کد رنگ HSLA باشد", + override: false, + }, + { + tag: "e164", + translation: "{0} باید یک شماره‌تلفن معتبر با فرمت E.164 باشد", + override: false, + }, + { + tag: "email", + translation: "{0} باید یک ایمیل معتبر باشد", + override: false, + }, + { + tag: "url", + translation: "{0} باید یک آدرس اینترنتی معتبر باشد", + override: false, + }, + { + tag: "uri", + translation: "{0} باید یک URI معتبر باشد", + override: false, + }, + { + tag: "base64", + translation: "{0} باید یک متن درمبنای64 معتبر باشد", + override: false, + }, + { + tag: "contains", + translation: "{0} باید شامل '{1}' باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "containsany", + translation: "{0} باید شامل کاراکترهای '{1}' باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "excludes", + translation: "{0} نمیتواند شامل '{1}' باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "excludesall", + translation: "{0} نمیتواند شامل کاراکترهای '{1}' باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "excludesrune", + translation: "{0} نمیتواند شامل '{1}' باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "isbn", + translation: "{0} باید یک شابک معتبر باشد", + override: false, + }, + { + tag: "isbn10", + translation: "{0} باید یک شابک(ISBN-10) معتبر باشد", + override: false, + }, + { + tag: "isbn13", + translation: "{0} باید یک شابک(ISBN-13) معتبر باشد", + override: false, + }, + { + tag: "uuid", + translation: "{0} باید یک UUID معتبر باشد", + override: false, + }, + { + tag: "uuid3", + translation: "{0} باید یک UUID نسخه 3 معتبر باشد", + override: false, + }, + { + tag: "uuid4", + translation: "{0} باید یک UUID نسخه 4 معتبر باشد", + override: false, + }, + { + tag: "uuid5", + translation: "{0} باید یک UUID نسخه 5 معتبر باشد", + override: false, + }, + { + tag: "ascii", + translation: "{0} باید فقط شامل کاراکترهای اسکی باشد", + override: false, + }, + { + tag: "printascii", + translation: "{0} باید فقط شامل کاراکترهای اسکی قابل چاپ باشد", + override: false, + }, + { + tag: "multibyte", + translation: "{0} باید شامل کاراکترهای چندبایته باشد", + override: false, + }, + { + tag: "datauri", + translation: "{0} باید یک Data URI معتبر باشد", + override: false, + }, + { + tag: "latitude", + translation: "{0} باید یک عرض جغرافیایی معتبر باشد", + override: false, + }, + { + tag: "longitude", + translation: "{0} باید یک طول جغرافیایی معتبر باشد", + override: false, + }, + { + tag: "ssn", + translation: "{0} باید یک شماره SSN معتبر باشد", + override: false, + }, + { + tag: "ipv4", + translation: "{0} باید یک آدرس آی‌پی IPv4 معتبر باشد", + override: false, + }, + { + tag: "ipv6", + translation: "{0} باید یک آدرس آی‌پی IPv6 معتبر باشد", + override: false, + }, + { + tag: "ip", + translation: "{0} باید یک آدرس آی‌پی معتبر باشد", + override: false, + }, + { + tag: "cidr", + translation: "{0} باید یک نشانه‌گذاری CIDR معتبر باشد", + override: false, + }, + { + tag: "cidrv4", + translation: "{0} باید یک نشانه‌گذاری CIDR معتبر برای آدرس آی‌پی IPv4 باشد", + override: false, + }, + { + tag: "cidrv6", + translation: "{0} باید یک نشانه‌گذاری CIDR معتبر برای آدرس آی‌پی IPv6 باشد", + override: false, + }, + { + tag: "tcp_addr", + translation: "{0} باید یک آدرس TCP معتبر باشد", + override: false, + }, + { + tag: "tcp4_addr", + translation: "{0} باید یک آدرس TCP IPv4 معتبر باشد", + override: false, + }, + { + tag: "tcp6_addr", + translation: "{0} باید یک آدرس TCP IPv6 معتبر باشد", + override: false, + }, + { + tag: "udp_addr", + translation: "{0} باید یک آدرس UDP معتبر باشد", + override: false, + }, + { + tag: "udp4_addr", + translation: "{0} باید یک آدرس UDP IPv4 معتبر باشد", + override: false, + }, + { + tag: "udp6_addr", + translation: "{0} باید یک آدرس UDP IPv6 معتبر باشد", + override: false, + }, + { + tag: "ip_addr", + translation: "{0} باید یک آدرس آی‌پی قابل دسترس باشد", + override: false, + }, + { + tag: "ip4_addr", + translation: "{0} باید یک آدرس آی‌پی IPv4 قابل دسترس باشد", + override: false, + }, + { + tag: "ip6_addr", + translation: "{0} باید یک آدرس آی‌پی IPv6 قابل دسترس باشد", + override: false, + }, + { + tag: "unix_addr", + translation: "{0} باید یک آدرس UNIX معتبر باشد", + override: false, + }, + { + tag: "mac", + translation: "{0} باید یک مک‌آدرس معتبر باشد", + override: false, + }, + { + tag: "unique", + translation: "{0} باید شامل مقادیر منحصربفرد باشد", + override: false, + }, + { + tag: "iscolor", + translation: "{0} باید یک رنگ معتبر باشد", + override: false, + }, + { + tag: "oneof", + translation: "{0} باید یکی از مقادیر [{1}] باشد", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + s, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + return s + }, + }, + { + tag: "json", + translation: "{0} باید یک json معتبر باشد", + override: false, + }, + { + tag: "lowercase", + translation: "{0} باید یک متن با حروف کوچک باشد", + override: false, + }, + { + tag: "uppercase", + translation: "{0} باید یک متن با حروف بزرگ باشد", + override: false, + }, + { + tag: "datetime", + translation: "فرمت {0} با {1} سازگار نیست", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "postcode_iso3166_alpha2", + translation: "{0} یک کدپستی معتبر کشور {1} نیست", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + { + tag: "postcode_iso3166_alpha2_field", + translation: "{0} یک کدپستی معتبر کشور فیلد {1} نیست", + override: false, + customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t + }, + }, + } + + for _, t := range translations { + + if t.customTransFunc != nil && t.customRegisFunc != nil { + err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) + } else if t.customTransFunc != nil && t.customRegisFunc == nil { + err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) + } else if t.customTransFunc == nil && t.customRegisFunc != nil { + err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) + } else { + err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) + } + + if err != nil { + return + } + } + + return +} + +func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { + return func(ut ut.Translator) (err error) { + if err = ut.Add(tag, translation, override); err != nil { + return + } + + return + } +} + +func translateFunc(ut ut.Translator, fe validator.FieldError) string { + t, err := ut.T(fe.Tag(), fe.Field()) + if err != nil { + log.Printf("warning: error translating FieldError: %#v", fe) + return fe.(error).Error() + } + + return t +} diff --git a/translations/fa/fa_test.go b/translations/fa/fa_test.go new file mode 100644 index 0000000..611f23e --- /dev/null +++ b/translations/fa/fa_test.go @@ -0,0 +1,685 @@ +package fa + +import ( + "testing" + "time" + + . "github.com/go-playground/assert/v2" + english "github.com/go-playground/locales/en" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" +) + +func TestTranslations(t *testing.T) { + eng := english.New() + uni := ut.New(eng, eng) + trans, _ := uni.GetTranslator("en") + + validate := validator.New() + + err := RegisterDefaultTranslations(validate, trans) + Equal(t, err, nil) + + type Inner struct { + EqCSFieldString string + NeCSFieldString string + GtCSFieldString string + GteCSFieldString string + LtCSFieldString string + LteCSFieldString string + } + + type Test struct { + Inner Inner + RequiredString string `validate:"required"` + RequiredNumber int `validate:"required"` + RequiredMultiple []string `validate:"required"` + LenString string `validate:"len=1"` + LenNumber float64 `validate:"len=1113.00"` + LenMultiple []string `validate:"len=7"` + MinString string `validate:"min=1"` + MinNumber float64 `validate:"min=1113.00"` + MinMultiple []string `validate:"min=7"` + MaxString string `validate:"max=3"` + MaxNumber float64 `validate:"max=1113.00"` + MaxMultiple []string `validate:"max=7"` + EqString string `validate:"eq=3"` + EqNumber float64 `validate:"eq=2.33"` + EqMultiple []string `validate:"eq=7"` + NeString string `validate:"ne="` + NeNumber float64 `validate:"ne=0.00"` + NeMultiple []string `validate:"ne=0"` + LtString string `validate:"lt=3"` + LtNumber float64 `validate:"lt=5.56"` + LtMultiple []string `validate:"lt=2"` + LtTime time.Time `validate:"lt"` + LteString string `validate:"lte=3"` + LteNumber float64 `validate:"lte=5.56"` + LteMultiple []string `validate:"lte=2"` + LteTime time.Time `validate:"lte"` + GtString string `validate:"gt=3"` + GtNumber float64 `validate:"gt=5.56"` + GtMultiple []string `validate:"gt=2"` + GtTime time.Time `validate:"gt"` + GteString string `validate:"gte=3"` + GteNumber float64 `validate:"gte=5.56"` + GteMultiple []string `validate:"gte=2"` + GteTime time.Time `validate:"gte"` + EqFieldString string `validate:"eqfield=MaxString"` + EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` + NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` + GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` + GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` + LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` + LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` + NeFieldString string `validate:"nefield=EqFieldString"` + GtFieldString string `validate:"gtfield=MaxString"` + GteFieldString string `validate:"gtefield=MaxString"` + LtFieldString string `validate:"ltfield=MaxString"` + LteFieldString string `validate:"ltefield=MaxString"` + AlphaString string `validate:"alpha"` + AlphanumString string `validate:"alphanum"` + NumericString string `validate:"numeric"` + NumberString string `validate:"number"` + HexadecimalString string `validate:"hexadecimal"` + HexColorString string `validate:"hexcolor"` + RGBColorString string `validate:"rgb"` + RGBAColorString string `validate:"rgba"` + HSLColorString string `validate:"hsl"` + HSLAColorString string `validate:"hsla"` + Email string `validate:"email"` + URL string `validate:"url"` + URI string `validate:"uri"` + Base64 string `validate:"base64"` + Contains string `validate:"contains=purpose"` + ContainsAny string `validate:"containsany=!@#$"` + Excludes string `validate:"excludes=text"` + ExcludesAll string `validate:"excludesall=!@#$"` + ExcludesRune string `validate:"excludesrune=☻"` + ISBN string `validate:"isbn"` + ISBN10 string `validate:"isbn10"` + ISBN13 string `validate:"isbn13"` + UUID string `validate:"uuid"` + UUID3 string `validate:"uuid3"` + UUID4 string `validate:"uuid4"` + UUID5 string `validate:"uuid5"` + ASCII string `validate:"ascii"` + PrintableASCII string `validate:"printascii"` + MultiByte string `validate:"multibyte"` + DataURI string `validate:"datauri"` + Latitude string `validate:"latitude"` + Longitude string `validate:"longitude"` + SSN string `validate:"ssn"` + IP string `validate:"ip"` + IPv4 string `validate:"ipv4"` + IPv6 string `validate:"ipv6"` + CIDR string `validate:"cidr"` + CIDRv4 string `validate:"cidrv4"` + CIDRv6 string `validate:"cidrv6"` + TCPAddr string `validate:"tcp_addr"` + TCPAddrv4 string `validate:"tcp4_addr"` + TCPAddrv6 string `validate:"tcp6_addr"` + UDPAddr string `validate:"udp_addr"` + UDPAddrv4 string `validate:"udp4_addr"` + UDPAddrv6 string `validate:"udp6_addr"` + IPAddr string `validate:"ip_addr"` + IPAddrv4 string `validate:"ip4_addr"` + IPAddrv6 string `validate:"ip6_addr"` + UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future + MAC string `validate:"mac"` + IsColor string `validate:"iscolor"` + StrPtrMinLen *string `validate:"min=10"` + StrPtrMaxLen *string `validate:"max=1"` + StrPtrLen *string `validate:"len=2"` + StrPtrLt *string `validate:"lt=1"` + StrPtrLte *string `validate:"lte=1"` + StrPtrGt *string `validate:"gt=10"` + StrPtrGte *string `validate:"gte=10"` + OneOfString string `validate:"oneof=red green"` + OneOfInt int `validate:"oneof=5 63"` + UniqueSlice []string `validate:"unique"` + UniqueArray [3]string `validate:"unique"` + UniqueMap map[string]string `validate:"unique"` + JSONString string `validate:"json"` + LowercaseString string `validate:"lowercase"` + UppercaseString string `validate:"uppercase"` + Datetime string `validate:"datetime=2006-01-02"` + PostCode string `validate:"postcode_iso3166_alpha2=SG"` + PostCodeCountry string + PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"` + } + + var test Test + + test.Inner.EqCSFieldString = "1234" + test.Inner.GtCSFieldString = "1234" + test.Inner.GteCSFieldString = "1234" + + test.MaxString = "1234" + test.MaxNumber = 2000 + test.MaxMultiple = make([]string, 9) + + test.LtString = "1234" + test.LtNumber = 6 + test.LtMultiple = make([]string, 3) + test.LtTime = time.Now().Add(time.Hour * 24) + + test.LteString = "1234" + test.LteNumber = 6 + test.LteMultiple = make([]string, 3) + test.LteTime = time.Now().Add(time.Hour * 24) + + test.LtFieldString = "12345" + test.LteFieldString = "12345" + + test.LtCSFieldString = "1234" + test.LteCSFieldString = "1234" + + test.AlphaString = "abc3" + test.AlphanumString = "abc3!" + test.NumericString = "12E.00" + test.NumberString = "12E" + + test.Excludes = "this is some test text" + test.ExcludesAll = "This is Great!" + test.ExcludesRune = "Love it ☻" + + test.ASCII = "カタカナ" + test.PrintableASCII = "カタカナ" + + test.MultiByte = "1234feerf" + + test.LowercaseString = "ABCDEFG" + test.UppercaseString = "abcdefg" + + s := "toolong" + test.StrPtrMaxLen = &s + test.StrPtrLen = &s + + test.UniqueSlice = []string{"1234", "1234"} + test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} + test.Datetime = "2008-Feb-01" + + err = validate.Struct(test) + NotEqual(t, err, nil) + + errs, ok := err.(validator.ValidationErrors) + Equal(t, ok, true) + + tests := []struct { + ns string + expected string + }{ + { + ns: "Test.IsColor", + expected: "IsColor باید یک رنگ معتبر باشد", + }, + { + ns: "Test.MAC", + expected: "MAC باید یک مک‌آدرس معتبر باشد", + }, + { + ns: "Test.IPAddr", + expected: "IPAddr باید یک آدرس آی‌پی قابل دسترس باشد", + }, + { + ns: "Test.IPAddrv4", + expected: "IPAddrv4 باید یک آدرس آی‌پی IPv4 قابل دسترس باشد", + }, + { + ns: "Test.IPAddrv6", + expected: "IPAddrv6 باید یک آدرس آی‌پی IPv6 قابل دسترس باشد", + }, + { + ns: "Test.UDPAddr", + expected: "UDPAddr باید یک آدرس UDP معتبر باشد", + }, + { + ns: "Test.UDPAddrv4", + expected: "UDPAddrv4 باید یک آدرس UDP IPv4 معتبر باشد", + }, + { + ns: "Test.UDPAddrv6", + expected: "UDPAddrv6 باید یک آدرس UDP IPv6 معتبر باشد", + }, + { + ns: "Test.TCPAddr", + expected: "TCPAddr باید یک آدرس TCP معتبر باشد", + }, + { + ns: "Test.TCPAddrv4", + expected: "TCPAddrv4 باید یک آدرس TCP IPv4 معتبر باشد", + }, + { + ns: "Test.TCPAddrv6", + expected: "TCPAddrv6 باید یک آدرس TCP IPv6 معتبر باشد", + }, + { + ns: "Test.CIDR", + expected: "CIDR باید یک نشانه‌گذاری CIDR معتبر باشد", + }, + { + ns: "Test.CIDRv4", + expected: "CIDRv4 باید یک نشانه‌گذاری CIDR معتبر برای آدرس آی‌پی IPv4 باشد", + }, + { + ns: "Test.CIDRv6", + expected: "CIDRv6 باید یک نشانه‌گذاری CIDR معتبر برای آدرس آی‌پی IPv6 باشد", + }, + { + ns: "Test.SSN", + expected: "SSN باید یک شماره SSN معتبر باشد", + }, + { + ns: "Test.IP", + expected: "IP باید یک آدرس آی‌پی معتبر باشد", + }, + { + ns: "Test.IPv4", + expected: "IPv4 باید یک آدرس آی‌پی IPv4 معتبر باشد", + }, + { + ns: "Test.IPv6", + expected: "IPv6 باید یک آدرس آی‌پی IPv6 معتبر باشد", + }, + { + ns: "Test.DataURI", + expected: "DataURI باید یک Data URI معتبر باشد", + }, + { + ns: "Test.Latitude", + expected: "Latitude باید یک عرض جغرافیایی معتبر باشد", + }, + { + ns: "Test.Longitude", + expected: "Longitude باید یک طول جغرافیایی معتبر باشد", + }, + { + ns: "Test.MultiByte", + expected: "MultiByte باید شامل کاراکترهای چندبایته باشد", + }, + { + ns: "Test.ASCII", + expected: "ASCII باید فقط شامل کاراکترهای اسکی باشد", + }, + { + ns: "Test.PrintableASCII", + expected: "PrintableASCII باید فقط شامل کاراکترهای اسکی قابل چاپ باشد", + }, + { + ns: "Test.UUID", + expected: "UUID باید یک UUID معتبر باشد", + }, + { + ns: "Test.UUID3", + expected: "UUID3 باید یک UUID نسخه 3 معتبر باشد", + }, + { + ns: "Test.UUID4", + expected: "UUID4 باید یک UUID نسخه 4 معتبر باشد", + }, + { + ns: "Test.UUID5", + expected: "UUID5 باید یک UUID نسخه 5 معتبر باشد", + }, + { + ns: "Test.ISBN", + expected: "ISBN باید یک شابک معتبر باشد", + }, + { + ns: "Test.ISBN10", + expected: "ISBN10 باید یک شابک(ISBN-10) معتبر باشد", + }, + { + ns: "Test.ISBN13", + expected: "ISBN13 باید یک شابک(ISBN-13) معتبر باشد", + }, + { + ns: "Test.Excludes", + expected: "Excludes نمیتواند شامل 'text' باشد", + }, + { + ns: "Test.ExcludesAll", + expected: "ExcludesAll نمیتواند شامل کاراکترهای '!@#$' باشد", + }, + { + ns: "Test.ExcludesRune", + expected: "ExcludesRune نمیتواند شامل '☻' باشد", + }, + { + ns: "Test.ContainsAny", + expected: "ContainsAny باید شامل کاراکترهای '!@#$' باشد", + }, + { + ns: "Test.Contains", + expected: "Contains باید شامل 'purpose' باشد", + }, + { + ns: "Test.Base64", + expected: "Base64 باید یک متن درمبنای64 معتبر باشد", + }, + { + ns: "Test.Email", + expected: "Email باید یک ایمیل معتبر باشد", + }, + { + ns: "Test.URL", + expected: "URL باید یک آدرس اینترنتی معتبر باشد", + }, + { + ns: "Test.URI", + expected: "URI باید یک URI معتبر باشد", + }, + { + ns: "Test.RGBColorString", + expected: "RGBColorString باید یک کد رنگ RGB باشد", + }, + { + ns: "Test.RGBAColorString", + expected: "RGBAColorString باید یک کد رنگ RGBA باشد", + }, + { + ns: "Test.HSLColorString", + expected: "HSLColorString باید یک کد رنگ HSL باشد", + }, + { + ns: "Test.HSLAColorString", + expected: "HSLAColorString باید یک کد رنگ HSLA باشد", + }, + { + ns: "Test.HexadecimalString", + expected: "HexadecimalString باید یک عدد درمبنای16 باشد", + }, + { + ns: "Test.HexColorString", + expected: "HexColorString باید یک کد رنگ HEX باشد", + }, + { + ns: "Test.NumberString", + expected: "NumberString باید یک عدد معتبر باشد", + }, + { + ns: "Test.NumericString", + expected: "NumericString باید یک عدد معتبر باشد", + }, + { + ns: "Test.AlphanumString", + expected: "AlphanumString میتواند فقط شامل حروف و اعداد باشد", + }, + { + ns: "Test.AlphaString", + expected: "AlphaString میتواند فقط شامل حروف باشد", + }, + { + ns: "Test.LtFieldString", + expected: "طول LtFieldString باید کمتر از MaxString باشد", + }, + { + ns: "Test.LteFieldString", + expected: "طول LteFieldString باید کمتر یا برابر MaxString باشد", + }, + { + ns: "Test.GtFieldString", + expected: "طول GtFieldString باید بیشتر از MaxString باشد", + }, + { + ns: "Test.GteFieldString", + expected: "طول GteFieldString باید بیشتر یا برابر MaxString باشد", + }, + { + ns: "Test.NeFieldString", + expected: "NeFieldString نمیتواند برابر EqFieldString باشد", + }, + { + ns: "Test.LtCSFieldString", + expected: "طول LtCSFieldString باید کمتر از Inner.LtCSFieldString باشد", + }, + { + ns: "Test.LteCSFieldString", + expected: "طول LteCSFieldString باید کمتر یا برابر Inner.LteCSFieldString باشد", + }, + { + ns: "Test.GtCSFieldString", + expected: "طول GtCSFieldString باید بیشتر از Inner.GtCSFieldString باشد", + }, + { + ns: "Test.GteCSFieldString", + expected: "طول GteCSFieldString باید بیشتر یا برابر Inner.GteCSFieldString باشد", + }, + { + ns: "Test.NeCSFieldString", + expected: "NeCSFieldString نمیتواند برابر Inner.NeCSFieldString باشد", + }, + { + ns: "Test.EqCSFieldString", + expected: "EqCSFieldString باید برابر Inner.EqCSFieldString باشد", + }, + { + ns: "Test.EqFieldString", + expected: "EqFieldString باید برابر MaxString باشد", + }, + { + ns: "Test.GteString", + expected: "طول GteString باید حداقل 3 کاراکتر باشد", + }, + { + ns: "Test.GteNumber", + expected: "GteNumber باید بیشتر یا برابر 5.56 باشد", + }, + { + ns: "Test.GteMultiple", + expected: "GteMultiple باید شامل حداقل 2 آیتم باشد", + }, + { + ns: "Test.GteTime", + expected: "GteTime باید بعد یا برابر تاریخ و زمان کنونی باشد", + }, + { + ns: "Test.GtString", + expected: "طول GtString باید بیشتر از 3 کاراکتر باشد", + }, + { + ns: "Test.GtNumber", + expected: "GtNumber باید بیشتر از 5.56 باشد", + }, + { + ns: "Test.GtMultiple", + expected: "GtMultiple باید دارای بیشتر از 2 آیتم باشد", + }, + { + ns: "Test.GtTime", + expected: "GtTime باید بعد از تاریخ و زمان کنونی باشد", + }, + { + ns: "Test.LteString", + expected: "طول LteString باید حداکثر 3 کاراکتر باشد", + }, + { + ns: "Test.LteNumber", + expected: "LteNumber باید کمتر یا برابر 5.56 باشد", + }, + { + ns: "Test.LteMultiple", + expected: "LteMultiple باید حداکثر شامل 2 آیتم باشد", + }, + { + ns: "Test.LteTime", + expected: "LteTime باید قبل یا برابر تاریخ و زمان کنونی باشد", + }, + { + ns: "Test.LtString", + expected: "طول LtString باید کمتر از 3 کاراکتر باشد", + }, + { + ns: "Test.LtNumber", + expected: "LtNumber باید کمتر از 5.56 باشد", + }, + { + ns: "Test.LtMultiple", + expected: "LtMultiple باید دارای کمتر از 2 آیتم باشد", + }, + { + ns: "Test.LtTime", + expected: "LtTime باید قبل از تاریخ و زمان کنونی باشد", + }, + { + ns: "Test.NeString", + expected: "NeString نباید برابر باشد", + }, + { + ns: "Test.NeNumber", + expected: "NeNumber نباید برابر 0.00 باشد", + }, + { + ns: "Test.NeMultiple", + expected: "NeMultiple نباید برابر 0 باشد", + }, + { + ns: "Test.EqString", + expected: "EqString برابر 3 نمیباشد", + }, + { + ns: "Test.EqNumber", + expected: "EqNumber برابر 2.33 نمیباشد", + }, + { + ns: "Test.EqMultiple", + expected: "EqMultiple برابر 7 نمیباشد", + }, + { + ns: "Test.MaxString", + expected: "طول MaxString باید حداکثر 3 کاراکتر باشد", + }, + { + ns: "Test.MaxNumber", + expected: "MaxNumber باید کمتر یا برابر 1,113.00 باشد", + }, + { + ns: "Test.MaxMultiple", + expected: "MaxMultiple باید شامل حداکثر 7 آیتم باشد", + }, + { + ns: "Test.MinString", + expected: "طول MinString باید حداقل 1 کاراکتر باشد", + }, + { + ns: "Test.MinNumber", + expected: "MinNumber باید بزرگتر یا برابر 1,113.00 باشد", + }, + { + ns: "Test.MinMultiple", + expected: "MinMultiple باید شامل حداقل 7 آیتم باشد", + }, + { + ns: "Test.LenString", + expected: "طول LenString باید 1 کاراکتر باشد", + }, + { + ns: "Test.LenNumber", + expected: "طول LenNumber باید برابر 1,113.00 باشد", + }, + { + ns: "Test.LenMultiple", + expected: "تعداد LenMultiple باید برابر 7 آیتم باشد", + }, + { + ns: "Test.RequiredString", + expected: "فیلد RequiredString اجباری میباشد", + }, + { + ns: "Test.RequiredNumber", + expected: "فیلد RequiredNumber اجباری میباشد", + }, + { + ns: "Test.RequiredMultiple", + expected: "فیلد RequiredMultiple اجباری میباشد", + }, + { + ns: "Test.StrPtrMinLen", + expected: "طول StrPtrMinLen باید حداقل 10 کاراکتر باشد", + }, + { + ns: "Test.StrPtrMaxLen", + expected: "طول StrPtrMaxLen باید حداکثر 1 کاراکتر باشد", + }, + { + ns: "Test.StrPtrLen", + expected: "طول StrPtrLen باید 2 کاراکتر باشد", + }, + { + ns: "Test.StrPtrLt", + expected: "طول StrPtrLt باید کمتر از 1 کاراکتر باشد", + }, + { + ns: "Test.StrPtrLte", + expected: "طول StrPtrLte باید حداکثر 1 کاراکتر باشد", + }, + { + ns: "Test.StrPtrGt", + expected: "طول StrPtrGt باید بیشتر از 10 کاراکتر باشد", + }, + { + ns: "Test.StrPtrGte", + expected: "طول StrPtrGte باید حداقل 10 کاراکتر باشد", + }, + { + ns: "Test.OneOfString", + expected: "OneOfString باید یکی از مقادیر [red green] باشد", + }, + { + ns: "Test.OneOfInt", + expected: "OneOfInt باید یکی از مقادیر [5 63] باشد", + }, + { + ns: "Test.UniqueSlice", + expected: "UniqueSlice باید شامل مقادیر منحصربفرد باشد", + }, + { + ns: "Test.UniqueArray", + expected: "UniqueArray باید شامل مقادیر منحصربفرد باشد", + }, + { + ns: "Test.UniqueMap", + expected: "UniqueMap باید شامل مقادیر منحصربفرد باشد", + }, + { + ns: "Test.JSONString", + expected: "JSONString باید یک json معتبر باشد", + }, + { + ns: "Test.LowercaseString", + expected: "LowercaseString باید یک متن با حروف کوچک باشد", + }, + { + ns: "Test.UppercaseString", + expected: "UppercaseString باید یک متن با حروف بزرگ باشد", + }, + { + ns: "Test.Datetime", + expected: "فرمت Datetime با 2006-01-02 سازگار نیست", + }, + { + ns: "Test.PostCode", + expected: "PostCode یک کدپستی معتبر کشور SG نیست", + }, + { + ns: "Test.PostCodeByField", + expected: "PostCodeByField یک کدپستی معتبر کشور فیلد PostCodeCountry نیست", + }, + } + + for _, tt := range tests { + + var fe validator.FieldError + + for _, e := range errs { + if tt.ns == e.Namespace() { + fe = e + break + } + } + + NotEqual(t, fe, nil) + Equal(t, tt.expected, fe.Translate(trans)) + } +} diff --git a/translations/ja/ja.go b/translations/ja/ja.go index 43ec648..7b887c0 100644 --- a/translations/ja/ja.go +++ b/translations/ja/ja.go @@ -1226,7 +1226,7 @@ }, { tag: "uuid5", - translation: "{0}はバージョンが4の正しいUUIDでなければなりません", + translation: "{0}はバージョンが5の正しいUUIDでなければなりません", override: false, }, { diff --git a/translations/ja/ja_test.go b/translations/ja/ja_test.go index 0120760..eaa2743 100644 --- a/translations/ja/ja_test.go +++ b/translations/ja/ja_test.go @@ -304,7 +304,7 @@ }, { ns: "Test.UUID5", - expected: "UUID5はバージョンが4の正しいUUIDでなければなりません", + expected: "UUID5はバージョンが5の正しいUUIDでなければなりません", }, { ns: "Test.ISBN", diff --git a/validator.go b/validator.go index f097f39..2a4fad0 100644 --- a/validator.go +++ b/validator.go @@ -74,7 +74,7 @@ } } - v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags) + v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags) } } @@ -222,12 +222,12 @@ structNs = append(append(structNs, cf.name...), '.') } - v.validateStruct(ctx, current, current, typ, ns, structNs, ct) - return - } - } - - if !ct.hasTag { + v.validateStruct(ctx, parent, current, typ, ns, structNs, ct) + return + } + } + + if ct == nil || !ct.hasTag { return } diff --git a/validator_instance.go b/validator_instance.go index fe6a487..8e27707 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -29,6 +29,10 @@ requiredWithAllTag = "required_with_all" requiredIfTag = "required_if" requiredUnlessTag = "required_unless" + excludedWithoutAllTag = "excluded_without_all" + excludedWithoutTag = "excluded_without" + excludedWithTag = "excluded_with" + excludedWithAllTag = "excluded_with_all" skipValidationTag = "-" diveTag = "dive" keysTag = "keys" @@ -111,7 +115,8 @@ 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: + case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag, + excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag: _ = v.registerValidation(k, wrapFunc(val), true, true) default: // no need to error check here, baked in will always be valid @@ -136,6 +141,33 @@ // SetTagName allows for changing of the default tag name of 'validate' func (v *Validate) SetTagName(name string) { v.tagName = name +} + +// ValidateMapCtx validates a map using a map of validation rules and allows passing of contextual +// validation validation information via context.Context. +func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} { + errs := make(map[string]interface{}) + for field, rule := range rules { + if reflect.ValueOf(rule).Kind() == reflect.Map && reflect.ValueOf(data[field]).Kind() == reflect.Map { + err := v.ValidateMapCtx(ctx, data[field].(map[string]interface{}), rule.(map[string]interface{})) + if len(err) > 0 { + errs[field] = err + } + } else if reflect.ValueOf(rule).Kind() == reflect.Map { + errs[field] = errors.New("The field: '" + field + "' is not a map to dive") + } else { + err := v.VarCtx(ctx, data[field], rule.(string)) + if err != nil { + errs[field] = err + } + } + } + return errs +} + +// ValidateMap validates map data form 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) } // RegisterTagNameFunc registers a function to get alternate names for StructFields. @@ -409,7 +441,10 @@ if len(flds) > 0 { vd.misc = append(vd.misc[0:0], name...) - vd.misc = append(vd.misc, '.') + // Don't append empty name for unnamed structs + if len(vd.misc) != 0 { + vd.misc = append(vd.misc, '.') + } for _, s := range flds { diff --git a/validator_test.go b/validator_test.go index 6c9fb1e..3f0ea8d 100644 --- a/validator_test.go +++ b/validator_test.go @@ -14,6 +14,7 @@ "testing" "time" + "github.com/go-playground/assert/v2" . "github.com/go-playground/assert/v2" "github.com/go-playground/locales/en" "github.com/go-playground/locales/fr" @@ -108,7 +109,6 @@ } func AssertError(t *testing.T, err error, nsKey, structNsKey, field, structField, expectedTag string) { - errs := err.(ValidationErrors) found := false @@ -150,7 +150,6 @@ } func getError(err error, nsKey, structNsKey string) FieldError { - errs := err.(ValidationErrors) var fe FieldError @@ -170,7 +169,6 @@ } func (v valuer) Value() (driver.Value, error) { - if v.Name == "errorme" { panic("SQL Driver Valuer error: some kind of error") // return nil, errors.New("some kind of error") @@ -189,7 +187,6 @@ } func ValidateCustomType(field reflect.Value) interface{} { - if cust, ok := field.Interface().(MadeUpCustomType); ok { if len(cust.FirstName) == 0 || len(cust.LastName) == 0 { @@ -203,7 +200,6 @@ } func OverrideIntTypeForSomeReason(field reflect.Value) interface{} { - if i, ok := field.Interface().(int); ok { if i == 1 { return "1" @@ -223,7 +219,6 @@ } func ValidateValuerType(field reflect.Value) interface{} { - if valuer, ok := field.Interface().(driver.Valuer); ok { val, err := valuer.Value() @@ -261,7 +256,6 @@ } func StructValidationTestStructSuccess(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "good value" { @@ -270,7 +264,6 @@ } func StructValidationTestStruct(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { @@ -279,7 +272,6 @@ } func StructValidationNoTestStructCustomName(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { @@ -288,7 +280,6 @@ } func StructValidationTestStructInvalid(sl StructLevel) { - st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { @@ -297,7 +288,6 @@ } func StructValidationTestStructReturnValidationErrors(sl StructLevel) { - s := sl.Current().Interface().(TestStructReturnValidationErrors) errs := sl.Validator().Struct(s.Inner1.Inner2) @@ -309,7 +299,6 @@ } func StructValidationTestStructReturnValidationErrors2(sl StructLevel) { - s := sl.Current().Interface().(TestStructReturnValidationErrors) errs := sl.Validator().Struct(s.Inner1.Inner2) @@ -337,7 +326,6 @@ } func StructLevelInvalidError(sl StructLevel) { - top := sl.Top().Interface().(StructLevelInvalidErr) s := sl.Current().Interface().(StructLevelInvalidErr) @@ -359,7 +347,6 @@ } func TestStructLevelInvalidError(t *testing.T) { - validate := New() validate.RegisterStructValidation(StructLevelInvalidError, StructLevelInvalidErr{}) @@ -383,7 +370,6 @@ } func TestNameNamespace(t *testing.T) { - type Inner2Namespace struct { String []string `validate:"dive,required" json:"JSONString"` } @@ -432,7 +418,6 @@ } func TestAnonymous(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -500,7 +485,6 @@ } func TestAnonymousSameStructDifferentTags(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -545,7 +529,6 @@ } func TestStructLevelReturnValidationErrors(t *testing.T) { - validate := New() validate.RegisterStructValidation(StructValidationTestStructReturnValidationErrors, TestStructReturnValidationErrors{}) @@ -575,7 +558,6 @@ } func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -632,7 +614,6 @@ } func TestStructLevelValidations(t *testing.T) { - v1 := New() v1.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) @@ -666,7 +647,6 @@ } func TestAliasTags(t *testing.T) { - validate := New() validate.RegisterAlias("iscoloralias", "hexcolor|rgb|rgba|hsl|hsla") @@ -714,7 +694,6 @@ } func TestNilValidator(t *testing.T) { - type TestStruct struct { Test string `validate:"required"` } @@ -724,7 +703,6 @@ var val *Validate fn := func(fl FieldLevel) bool { - return fl.Parent().String() == fl.Field().String() } @@ -949,6 +927,38 @@ NotEqual(t, errs, nil) AssertError(t, errs, "TestPartial.Anonymous.SubAnonStruct[0].Test", "TestPartial.Anonymous.SubAnonStruct[0].Test", "Test", "Test", "required") + // Test for unnamed struct + testStruct := &TestStruct{ + String: "test", + } + unnamedStruct := struct { + String string `validate:"required" json:"StringVal"` + }{String: "test"} + composedUnnamedStruct := struct{ *TestStruct }{&TestStruct{String: "test"}} + + errs = validate.StructPartial(testStruct, "String") + Equal(t, errs, nil) + + errs = validate.StructPartial(unnamedStruct, "String") + Equal(t, errs, nil) + + errs = validate.StructPartial(composedUnnamedStruct, "TestStruct.String") + Equal(t, errs, nil) + + testStruct.String = "" + errs = validate.StructPartial(testStruct, "String") + NotEqual(t, errs, nil) + AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "required") + + unnamedStruct.String = "" + errs = validate.StructPartial(unnamedStruct, "String") + NotEqual(t, errs, nil) + AssertError(t, errs, "String", "String", "String", "String", "required") + + composedUnnamedStruct.String = "" + errs = validate.StructPartial(composedUnnamedStruct, "TestStruct.String") + NotEqual(t, errs, nil) + AssertError(t, errs, "TestStruct.String", "TestStruct.String", "String", "String", "required") } func TestCrossStructLteFieldValidation(t *testing.T) { @@ -1638,12 +1648,14 @@ i := 1 j = 1 k = 1.543 + b := true arr := []string{"test"} s2 := "abcd" i2 := 1 j2 = 1 k2 = 1.543 + b2 := true arr2 := []string{"test"} arr3 := []string{"test", "test2"} now2 := now @@ -1664,6 +1676,10 @@ NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") + errs = validate.VarWithValue(b2, b, "necsfield") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "necsfield") + errs = validate.VarWithValue(arr2, arr, "necsfield") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "necsfield") @@ -1789,7 +1805,7 @@ errs = validate.Struct(test) Equal(t, errs, nil) - newTime := time.Now().UTC() + newTime := time.Now().Add(time.Hour).UTC() test.CreatedAt = &newTime errs = validate.Struct(test) @@ -1802,6 +1818,7 @@ i := 1 j = 1 k = 1.543 + b := true arr := []string{"test"} var j2 uint64 @@ -1810,6 +1827,7 @@ i2 := 1 j2 = 1 k2 = 1.543 + b2 := true arr2 := []string{"test"} arr3 := []string{"test", "test2"} now2 := now @@ -1826,6 +1844,9 @@ errs = validate.VarWithValue(k2, k, "eqcsfield") Equal(t, errs, nil) + errs = validate.VarWithValue(b2, b, "eqcsfield") + Equal(t, errs, nil) + errs = validate.VarWithValue(arr2, arr, "eqcsfield") Equal(t, errs, nil) @@ -1928,7 +1949,6 @@ } func TestCrossNamespaceFieldValidation(t *testing.T) { - type SliceStruct struct { Name string } @@ -2166,7 +2186,6 @@ } func TestExistsValidation(t *testing.T) { - jsonText := "{ \"truthiness2\": true }" type Thing struct { @@ -2197,7 +2216,6 @@ } func TestSQLValue2Validation(t *testing.T) { - validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) @@ -2248,7 +2266,6 @@ } func TestSQLValueValidation(t *testing.T) { - validate := New() validate.RegisterCustomTypeFunc(ValidateValuerType, (*driver.Valuer)(nil), valuer{}) validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{}) @@ -2926,7 +2943,6 @@ } func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { - validate := New() var m map[string]string @@ -3004,7 +3020,6 @@ } func TestDatePtrValidationIssueValidation(t *testing.T) { - type Test struct { LastViewed *time.Time Reminder *time.Time @@ -3056,7 +3071,6 @@ } func TestInterfaceErrValidation(t *testing.T) { - var v2 interface{} = 1 var v1 interface{} = v2 @@ -3230,7 +3244,6 @@ } func TestMapDiveValidation(t *testing.T) { - validate := New() n := map[int]interface{}{0: nil} @@ -3271,6 +3284,21 @@ // for full test coverage s := fmt.Sprint(errs.Error()) NotEqual(t, s, "") + + type TestMapInterface struct { + Errs map[int]interface{} `validate:"dive"` + } + + mit := map[int]interface{}{0: Inner{"ok"}, 1: Inner{""}, 3: nil, 5: "string", 6: 33} + + msi := &TestMapInterface{ + Errs: mit, + } + + errs = validate.Struct(msi) + NotEqual(t, errs, nil) + Equal(t, len(errs.(ValidationErrors)), 1) + AssertError(t, errs, "TestMapInterface.Errs[1].Name", "TestMapInterface.Errs[1].Name", "Name", "Name", "required") type TestMapTimeStruct struct { Errs map[int]*time.Time `validate:"gt=0,dive,required"` @@ -3353,7 +3381,6 @@ } func TestArrayDiveValidation(t *testing.T) { - validate := New() arr := []string{"ok", "", "ok"} @@ -4362,7 +4389,6 @@ } func TestExcludesRuneValidation(t *testing.T) { - tests := []struct { Value string `validate:"excludesrune=☻"` Tag string @@ -4390,7 +4416,6 @@ } func TestExcludesAllValidation(t *testing.T) { - tests := []struct { Value string `validate:"excludesall=@!{}[]"` Tag string @@ -4436,7 +4461,6 @@ } func TestExcludesValidation(t *testing.T) { - tests := []struct { Value string `validate:"excludes=@"` Tag string @@ -4464,7 +4488,6 @@ } func TestContainsRuneValidation(t *testing.T) { - tests := []struct { Value string `validate:"containsrune=☻"` Tag string @@ -4492,7 +4515,6 @@ } func TestContainsAnyValidation(t *testing.T) { - tests := []struct { Value string `validate:"containsany=@!{}[]"` Tag string @@ -4520,7 +4542,6 @@ } func TestContainsValidation(t *testing.T) { - tests := []struct { Value string `validate:"contains=@"` Tag string @@ -4557,6 +4578,7 @@ i := 1 j = 1 k = 1.543 + b := true arr := []string{"test"} now := time.Now().UTC() @@ -4566,6 +4588,7 @@ i2 := 3 j2 = 2 k2 = 1.5434456 + b2 := false arr2 := []string{"test", "test2"} arr3 := []string{"test"} now2 := now @@ -4582,6 +4605,9 @@ errs = validate.VarWithValue(k2, k, "nefield") Equal(t, errs, nil) + errs = validate.VarWithValue(b2, b, "nefield") + Equal(t, errs, nil) + errs = validate.VarWithValue(arr2, arr, "nefield") Equal(t, errs, nil) @@ -4607,7 +4633,7 @@ NotEqual(t, errs, nil) AssertError(t, errs, "Test.Start", "Test.Start", "Start", "Start", "nefield") - now3 := time.Now().UTC() + now3 := time.Now().Add(time.Hour).UTC() sv = &Test{ Start: &now, @@ -4792,6 +4818,7 @@ i := 1 j = 1 k = 1.543 + b := true arr := []string{"test"} now := time.Now().UTC() @@ -4801,6 +4828,7 @@ i2 := 1 j2 = 1 k2 = 1.543 + b2 := true arr2 := []string{"test"} arr3 := []string{"test", "test2"} now2 := now @@ -4817,6 +4845,9 @@ errs = validate.VarWithValue(k2, k, "eqfield") Equal(t, errs, nil) + errs = validate.VarWithValue(b2, b, "eqfield") + Equal(t, errs, nil) + errs = validate.VarWithValue(arr2, arr, "eqfield") Equal(t, errs, nil) @@ -4840,7 +4871,7 @@ errs = validate.Struct(sv) Equal(t, errs, nil) - now3 := time.Now().UTC() + now3 := time.Now().Add(time.Hour).UTC() sv = &Test{ Start: &now, @@ -5096,7 +5127,6 @@ } func TestBase64Validation(t *testing.T) { - validate := New() s := "dW5pY29ybg==" @@ -5200,7 +5230,6 @@ } func TestEthereumAddressValidation(t *testing.T) { - validate := New() tests := []struct { @@ -5254,7 +5283,6 @@ } func TestBitcoinAddressValidation(t *testing.T) { - validate := New() tests := []struct { @@ -5364,7 +5392,6 @@ } func TestBitcoinBech32AddressValidation(t *testing.T) { - validate := New() tests := []struct { @@ -5415,7 +5442,6 @@ } func TestNoStructLevelValidation(t *testing.T) { - type Inner struct { Test string `validate:"len=5"` } @@ -5447,7 +5473,6 @@ } func TestStructOnlyValidation(t *testing.T) { - type Inner struct { Test string `validate:"len=5"` } @@ -6513,7 +6538,6 @@ Equal(t, errs, nil) fn := func(fl FieldLevel) bool { - return fl.Parent().String() == fl.Field().String() } @@ -6531,9 +6555,7 @@ } func TestAddFunctions(t *testing.T) { - fn := func(fl FieldLevel) bool { - return true } @@ -6562,7 +6584,6 @@ } func TestChangeTag(t *testing.T) { - validate := New() validate.SetTagName("val") @@ -7209,8 +7230,7 @@ } func TestUrnRFC2141(t *testing.T) { - - var tests = []struct { + tests := []struct { param string expected bool }{ @@ -7286,8 +7306,7 @@ } func TestUrl(t *testing.T) { - - var tests = []struct { + tests := []struct { param string expected bool }{ @@ -7354,8 +7373,7 @@ } func TestUri(t *testing.T) { - - var tests = []struct { + tests := []struct { param string expected bool }{ @@ -7421,7 +7439,6 @@ } func TestOrTag(t *testing.T) { - validate := New() s := "rgba(0,31,255,0.5)" @@ -7451,7 +7468,7 @@ Equal(t, errs, nil) s = "green" - errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") //should fail on first validation block + errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") // should fail on first validation block NotEqual(t, errs, nil) ve := errs.(ValidationErrors) Equal(t, len(ve), 1) @@ -7464,7 +7481,6 @@ v2 := New() v2.RegisterTagNameFunc(func(fld reflect.StructField) string { - name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { @@ -7489,7 +7505,6 @@ } func TestHsla(t *testing.T) { - validate := New() s := "hsla(360,100%,100%,1)" @@ -7536,7 +7551,6 @@ } func TestHsl(t *testing.T) { - validate := New() s := "hsl(360,100%,50%)" @@ -7574,7 +7588,6 @@ } func TestRgba(t *testing.T) { - validate := New() s := "rgba(0,31,255,0.5)" @@ -7620,7 +7633,6 @@ } func TestRgb(t *testing.T) { - validate := New() s := "rgb(0,31,255)" @@ -7662,7 +7674,6 @@ } func TestEmail(t *testing.T) { - validate := New() s := "test@mail.com" @@ -7730,7 +7741,6 @@ } func TestHexColor(t *testing.T) { - validate := New() s := "#fff" @@ -7758,7 +7768,6 @@ } func TestHexadecimal(t *testing.T) { - validate := New() s := "ff0044" @@ -7785,7 +7794,6 @@ } func TestNumber(t *testing.T) { - validate := New() s := "1" @@ -7833,7 +7841,6 @@ } func TestNumeric(t *testing.T) { - validate := New() s := "1" @@ -7876,7 +7883,6 @@ } func TestAlphaNumeric(t *testing.T) { - validate := New() s := "abcd123" @@ -7894,7 +7900,6 @@ } func TestAlpha(t *testing.T) { - validate := New() s := "abcd" @@ -7924,11 +7929,9 @@ errs = validate.Var(1, "alpha") NotEqual(t, errs, nil) AssertError(t, errs, "", "", "", "", "alpha") - } func TestStructStringValidation(t *testing.T) { - validate := New() tSuccess := &TestString{ @@ -8010,7 +8013,6 @@ } func TestStructInt32Validation(t *testing.T) { - type TestInt32 struct { Required int `validate:"required"` Len int `validate:"len=10"` @@ -8074,7 +8076,6 @@ } func TestStructUint64Validation(t *testing.T) { - validate := New() tSuccess := &TestUint64{ @@ -8114,7 +8115,6 @@ } func TestStructFloat64Validation(t *testing.T) { - validate := New() tSuccess := &TestFloat64{ @@ -8154,7 +8154,6 @@ } func TestStructSliceValidation(t *testing.T) { - validate := New() tSuccess := &TestSlice{ @@ -8204,11 +8203,9 @@ _, ok := fe.Value().([]int) Equal(t, ok, true) - } func TestInvalidStruct(t *testing.T) { - validate := New() s := &SubTest{ @@ -8233,7 +8230,6 @@ } func TestInvalidValidatorFunction(t *testing.T) { - validate := New() s := &SubTest{ @@ -8244,7 +8240,6 @@ } func TestCustomFieldName(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("schema"), ",", 2)[0] @@ -8288,7 +8283,6 @@ } func TestMutipleRecursiveExtractStructCache(t *testing.T) { - validate := New() type Recursive struct { @@ -8305,7 +8299,6 @@ ptr := fmt.Sprintf("%p", sc) for i := 0; i < 100; i++ { - go func() { <-proceed sc := validate.extractStructCache(current, name) @@ -8318,7 +8311,6 @@ // Thanks @robbrockbank, see https://github.com/go-playground/validator/issues/249 func TestPointerAndOmitEmpty(t *testing.T) { - validate := New() type Test struct { @@ -8364,7 +8356,6 @@ } func TestRequired(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -8388,7 +8379,6 @@ } func TestBoolEqual(t *testing.T) { - validate := New() type Test struct { @@ -8416,16 +8406,13 @@ validate := New() err := validate.RegisterTranslation("required", trans, func(ut ut.Translator) (err error) { - // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} is a required field", false); err != nil { return } return - }, func(ut ut.Translator, fe FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) @@ -8438,16 +8425,13 @@ err = validate.RegisterTranslation("required", fr, func(ut ut.Translator) (err error) { - // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} est un champ obligatoire", false); err != nil { return } return - }, func(ut ut.Translator, fe FieldError) string { - t, transErr := ut.T(fe.Tag(), fe.Field()) if transErr != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) @@ -8525,16 +8509,13 @@ validate := New() err = validate.RegisterTranslation("required", trans, func(ut ut.Translator) (err error) { - // using this stype because multiple translation may have to be added for the full translation if err = ut.Add("required", "{0} is a required field", false); err != nil { return } return - }, func(ut ut.Translator, fe FieldError) string { - t, err := ut.T(fe.Tag(), fe.Field()) if err != nil { fmt.Printf("warning: error translating FieldError: %#v", fe.(*fieldError)) @@ -8549,7 +8530,6 @@ } func TestStructFiltered(t *testing.T) { - p1 := func(ns []byte) bool { if bytes.HasSuffix(ns, []byte("NoTag")) || bytes.HasSuffix(ns, []byte("Required")) { return false @@ -8715,7 +8695,6 @@ } func TestRequiredPtr(t *testing.T) { - type Test struct { Bool *bool `validate:"required"` } @@ -8849,7 +8828,6 @@ } func TestAlphanumericUnicodeValidation(t *testing.T) { - tests := []struct { param string expected bool @@ -8892,7 +8870,6 @@ } func TestArrayStructNamespace(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -8921,7 +8898,6 @@ } func TestMapStructNamespace(t *testing.T) { - validate := New() validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] @@ -9576,6 +9552,9 @@ {"a%b", false}, {"1%2", false}, {"%%a%%", false}, + {"hello", true}, + {"", true}, + {"+", true}, } validate := New() @@ -9602,7 +9581,6 @@ } func TestKeys(t *testing.T) { - type Test struct { Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey,endkeys,eq=testval" json:"test1"` Test2 map[int]int `validate:"gt=0,dive,keys,eq=3,endkeys,eq=4" json:"test2"` @@ -9771,7 +9749,6 @@ } func TestKeyOrs(t *testing.T) { - type Test struct { Test1 map[string]string `validate:"gt=0,dive,keys,eq=testkey|eq=testkeyok,endkeys,eq=testval" json:"test1"` } @@ -10028,12 +10005,15 @@ Field6 uint `validate:"required_unless=Field5 2" json:"field_6"` Field7 float32 `validate:"required_unless=Field6 0" json:"field_7"` Field8 float64 `validate:"required_unless=Field7 0.0" json:"field_8"` + Field9 bool `validate:"omitempty" json:"field_9"` + Field10 string `validate:"required_unless=Field9 true" json:"field_10"` }{ FieldE: "test", Field2: &fieldVal, Field3: map[string]string{"key": "val"}, Field4: "test", Field5: 2, + Field9: true, } validate := New() @@ -10053,6 +10033,8 @@ Field5 string `validate:"required_unless=Field3 0" json:"field_5"` Field6 string `validate:"required_unless=Inner.Field test" json:"field_6"` Field7 string `validate:"required_unless=Inner2.Field test" json:"field_7"` + Field8 bool `validate:"omitempty" json:"field_8"` + Field9 string `validate:"required_unless=Field8 true" json:"field_9"` }{ Inner: &Inner{Field: &fieldVal}, FieldE: "test", @@ -10063,10 +10045,11 @@ NotEqual(t, errs, nil) ve := errs.(ValidationErrors) - Equal(t, len(ve), 3) + Equal(t, len(ve), 4) AssertError(t, errs, "Field3", "Field3", "Field3", "Field3", "required_unless") AssertError(t, errs, "Field4", "Field4", "Field4", "Field4", "required_unless") AssertError(t, errs, "Field7", "Field7", "Field7", "Field7", "required_unless") + AssertError(t, errs, "Field9", "Field9", "Field9", "Field9", "required_unless") defer func() { if r := recover(); r == nil { @@ -10202,6 +10185,28 @@ name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_with") } + + test3 := struct { + Inner *Inner + Inner2 *Inner + Field string `validate:"omitempty" json:"field"` + FieldE string `validate:"omitempty" json:"field_e"` + Field1 string `validate:"excluded_with=FieldE" json:"field_1"` + Field2 *string `validate:"excluded_with=FieldE" json:"field_2"` + Field3 map[string]string `validate:"excluded_with=FieldE" json:"field_3"` + Field4 interface{} `validate:"excluded_with=FieldE" json:"field_4"` + Field5 string `validate:"excluded_with=Inner.FieldE" json:"field_5"` + Field6 string `validate:"excluded_with=Inner2.FieldE" json:"field_6"` + }{ + Inner: &Inner{FieldE: "populated"}, + Inner2: &Inner{FieldE: "populated"}, + FieldE: "populated", + } + + validate = New() + + errs = validate.Struct(test3) + Equal(t, errs, nil) } func TestExcludedWithout(t *testing.T) { @@ -10266,6 +10271,26 @@ name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_without") } + + test3 := struct { + Inner *Inner + Inner2 *Inner + Field string `validate:"omitempty" json:"field"` + FieldE string `validate:"omitempty" json:"field_e"` + Field1 string `validate:"excluded_without=Field" json:"field_1"` + Field2 *string `validate:"excluded_without=Field" json:"field_2"` + Field3 map[string]string `validate:"excluded_without=Field" json:"field_3"` + Field4 interface{} `validate:"excluded_without=Field" json:"field_4"` + Field5 string `validate:"excluded_without=Inner.Field" json:"field_5"` + }{ + Inner: &Inner{Field: &fieldVal}, + Field: "populated", + } + + validate = New() + + errs = validate.Struct(test3) + Equal(t, errs, nil) } func TestExcludedWithAll(t *testing.T) { @@ -10334,6 +10359,29 @@ name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_with_all") } + + test3 := struct { + Inner *Inner + Inner2 *Inner + Field string `validate:"omitempty" json:"field"` + FieldE string `validate:"omitempty" json:"field_e"` + Field1 string `validate:"excluded_with_all=FieldE Field" json:"field_1"` + Field2 *string `validate:"excluded_with_all=FieldE Field" json:"field_2"` + Field3 map[string]string `validate:"excluded_with_all=FieldE Field" json:"field_3"` + Field4 interface{} `validate:"excluded_with_all=FieldE Field" json:"field_4"` + Field5 string `validate:"excluded_with_all=Inner.FieldE" json:"field_5"` + Field6 string `validate:"excluded_with_all=Inner2.FieldE" json:"field_6"` + }{ + Inner: &Inner{FieldE: "populated"}, + Inner2: &Inner{FieldE: "populated"}, + Field: "populated", + FieldE: "populated", + } + + validate = New() + + errs = validate.Struct(test3) + Equal(t, errs, nil) } func TestExcludedWithoutAll(t *testing.T) { @@ -10352,9 +10400,10 @@ Field2 *string `validate:"excluded_without_all=Field FieldE" json:"field_2"` Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"` Field4 interface{} `validate:"excluded_without_all=Field FieldE" json:"field_4"` - Field5 string `validate:"excluded_without_all=Inner.Field Inner.Field2" json:"field_5"` + Field5 string `validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5"` }{ Inner: &Inner{Field: &fieldVal}, + Inner2: &Inner{Field: &fieldVal}, Field: "populated", Field1: fieldVal, Field2: &fieldVal, @@ -10398,6 +10447,28 @@ name := fmt.Sprintf("Field%d", i) AssertError(t, errs, name, name, name, name, "excluded_without_all") } + + test3 := struct { + Inner *Inner + Inner2 *Inner + Field string `validate:"omitempty" json:"field"` + FieldE string `validate:"omitempty" json:"field_e"` + Field1 string `validate:"excluded_without_all=Field FieldE" json:"field_1"` + Field2 *string `validate:"excluded_without_all=Field FieldE" json:"field_2"` + Field3 map[string]string `validate:"excluded_without_all=Field FieldE" json:"field_3"` + Field4 interface{} `validate:"excluded_without_all=Field FieldE" json:"field_4"` + Field5 string `validate:"excluded_without_all=Inner.Field Inner2.Field" json:"field_5"` + }{ + Inner: &Inner{Field: &fieldVal}, + Inner2: &Inner{Field: &fieldVal}, + Field: "populated", + FieldE: "populated", + } + + validate = New() + + errs = validate.Struct(test3) + Equal(t, errs, nil) } func TestRequiredWithAll(t *testing.T) { @@ -10455,7 +10526,6 @@ } func TestRequiredWithout(t *testing.T) { - type Inner struct { Field *string } @@ -10521,7 +10591,6 @@ } func TestRequiredWithoutAll(t *testing.T) { - fieldVal := "test" test := struct { Field1 string `validate:"omitempty" json:"field_1"` @@ -10578,7 +10647,6 @@ } func TestAbilityToValidateNils(t *testing.T) { - type TestStruct struct { Test *string `validate:"nil"` } @@ -10720,7 +10788,6 @@ } func Test_hostnameport_validator(t *testing.T) { - type Host struct { Addr string `validate:"hostname_port"` } @@ -10822,7 +10889,6 @@ PanicMatches(t, func() { _ = validate.Var(2, "uppercase") }, "Bad field type int") - } func TestDatetimeValidation(t *testing.T) { @@ -10885,6 +10951,34 @@ } else { if IsEqual(errs, nil) { t.Fatalf("Index: %d iso3166_1_alpha2 failed Error: %s", i, errs) + } + } + } +} + +func TestIsIso31662Validation(t *testing.T) { + tests := []struct { + value string `validate:"iso3166_2"` + expected bool + }{ + {"US-FL", true}, + {"US-F", false}, + {"US", false}, + } + + validate := New() + + for i, test := range tests { + + errs := validate.Var(test.value, "iso3166_2") + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d iso3166_2 failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d iso3166_2 failed Error: %s", i, errs) } } } @@ -11033,3 +11127,199 @@ }) } } + +func TestBCP47LanguageTagValidation(t *testing.T) { + tests := []struct { + value string `validate:"bcp47_language_tag"` + tag string + expected bool + }{ + {"en-US", "bcp47_language_tag", true}, + {"en_GB", "bcp47_language_tag", true}, + {"es", "bcp47_language_tag", true}, + {"English", "bcp47_language_tag", false}, + {"ESES", "bcp47_language_tag", false}, + {"az-Cyrl-AZ", "bcp47_language_tag", true}, + {"en-029", "bcp47_language_tag", true}, + {"xog", "bcp47_language_tag", true}, + } + + 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 locale failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d locale failed Error: %s", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "bcp47_language_tag" { + t.Fatalf("Index: %d locale failed Error: %s", i, errs) + } + } + } + } + + PanicMatches(t, func() { + _ = validate.Var(2, "bcp47_language_tag") + }, "Bad field type int") +} + +func TestBicIsoFormatValidation(t *testing.T) { + tests := []struct { + value string `validate:"bic"` + tag string + expected bool + }{ + {"SBICKEN1345", "bic", true}, + {"SBICKEN1", "bic", true}, + {"SBICKENY", "bic", true}, + {"SBICKEN1YYP", "bic", true}, + {"SBIC23NXXX", "bic", false}, + {"S23CKENXXXX", "bic", false}, + {"SBICKENXX", "bic", false}, + {"SBICKENXX9", "bic", false}, + {"SBICKEN13458", "bic", false}, + {"SBICKEN", "bic", 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 bic failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d bic failed Error: %s", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "bic" { + t.Fatalf("Index: %d bic failed Error: %s", i, errs) + } + } + } + } +} + +func TestPostCodeByIso3166Alpha2(t *testing.T) { + tests := map[string][]struct { + value string + expected bool + }{ + "VN": { + {"ABC", false}, + {"700000", true}, + {"A1", false}, + }, + "GB": { + {"EC1A 1BB", true}, + {"CF10 1B1H", false}, + }, + "VI": { + {"00803", true}, + {"1234567", false}, + }, + "LC": { // not support regexp for post code + {"123456", false}, + }, + "XX": { // not support country + {"123456", false}, + }, + } + + validate := New() + + for cc, ccTests := range tests { + for i, test := range ccTests { + errs := validate.Var(test.value, fmt.Sprintf("postcode_iso3166_alpha2=%s", cc)) + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2=%s failed Error: %s", i, cc, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2=%s failed Error: %s", i, cc, errs) + } + } + } + } +} + +func TestPostCodeByIso3166Alpha2Field(t *testing.T) { + tests := []struct { + Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` + CountryCode interface{} + expected bool + }{ + {"ABC", "VN", false}, + {"700000", "VN", true}, + {"A1", "VN", false}, + {"EC1A 1BB", "GB", true}, + {"CF10 1B1H", "GB", false}, + {"00803", "VI", true}, + {"1234567", "VI", false}, + {"123456", "LC", false}, // not support regexp for post code + {"123456", "XX", false}, // not support country + } + + validate := New() + + for i, test := range tests { + errs := validate.Struct(test) + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2_field=CountryCode failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d postcode_iso3166_alpha2_field=CountryCode failed Error: %s", i, errs) + } + } + } +} + +func TestPostCodeByIso3166Alpha2Field_WrongField(t *testing.T) { + type test struct { + Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` + CountryCode1 interface{} + expected bool + } + + errs := New().Struct(test{"ABC", "VN", false}) + assert.NotEqual(t, nil, errs) +} + +func TestPostCodeByIso3166Alpha2Field_MissingParam(t *testing.T) { + type test struct { + Value string `validate:"postcode_iso3166_alpha2_field="` + CountryCode1 interface{} + expected bool + } + + errs := New().Struct(test{"ABC", "VN", false}) + assert.NotEqual(t, nil, errs) +} + +func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) { + type test struct { + Value string `validate:"postcode_iso3166_alpha2_field=CountryCode"` + CountryCode interface{} + expected bool + } + defer func() { _ = recover() }() + + _ = New().Struct(test{"ABC", 123, false}) + t.Errorf("Didn't panic as expected") +}