Compare commits

..

109 Commits

Author SHA1 Message Date
Dean Karn f5e5146b31 update version README 2 years ago
Cyro Dubeux 56e2f31322
pt_BR translation improvements (#967) 2 years ago
Joselito Viveiros Nogueira Filho e9f2d9f21a
fix: removed unnecessary cast so we can mock ValidationErrors (#980) (#981) 2 years ago
Eduardo Mello b43d437012
feat: add cve validator (#983) 2 years ago
João Fonseca 58d420de41
add kosovo (#1081) 2 years ago
Aleksander Dejewski c6f8637983
Fixed NotBlank validator to cover all whitespace characters (#997) 2 years ago
Gatis Rīders f6f934c4e9
Added Latvian translations (#1005) 2 years ago
konstantin ae3e728763
Introduce Luhn Checksum Validation (#1009) 2 years ago
Tanryberdi 0665b9518a
Refactor: fix for lint errors (#1011) 2 years ago
jnst 21b88d1a25
Fix the Japanese translations of gte and lte (#1012) 2 years ago
jnst 4f5cf1d499
Update Japanese translations (#1013) 2 years ago
Kmilo Denis González 2f3efda84f
Added a genre enum to the user model and a custom validation (#1014) 2 years ago
brent s 2e43671001
(New validator) Validate non-existing but valid file/directory paths (#1022) 2 years ago
just Alan f560fd4e07
Feat: support mongodb objectID validation (#1023) 2 years ago
Yasoob Haider 29d50ba963
add validation for base64 url without = padding (#1024) 2 years ago
zemzale 1c1f70d35b
feat(unique): Add support for struct memember validation (#1048) 2 years ago
Yann Salaün cc768b176d
fix unique= when struct field is a nil pointer (#1041) 2 years ago
Alberto Forcato 3ee65f8c59
Add cron support (#1045) 2 years ago
Owen Gong 89b91cea99
Added "http_url" tag to validate if the variable is a HTTP(s) URL (#1047) 2 years ago
Vijay Nallagatla f2078f7696
Fix unique validator for map with Pointer value (#1062) 2 years ago
Arthur Jenoudet ef342b6f7c
fix validator excluded_unless (#1064) 2 years ago
Dean Karn f3086daf63 fix README 2 years ago
Vitor Hugo 75ba9f6a84
Update README.md (#1066) 2 years ago
Dean Karn 13ad6f5b30 update deps 2 years ago
Simon Tremblay c242c49c02
Update go.mod/go.sum using go mod tidy (#1071) 2 years ago
Dean Karn f17b3458fa fix README 2 years ago
Dean Karn d1178535f7 change eq and ne ignore case tag names 2 years ago
sgallizia 72a3e75460
added IsEqIgnoreCase and IsNeIgnoreCase (#1076) 2 years ago
Phil Porada c0b3430b1f
Fix spelling error in doc (#1078) 2 years ago
Mohamed Sohail b95730fb11
feat: add eth_addr_checksum validation, update eth_addr (#1080) 2 years ago
Dean Karn 8f07b03682
update deps (#1061) 2 years ago
Roberto Ramírez 7edc63a0be
#updated Added required_id spanish translation (#1026) 2 years ago
Marc Brugger 3201fe42fe
Add FQDN en translation (#1058) 2 years ago
wjl110 5aa5f93593
update gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b to 3.0.0 (#1057) 2 years ago
tomaisthorpe f036dd475d
update golang.org/x/text to resolve CVE-2022-32149 (#1015) 2 years ago
Dean Karn c7e0172e0f
Update README.md 2 years ago
Vaibhav Dighe 1e8c614c2a
Fixed boolean validation to handle bool kind (#988) 2 years ago
Dean Karn 9e2ea40380 update ci action versions 3 years ago
Dean Karn 29bf2a5bd0 bump version 3 years ago
Dean Karn 02c12dd7ef update RegisterStructValidationMapRules docs 3 years ago
Leo Liang d0d0c355aa
Feat: support validate struct without struct tag (#934) 3 years ago
Jason.Zhang d3e4be3e44
Enhanced ValidationCtx method to support nested map in slice #915 (#917) 3 years ago
gosua 99922fccc7
Enhance example in function docu (#858) 3 years ago
Sec Cake 4f55647bd7
Added some hash validation (#875) 3 years ago
mrkongo 39aa2e3a27
add it_IT translation (#694) 3 years ago
Vuong 7fa836dc0a
Add Vietnamese translations (#820) 3 years ago
Ayoob Mohammed 21a103f428
Add Arabic translations (#825) 3 years ago
Eduardo Mello e3f29bf088
Boolean translation (#930) 3 years ago
Renato Alves Torres d37da5e53c
fix: add en translation for required_if (#884) 3 years ago
Ciprian 0a26ee57e4
Updated `endsnotwith` description in Readme (#824) 3 years ago
Lauris BH f09500fca7
Fix support for aliased time.Time types (#890) 3 years ago
Massimo Costa 090afeb8ac
enhancement: add italian translation (#914) 3 years ago
XIE Long af72f63d39
Result is wrong while there are multiple group of OR operators #910 (#911) 3 years ago
Stefan Dillenburg f2d3ff7f98
fix: Remove underscore from RFC-1123 based regex (#912) 3 years ago
hehe.bu aea8782168
fix ja typos (#898) 3 years ago
Sol 24b5175a34
Fix typo (#891) 3 years ago
NgeKaworu bc9f9dd2eb
Update zh.go (#856) 3 years ago
alessmar dd2857a4cb
Credit card validation (#924) 3 years ago
Dean Karn bb30072b48 update ci config 3 years ago
Jacob Hochstetler c0195b2b40
added excluded_if/excluded_unless tags + tests (#847) 3 years ago
Dean Karn 58d5778b18
Update README.md 3 years ago
Johannes 3e49fe4eb8
bump golang.org/x/text to fix CVE-2021-38561 (#881) 3 years ago
Anmar85 dd2de9c1f7
update /x/crypto to resolve CVE-2021-43565 (#904) 3 years ago
Dean Karn 88976f39f6
Update README.md 3 years ago
jtseng-godaddy 06ec79d987
Including regex version validation (#831) 3 years ago
Markus Tenghamn 8fe074c546
Added ulid validation (#826) 3 years ago
Kazuki Onishi ec2071b383
Add DNS RFC 1035 label format validator (#833) 3 years ago
nesty92 c67d01d610
Add support for all hex color notations (#866) (#867) 3 years ago
Markus Tenghamn 19f8e61dba
Fixed country_code validation to properly handle strings (#873) 3 years ago
Dean Karn ce34f361cc
update ut dep (#816) 3 years ago
Metin Oğurlu d4271985b4
Feature/currency codes (#811) 3 years ago
András Czigány 42525d89ab
document thread safety and recommended singleton usage (#809) 3 years ago
Xavier Vello a67baa74f1
feature/boolean (#804) 3 years ago
Dmitriy 14221d02a5
fix: Fixed panic when use ru lang for translation, added and fixed tests (#814) 3 years ago
Dean Karn 6dbf61e046
update deps (#815) 3 years ago
Dean Karn 9a5bce3253
Update README.md 3 years ago
Dean Karn b03f1f453e
update all deps to latest versions (#801) 3 years ago
cokezhang 61a982014e
enhancement: add zh translations for tag alphaunicode,alphanumunicode,containsrune,startswith,endswith (#799) 3 years ago
Oleg Nikachev 44c2696cbd
Minor fixes. (#798) 3 years ago
steveorourke e40bece342
Add support for jwt validation (#783) 3 years ago
Brian Leishman 8cfa1e93b6
Update README.md (#765) 3 years ago
Saed SayedAhmed f1befad848
Addressing security vulnerabilities (#774) 3 years ago
Dean Karn 65bb123677
Update README.md 3 years ago
amir e3e38634b1
Add persian translations (#771) 3 years ago
N/A af8b8d1c88
Add iso-3166-2 (#788) 3 years ago
Levani 8bfa88a462
Update README.md (#786) 3 years ago
Dean Karn 9104fe2461
Update README.md 3 years ago
masafumi-i 90ab42ba67
fix ja translation (#792) 3 years ago
Alonso Villegas b1b32b2064
Fix map diving validation (#793) 3 years ago
Dean Karn 76b917f432
Update README.md 4 years ago
Dean Karn 95ac68b6d7
fix url_encoded regex (#769) 4 years ago
Dean Karn d07eb88fb0
Pr cleanup (#767) 4 years ago
ѵµσɳɠ a53d64fc35
Postcode validator for value and field (#759) 4 years ago
Oleksii Kulikov c2066206fe
Add BIC ISO format validator (#758) 4 years ago
zytell3301 b95d43b789
Add ability to validate map data (#752) 4 years ago
Zane DeGraffenried 31dd62f1c9
Fix boolean support for required_if, required_unless and eqfield (#754) 4 years ago
Dean Karn b926bf0df9
Update README.md 4 years ago
Josh Slate add373fff7
feat: add bcp 47 language tag validator (#730) 4 years ago
Dean Karn 68248183b4
Update README.md 4 years ago
Deri Herdianto 526b0968b3
Update errors.go (#671) 4 years ago
Sergei Isaev 2b75c46052
version removed from installation and import (#710) 4 years ago
frederikhors 3c8db83c19
New official Documentation URL (#706) 4 years ago
Peperoncino 5b8f3b8a0b
corresponds to boolean value of nefield (#712) 4 years ago
Torwang 882ec0def4
fix StructLevel Parent() (#716) 4 years ago
Qalifah 0e674563ff
error in spelling (#732) 4 years ago
Michał Treter ec1baac93d
Fix accessing fields in composed structs (#733) 4 years ago
João Francisco 514c9dbd77
Fix excludedWithoutAll comment (#673) 4 years ago
Jake-Convictional 9c415c4565
Add support for excluded_with on pointer fields (#746) 4 years ago
Dean Karn f6584a41c8
split listing into separate job (#680) 4 years ago
  1. 1
      .github/CODEOWNERS
  2. 3
      .github/ISSUE_TEMPLATE.md
  3. 2
      .github/PULL_REQUEST_TEMPLATE.md
  4. 19
      .github/workflows/workflow.yml
  5. 1
      .gitignore
  6. 16
      MAINTAINERS.md
  7. 4
      Makefile
  8. 83
      README.md
  9. 87
      _examples/map-validation/main.go
  10. 80
      _examples/struct-level/main.go
  11. 92
      _examples/struct-map-rules-validation/main.go
  12. 1262
      baked_in.go
  13. 7
      cache.go
  14. 976
      country_codes.go
  15. 79
      currency_codes.go
  16. 449
      doc.go
  17. 27
      errors.go
  18. 23
      field_level.go
  19. 15
      go.mod
  20. 49
      go.sum
  21. 2
      non-standard/validators/notblank.go
  22. 4
      non-standard/validators/notblank_test.go
  23. 173
      postcode_regexes.go
  24. 58
      regexes.go
  25. 12
      struct_level.go
  26. 1389
      translations/ar/ar.go
  27. 695
      translations/ar/ar_test.go
  28. 119
      translations/en/en.go
  29. 48
      translations/en/en_test.go
  30. 10
      translations/es/es.go
  31. 8
      translations/es/es_test.go
  32. 1384
      translations/fa/fa.go
  33. 690
      translations/fa/fa_test.go
  34. 5
      translations/fr/fr.go
  35. 13
      translations/fr/fr_test.go
  36. 5
      translations/id/id.go
  37. 7
      translations/id/id_test.go
  38. 1261
      translations/it/it.go
  39. 725
      translations/it/it_test.go
  40. 129
      translations/ja/ja.go
  41. 302
      translations/ja/ja_test.go
  42. 1399
      translations/lv/lv.go
  43. 709
      translations/lv/lv_test.go
  44. 5
      translations/nl/nl.go
  45. 7
      translations/nl/nl_test.go
  46. 5
      translations/pt/pt.go
  47. 5
      translations/pt/pt_test.go
  48. 17
      translations/pt_BR/pt_BR.go
  49. 25
      translations/pt_BR/pt_BR_test.go
  50. 118
      translations/ru/ru.go
  51. 379
      translations/ru/ru_test.go
  52. 5
      translations/tr/tr.go
  53. 7
      translations/tr/tr_test.go
  54. 1384
      translations/vi/vi.go
  55. 690
      translations/vi/vi_test.go
  56. 90
      translations/zh/zh.go
  57. 257
      translations/zh/zh_test.go
  58. 5
      translations/zh_tw/zh_tw.go
  59. 5
      translations/zh_tw/zh_tw_test.go
  60. 2
      util.go
  61. 18
      validator.go
  62. 113
      validator_instance.go
  63. 6921
      validator_test.go

@ -0,0 +1 @@
* @go-playground/validator-maintainers

@ -1,3 +1,6 @@
- [ ] 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: ### Package version eg. v9, v10:

@ -4,4 +4,4 @@
**Make sure that you've checked the boxes below before you submit PR:** **Make sure that you've checked the boxes below before you submit PR:**
- [ ] Tests exist or have been written that cover this particular change. - [ ] Tests exist or have been written that cover this particular change.
@go-playground/admins @go-playground/validator-maintainers

@ -8,20 +8,20 @@ jobs:
test: test:
strategy: strategy:
matrix: matrix:
go-version: [1.14.x, 1.15.x] go-version: [1.19.x]
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: ${{ matrix.go-version }} go-version: ${{ matrix.go-version }}
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Restore Cache - name: Restore Cache
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }}
@ -32,7 +32,7 @@ jobs:
run: go test -race -covermode=atomic -coverprofile="profile.cov" ./... run: go test -race -covermode=atomic -coverprofile="profile.cov" ./...
- name: Send Coverage - name: Send Coverage
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.15.x' if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.19.x'
uses: shogo82148/actions-goveralls@v1 uses: shogo82148/actions-goveralls@v1
with: with:
path-to-profile: profile.cov path-to-profile: profile.cov
@ -41,8 +41,11 @@ jobs:
name: lint name: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/setup-go@v3
with:
go-version: 1.19.x
- uses: actions/checkout@v3
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v2 uses: golangci/golangci-lint-action@v3
with: with:
version: v1.31 version: v1.50.1

1
.gitignore vendored

@ -28,3 +28,4 @@ _testmain.go
*.txt *.txt
cover.html cover.html
README.html README.html
.idea

@ -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.

@ -3,11 +3,11 @@ GOCMD=GO111MODULE=on go
linters-install: linters-install:
@golangci-lint --version >/dev/null 2>&1 || { \ @golangci-lint --version >/dev/null 2>&1 || { \
echo "installing linting tools..."; \ 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.41.1; \
} }
lint: linters-install lint: linters-install
$(PWD)/bin/golangci-lint run golangci-lint run
test: test:
$(GOCMD) test -cover -race ./... $(GOCMD) test -cover -race ./...

@ -1,7 +1,7 @@
Package validator Package validator
================ =================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v10/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-10.4.1-green.svg) ![Project status](https://img.shields.io/badge/version-10.12.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![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) [![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) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
@ -43,7 +43,7 @@ They return type error to avoid the issue discussed in the following, where err
* http://stackoverflow.com/a/29138676/3158232 * http://stackoverflow.com/a/29138676/3158232
* https://github.com/go-playground/validator/issues/134 * 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 ```go
err := validate.Struct(mystruct) err := validate.Struct(mystruct)
@ -53,7 +53,7 @@ validationErrors := err.(validator.ValidationErrors)
Usage and documentation 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: ##### Examples:
@ -73,8 +73,8 @@ Baked-in Validations
| - | - | | - | - |
| eqcsfield | Field Equals Another Field (relative)| | eqcsfield | Field Equals Another Field (relative)|
| eqfield | Field Equals Another Field | | eqfield | Field Equals Another Field |
| fieldcontains | NOT DOCUMENTED IN doc.go | | fieldcontains | Check the indicated characters are present in the Field |
| fieldexcludes | NOT DOCUMENTED IN doc.go | | fieldexcludes | Check the indicated characters are not present in the field |
| gtcsfield | Field Greater Than Another Relative Field | | gtcsfield | Field Greater Than Another Relative Field |
| gtecsfield | Field Greater Than or Equal To Another Relative Field | | gtecsfield | Field Greater Than or Equal To Another Relative Field |
| gtefield | Field Greater Than or Equal To Another Field | | gtefield | Field Greater Than or Equal To Another Field |
@ -100,7 +100,7 @@ Baked-in Validations
| hostname_rfc1123 | Hostname RFC 1123 | | hostname_rfc1123 | Hostname RFC 1123 |
| ip | Internet Protocol Address IP | | ip | Internet Protocol Address IP |
| ip4_addr | Internet Protocol Address IPv4 | | ip4_addr | Internet Protocol Address IPv4 |
| ip6_addr |Internet Protocol Address IPv6 | | ip6_addr | Internet Protocol Address IPv6 |
| ip_addr | Internet Protocol Address IP | | ip_addr | Internet Protocol Address IP |
| ipv4 | Internet Protocol Address IPv4 | | ipv4 | Internet Protocol Address IPv4 |
| ipv6 | Internet Protocol Address IPv6 | | ipv6 | Internet Protocol Address IPv6 |
@ -114,6 +114,7 @@ Baked-in Validations
| unix_addr | Unix domain socket end point Address | | unix_addr | Unix domain socket end point Address |
| uri | URI String | | uri | URI String |
| url | URL String | | url | URL String |
| http_url | HTTP URL String |
| url_encoded | URL Encoded | | url_encoded | URL Encoded |
| urn_rfc2141 | Urn RFC 2141 String | | urn_rfc2141 | Urn RFC 2141 String |
@ -126,15 +127,21 @@ Baked-in Validations
| alphanumunicode | Alphanumeric Unicode | | alphanumunicode | Alphanumeric Unicode |
| alphaunicode | Alpha Unicode | | alphaunicode | Alpha Unicode |
| ascii | ASCII | | ascii | ASCII |
| boolean | Boolean |
| contains | Contains | | contains | Contains |
| containsany | Contains Any | | containsany | Contains Any |
| containsrune | Contains Rune | | containsrune | Contains Rune |
| endsnotwith | Ends Not With |
| endswith | Ends With | | endswith | Ends With |
| excludes | Excludes |
| excludesall | Excludes All |
| excludesrune | Excludes Rune |
| lowercase | Lowercase | | lowercase | Lowercase |
| multibyte | Multi-Byte Characters | | multibyte | Multi-Byte Characters |
| number | NOT DOCUMENTED IN doc.go | | number | Number |
| numeric | Numeric | | numeric | Numeric |
| printascii | Printable ASCII | | printascii | Printable ASCII |
| startsnotwith | Starts Not With |
| startswith | Starts With | | startswith | Starts With |
| uppercase | Uppercase | | uppercase | Uppercase |
@ -143,8 +150,14 @@ Baked-in Validations
| - | - | | - | - |
| base64 | Base64 String | | base64 | Base64 String |
| base64url | Base64URL String | | base64url | Base64URL String |
| base64rawurl | Base64RawURL String |
| bic | Business Identifier Code (ISO 9362) |
| bcp47_language_tag | Language tag (BCP 47) |
| btc_addr | Bitcoin Address | | btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
| credit_card | Credit Card Number |
| mongodb | MongoDB ObjectID |
| cron | Cron |
| datetime | Datetime | | datetime | Datetime |
| e164 | e164 formatted phone number | | e164 | e164 formatted phone number |
| email | E-mail String | email | E-mail String
@ -158,12 +171,22 @@ Baked-in Validations
| isbn | International Standard Book Number | | isbn | International Standard Book Number |
| isbn10 | International Standard Book Number 10 | | isbn10 | International Standard Book Number 10 |
| isbn13 | International Standard Book Number 13 | | isbn13 | International Standard Book Number 13 |
| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) |
| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) |
| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) |
| iso3166_2 | Country subdivision code (ISO 3166-2) |
| iso4217 | Currency code (ISO 4217) |
| json | JSON | | json | JSON |
| jwt | JSON Web Token (JWT) |
| latitude | Latitude | | latitude | Latitude |
| longitude | Longitude | | longitude | Longitude |
| luhn_checksum | Luhn Algorithm Checksum (for strings and (u)int) |
| postcode_iso3166_alpha2 | Postcode |
| postcode_iso3166_alpha2_field | Postcode |
| rgb | RGB String | | rgb | RGB String |
| rgba | RGBA String | | rgba | RGBA String |
| ssn | Social Security Number SSN | | ssn | Social Security Number SSN |
| timezone | Timezone |
| uuid | Universally Unique Identifier UUID | | uuid | Universally Unique Identifier UUID |
| uuid3 | Universally Unique Identifier UUID v3 | | uuid3 | Universally Unique Identifier UUID v3 |
| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | | uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 |
@ -172,26 +195,39 @@ Baked-in Validations
| uuid5 | Universally Unique Identifier UUID v5 | | uuid5 | Universally Unique Identifier UUID v5 |
| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 | | uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 | | uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
| md4 | MD4 hash |
| md5 | MD5 hash |
| sha256 | SHA256 hash |
| sha384 | SHA384 hash |
| sha512 | SHA512 hash |
| ripemd128 | RIPEMD-128 hash |
| ripemd128 | RIPEMD-160 hash |
| tiger128 | TIGER128 hash |
| tiger160 | TIGER160 hash |
| tiger192 | TIGER192 hash |
| semver | Semantic Versioning 2.0.0 |
| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
| cve | Common Vulnerabilities and Exposures Identifier (CVE id) |
### Comparisons: ### Comparisons:
| Tag | Description | | Tag | Description |
| - | - | | - | - |
| eq | Equals | | eq | Equals |
| eq_ignore_case | Equals ignoring case |
| gt | Greater than| | gt | Greater than|
| gte |Greater than or equal | | gte | Greater than or equal |
| lt | Less Than | | lt | Less Than |
| lte | Less Than or Equal | | lte | Less Than or Equal |
| ne | Not Equal | | ne | Not Equal |
| ne_ignore_case | Not Equal ignoring case |
### Other: ### Other:
| Tag | Description | | Tag | Description |
| - | - | | - | - |
| dir | Directory | | dir | Existing Directory |
| endswith | Ends With | | dirpath | Directory Path |
| excludes | Excludes | | file | Existing File |
| excludesall | Excludes All | | filepath | File Path |
| excludesrune | Excludes Rune |
| file | File path |
| isdefault | Is Default | | isdefault | Is Default |
| len | Length | | len | Length |
| max | Maximum | | max | Maximum |
@ -204,12 +240,20 @@ Baked-in Validations
| required_with_all | Required With All | | required_with_all | Required With All |
| required_without | Required Without | | required_without | Required Without |
| required_without_all | Required Without All | | required_without_all | Required Without All |
| excluded_if | Excluded If |
| excluded_unless | Excluded Unless |
| excluded_with | Excluded With | | excluded_with | Excluded With |
| excluded_with_all | Excluded With All | | excluded_with_all | Excluded With All |
| excluded_without | Excluded Without | | excluded_without | Excluded Without |
| excluded_without_all | Excluded Without All | | excluded_without_all | Excluded Without All |
| unique | Unique | | unique | Unique |
#### Aliases:
| Tag | Description |
| - | - |
| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla |
| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric |
Benchmarks Benchmarks
------ ------
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 ###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64
@ -295,5 +339,10 @@ How to Contribute
Make a pull request... Make a pull request...
License License
------ -------
Distributed under MIT License, please see license file within the code for more details. 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

@ -0,0 +1,87 @@
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",
"phones": []map[string]interface{}{
{
"number": "11-111-1111",
"remark": "home",
},
{
"number": "22-222-2222",
"remark": "work",
},
},
},
}
// 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",
"phones": map[string]interface{}{
"number": "required,min=4,max=32",
"remark": "required,min=1,max=32",
},
},
}
if len(validate.ValidateMap(data, rules)) == 0 {
// Data is valid
}
// Data is invalid
}

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -8,6 +9,36 @@ import (
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
type validationError struct {
Namespace string `json:"namespace"` // can differ when a custom TagNameFunc is registered or
Field string `json:"field"` // by passing alt name to ReportError like below
StructNamespace string `json:"structNamespace"`
StructField string `json:"structField"`
Tag string `json:"tag"`
ActualTag string `json:"actualTag"`
Kind string `json:"kind"`
Type string `json:"type"`
Value string `json:"value"`
Param string `json:"param"`
Message string `json:"message"`
}
type Gender uint
const (
Male Gender = iota + 1
Female
Intersex
)
func (gender Gender) String() string {
terms := []string{"Male", "Female", "Intersex"}
if gender < Male || gender > Intersex {
return "unknown"
}
return terms[gender]
}
// User contains user information // User contains user information
type User struct { type User struct {
FirstName string `json:"fname"` FirstName string `json:"fname"`
@ -16,6 +47,7 @@ type User struct {
Email string `json:"e-mail" validate:"required,email"` Email string `json:"e-mail" validate:"required,email"`
FavouriteColor string `validate:"hexcolor|rgb|rgba"` FavouriteColor string `validate:"hexcolor|rgb|rgba"`
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage... Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
Gender Gender `json:"gender" validate:"required,gender_custom_validation"`
} }
// Address houses a users address information // Address houses a users address information
@ -44,9 +76,20 @@ func main() {
// register validation for 'User' // register validation for 'User'
// NOTE: only have to register a non-pointer type for 'User', validator // 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{}) validate.RegisterStructValidation(UserStructLevelValidation, User{})
// register a custom validation for user genre on a line
// validates that an enum is within the interval
err := validate.RegisterValidation("gender_custom_validation", func(fl validator.FieldLevel) bool {
value := fl.Field().Interface().(Gender)
return value.String() != "unknown"
})
if err != nil {
fmt.Println(err)
return
}
// build 'User' info, normally posted data etc... // build 'User' info, normally posted data etc...
address := &Address{ address := &Address{
Street: "Eavesdown Docks", Street: "Eavesdown Docks",
@ -65,7 +108,7 @@ func main() {
} }
// returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError )
err := validate.Struct(user) err = validate.Struct(user)
if err != nil { if err != nil {
// this check is only needed when your code could produce // this check is only needed when your code could produce
@ -77,18 +120,27 @@ func main() {
} }
for _, err := range err.(validator.ValidationErrors) { for _, err := range err.(validator.ValidationErrors) {
e := validationError{
fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or Namespace: err.Namespace(),
fmt.Println(err.Field()) // by passing alt name to ReportError like below Field: err.Field(),
fmt.Println(err.StructNamespace()) StructNamespace: err.StructNamespace(),
fmt.Println(err.StructField()) StructField: err.StructField(),
fmt.Println(err.Tag()) Tag: err.Tag(),
fmt.Println(err.ActualTag()) ActualTag: err.ActualTag(),
fmt.Println(err.Kind()) Kind: fmt.Sprintf("%v", err.Kind()),
fmt.Println(err.Type()) Type: fmt.Sprintf("%v", err.Type()),
fmt.Println(err.Value()) Value: fmt.Sprintf("%v", err.Value()),
fmt.Println(err.Param()) Param: err.Param(),
fmt.Println() Message: err.Error(),
}
indent, err := json.MarshalIndent(e, "", " ")
if err != nil {
fmt.Println(err)
panic(err)
}
fmt.Println(string(indent))
} }
// from here you can create your own error messages in whatever language you wish // from here you can create your own error messages in whatever language you wish

@ -0,0 +1,92 @@
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type Data struct {
Name string
Email string
Details *Details
}
type Details struct {
FamilyMembers *FamilyMembers
Salary string
}
type FamilyMembers struct {
FatherName string
MotherName string
}
type Data2 struct {
Name string
Age uint32
}
var validate = validator.New()
func main() {
validateStruct()
// output
// Key: 'Data2.Name' Error:Field validation for 'Name' failed on the 'min' tag
// Key: 'Data2.Age' Error:Field validation for 'Age' failed on the 'max' tag
validateStructNested()
// output
// Key: 'Data.Name' Error:Field validation for 'Name' failed on the 'max' tag
// Key: 'Data.Details.FamilyMembers' Error:Field validation for 'FamilyMembers' failed on the 'required' tag
}
func validateStruct() {
data := Data2{
Name: "leo",
Age: 1000,
}
rules := map[string]string{
"Name": "min=4,max=6",
"Age": "min=4,max=6",
}
validate.RegisterStructValidationMapRules(rules, Data2{})
err := validate.Struct(data)
fmt.Println(err)
fmt.Println()
}
func validateStructNested() {
data := Data{
Name: "11sdfddd111",
Email: "zytel3301@mail.com",
Details: &Details{
Salary: "1000",
},
}
rules1 := map[string]string{
"Name": "min=4,max=6",
"Email": "required,email",
"Details": "required",
}
rules2 := map[string]string{
"Salary": "number",
"FamilyMembers": "required",
}
rules3 := map[string]string{
"FatherName": "required,min=4,max=32",
"MotherName": "required,min=4,max=32",
}
validate.RegisterStructValidationMapRules(rules1, Data{})
validate.RegisterStructValidationMapRules(rules2, Details{})
validate.RegisterStructValidationMapRules(rules3, FamilyMembers{})
err := validate.Struct(data)
fmt.Println(err)
}

File diff suppressed because it is too large Load Diff

@ -114,6 +114,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]} cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]}
numFields := current.NumField() numFields := current.NumField()
rules := v.rules[typ]
var ctag *cTag var ctag *cTag
var fld reflect.StructField var fld reflect.StructField
@ -128,7 +129,11 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
continue continue
} }
tag = fld.Tag.Get(v.tagName) if rtag, ok := rules[fld.Name]; ok {
tag = rtag
} else {
tag = fld.Tag.Get(v.tagName)
}
if tag == skipValidationTag { if tag == skipValidationTag {
continue continue

@ -51,7 +51,7 @@ var iso3166_1_alpha2 = map[string]bool{
"TV": true, "UG": true, "UA": true, "AE": true, "GB": true, "TV": true, "UG": true, "UA": true, "AE": true, "GB": true,
"US": true, "UM": true, "UY": true, "UZ": true, "VU": true, "US": true, "UM": true, "UY": true, "UZ": true, "VU": true,
"VE": true, "VN": true, "VG": true, "VI": true, "WF": true, "VE": true, "VN": true, "VG": true, "VI": true, "WF": true,
"EH": true, "YE": true, "ZM": true, "ZW": true, "EH": true, "YE": true, "ZM": true, "ZW": true, "XK": true,
} }
var iso3166_1_alpha3 = map[string]bool{ var iso3166_1_alpha3 = map[string]bool{
@ -105,7 +105,7 @@ var iso3166_1_alpha3 = map[string]bool{
"UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true, "UGA": true, "UKR": true, "ARE": true, "GBR": true, "UMI": true,
"USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true, "USA": true, "URY": true, "UZB": true, "VUT": true, "VEN": true,
"VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true, "VNM": true, "VGB": true, "VIR": true, "WLF": true, "ESH": true,
"YEM": true, "ZMB": true, "ZWE": true, "ALA": true, "YEM": true, "ZMB": true, "ZWE": true, "ALA": true, "UNK": true,
} }
var iso3166_1_alpha_numeric = map[int]bool{ var iso3166_1_alpha_numeric = map[int]bool{
// see: https://www.iso.org/iso-3166-country-codes.html // see: https://www.iso.org/iso-3166-country-codes.html
@ -158,5 +158,975 @@ var iso3166_1_alpha_numeric = map[int]bool{
800: true, 804: true, 784: true, 826: true, 581: true, 800: true, 804: true, 784: true, 826: true, 581: true,
840: true, 858: true, 860: true, 548: true, 862: true, 840: true, 858: true, 860: true, 548: true, 862: true,
704: true, 92: true, 850: true, 876: true, 732: true, 704: true, 92: true, 850: true, 876: true, 732: true,
887: true, 894: true, 716: true, 248: true, 887: true, 894: true, 716: true, 248: true, 153: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,
} }

@ -0,0 +1,79 @@
package validator
var iso4217 = map[string]bool{
"AFN": true, "EUR": true, "ALL": true, "DZD": true, "USD": true,
"AOA": true, "XCD": true, "ARS": true, "AMD": true, "AWG": true,
"AUD": true, "AZN": true, "BSD": true, "BHD": true, "BDT": true,
"BBD": true, "BYN": true, "BZD": true, "XOF": true, "BMD": true,
"INR": true, "BTN": true, "BOB": true, "BOV": true, "BAM": true,
"BWP": true, "NOK": true, "BRL": true, "BND": true, "BGN": true,
"BIF": true, "CVE": true, "KHR": true, "XAF": true, "CAD": true,
"KYD": true, "CLP": true, "CLF": true, "CNY": true, "COP": true,
"COU": true, "KMF": true, "CDF": true, "NZD": true, "CRC": true,
"HRK": true, "CUP": true, "CUC": true, "ANG": true, "CZK": true,
"DKK": true, "DJF": true, "DOP": true, "EGP": true, "SVC": true,
"ERN": true, "SZL": true, "ETB": true, "FKP": true, "FJD": true,
"XPF": true, "GMD": true, "GEL": true, "GHS": true, "GIP": true,
"GTQ": true, "GBP": true, "GNF": true, "GYD": true, "HTG": true,
"HNL": true, "HKD": true, "HUF": true, "ISK": true, "IDR": true,
"XDR": true, "IRR": true, "IQD": true, "ILS": true, "JMD": true,
"JPY": true, "JOD": true, "KZT": true, "KES": true, "KPW": true,
"KRW": true, "KWD": true, "KGS": true, "LAK": true, "LBP": true,
"LSL": true, "ZAR": true, "LRD": true, "LYD": true, "CHF": true,
"MOP": true, "MKD": true, "MGA": true, "MWK": true, "MYR": true,
"MVR": true, "MRU": true, "MUR": true, "XUA": true, "MXN": true,
"MXV": true, "MDL": true, "MNT": true, "MAD": true, "MZN": true,
"MMK": true, "NAD": true, "NPR": true, "NIO": true, "NGN": true,
"OMR": true, "PKR": true, "PAB": true, "PGK": true, "PYG": true,
"PEN": true, "PHP": true, "PLN": true, "QAR": true, "RON": true,
"RUB": true, "RWF": true, "SHP": true, "WST": true, "STN": true,
"SAR": true, "RSD": true, "SCR": true, "SLL": true, "SGD": true,
"XSU": true, "SBD": true, "SOS": true, "SSP": true, "LKR": true,
"SDG": true, "SRD": true, "SEK": true, "CHE": true, "CHW": true,
"SYP": true, "TWD": true, "TJS": true, "TZS": true, "THB": true,
"TOP": true, "TTD": true, "TND": true, "TRY": true, "TMT": true,
"UGX": true, "UAH": true, "AED": true, "USN": true, "UYU": true,
"UYI": true, "UYW": true, "UZS": true, "VUV": true, "VES": true,
"VND": true, "YER": true, "ZMW": true, "ZWL": true, "XBA": true,
"XBB": true, "XBC": true, "XBD": true, "XTS": true, "XXX": true,
"XAU": true, "XPD": true, "XPT": true, "XAG": true,
}
var iso4217_numeric = map[int]bool{
8: true, 12: true, 32: true, 36: true, 44: true,
48: true, 50: true, 51: true, 52: true, 60: true,
64: true, 68: true, 72: true, 84: true, 90: true,
96: true, 104: true, 108: true, 116: true, 124: true,
132: true, 136: true, 144: true, 152: true, 156: true,
170: true, 174: true, 188: true, 191: true, 192: true,
203: true, 208: true, 214: true, 222: true, 230: true,
232: true, 238: true, 242: true, 262: true, 270: true,
292: true, 320: true, 324: true, 328: true, 332: true,
340: true, 344: true, 348: true, 352: true, 356: true,
360: true, 364: true, 368: true, 376: true, 388: true,
392: true, 398: true, 400: true, 404: true, 408: true,
410: true, 414: true, 417: true, 418: true, 422: true,
426: true, 430: true, 434: true, 446: true, 454: true,
458: true, 462: true, 480: true, 484: true, 496: true,
498: true, 504: true, 512: true, 516: true, 524: true,
532: true, 533: true, 548: true, 554: true, 558: true,
566: true, 578: true, 586: true, 590: true, 598: true,
600: true, 604: true, 608: true, 634: true, 643: true,
646: true, 654: true, 682: true, 690: true, 694: true,
702: true, 704: true, 706: true, 710: true, 728: true,
748: true, 752: true, 756: true, 760: true, 764: true,
776: true, 780: true, 784: true, 788: true, 800: true,
807: true, 818: true, 826: true, 834: true, 840: true,
858: true, 860: true, 882: true, 886: true, 901: true,
927: true, 928: true, 929: true, 930: true, 931: true,
932: true, 933: true, 934: true, 936: true, 938: true,
940: true, 941: true, 943: true, 944: true, 946: true,
947: true, 948: true, 949: true, 950: true, 951: true,
952: true, 953: true, 955: true, 956: true, 957: true,
958: true, 959: true, 960: true, 961: true, 962: true,
963: true, 964: true, 965: true, 967: true, 968: true,
969: true, 970: true, 971: true, 972: true, 973: true,
975: true, 976: true, 977: true, 978: true, 979: true,
980: true, 981: true, 984: true, 985: true, 986: true,
990: true, 994: true, 997: true, 999: true,
}

449
doc.go

File diff suppressed because it is too large Load Diff

@ -44,12 +44,9 @@ func (ve ValidationErrors) Error() string {
buff := bytes.NewBufferString("") buff := bytes.NewBufferString("")
var fe *fieldError
for i := 0; i < len(ve); i++ { for i := 0; i < len(ve); i++ {
fe = ve[i].(*fieldError) buff.WriteString(ve[i].Error())
buff.WriteString(fe.Error())
buff.WriteString("\n") buff.WriteString("\n")
} }
@ -82,7 +79,7 @@ func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslati
// FieldError contains all functions to get error details // FieldError contains all functions to get error details
type FieldError interface { 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 // validation was an alias, this will return the
// alias name and not the underlying tag that failed. // alias name and not the underlying tag that failed.
// //
@ -90,7 +87,7 @@ type FieldError interface {
// will return "iscolor" // will return "iscolor"
Tag() string 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. // alias the actual tag within the alias will be returned.
// If an 'or' validation fails the entire or will be returned. // If an 'or' validation fails the entire or will be returned.
// //
@ -98,7 +95,7 @@ type FieldError interface {
// will return "hexcolor|rgb|rgba|hsl|hsla" // will return "hexcolor|rgb|rgba|hsl|hsla"
ActualTag() string 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. // name taking precedence over the field's actual name.
// //
// eg. JSON name "User.fname" // eg. JSON name "User.fname"
@ -109,7 +106,7 @@ type FieldError interface {
// using validate.Field(...) as there is no way to extract it's name // using validate.Field(...) as there is no way to extract it's name
Namespace() string 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. // actual name.
// //
// eq. "User.FirstName" see Namespace for comparison // eq. "User.FirstName" see Namespace for comparison
@ -118,24 +115,24 @@ type FieldError interface {
// using validate.Field(...) as there is no way to extract its name // using validate.Field(...) as there is no way to extract its name
StructNamespace() string 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. // field's actual name.
// //
// eq. JSON name "fname" // eq. JSON name "fname"
// see StructField for comparison // see StructField for comparison
Field() string 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" // eq. "FirstName"
// see Field for comparison // see Field for comparison
StructField() string 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 // message
Value() interface{} 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 // help with generating an error message
Param() string Param() string
@ -146,10 +143,10 @@ type FieldError interface {
// Type returns the Field's reflect Type // 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 Type() reflect.Type
// returns the FieldError's translated error // Translate returns the FieldError's translated error
// from the provided 'ut.Translator' and registered 'TranslationFunc' // from the provided 'ut.Translator' and registered 'TranslationFunc'
// //
// NOTE: if no registered translator can be found it returns the same as // NOTE: if no registered translator can be found it returns the same as
@ -221,7 +218,7 @@ func (fe *fieldError) Field() string {
// return fld // 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 { func (fe *fieldError) StructField() string {
// return fe.structField // return fe.structField
return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):]

@ -5,24 +5,25 @@ import "reflect"
// FieldLevel contains all the information and helper functions // FieldLevel contains all the information and helper functions
// to validate a field // to validate a field
type FieldLevel interface { type FieldLevel interface {
// returns the top level struct, if any
// Top returns the top level struct, if any
Top() reflect.Value 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' // the comparison value if called 'VarWithValue'
Parent() reflect.Value Parent() reflect.Value
// returns current field for validation // Field returns current field for validation
Field() reflect.Value 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. // name taking precedence over the fields actual name.
FieldName() string FieldName() string
// returns the struct field's name // StructFieldName returns the struct field's name
StructFieldName() string StructFieldName() string
// returns param for validation against current field // Param returns param for validation against current field
Param() string Param() string
// GetTag returns the current validations tag name // GetTag returns the current validations tag name
@ -33,7 +34,7 @@ type FieldLevel interface {
// underlying value and it's kind. // underlying value and it's kind.
ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) 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 // in the param and returns the field, field kind and whether is was successful in retrieving
// the field at all. // the field at all.
// //
@ -49,7 +50,7 @@ type FieldLevel interface {
// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable. // Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) 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 // 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. // the field at all.
// //
@ -57,7 +58,7 @@ type FieldLevel interface {
// could not be retrieved because it didn't exist. // could not be retrieved because it didn't exist.
GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) 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. // the field and namespace allowing more extensibility for validators.
GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool)
} }
@ -107,12 +108,12 @@ func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string)
return current, kind, found 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) { func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) {
return v.getStructFieldOKInternal(v.slflParent, v.ct.param) 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. // the field and namespace allowing more extensibility for validators.
func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) { func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) {
return v.getStructFieldOKInternal(val, namespace) return v.getStructFieldOKInternal(val, namespace)

@ -1,11 +1,14 @@
module github.com/go-playground/validator/v10 module github.com/go-playground/validator/v10
go 1.13 go 1.18
require ( require (
github.com/go-playground/assert/v2 v2.0.1 github.com/go-playground/assert/v2 v2.2.0
github.com/go-playground/locales v0.13.0 github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.17.0 github.com/go-playground/universal-translator v0.18.1
github.com/leodido/go-urn v1.2.0 github.com/leodido/go-urn v1.2.2
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/crypto v0.7.0
golang.org/x/text v0.8.0
) )
require golang.org/x/sys v0.6.0 // indirect

@ -1,28 +1,31 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -14,7 +14,7 @@ func NotBlank(fl validator.FieldLevel) bool {
switch field.Kind() { switch field.Kind() {
case reflect.String: case reflect.String:
return len(strings.TrimSpace(field.String())) > 0 return len(strings.Trim(strings.TrimSpace(field.String()), "\x1c\x1d\x1e\x1f")) > 0
case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array: case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array:
return field.Len() > 0 return field.Len() > 0
case reflect.Ptr, reflect.Interface, reflect.Func: case reflect.Ptr, reflect.Interface, reflect.Func:

@ -3,8 +3,8 @@ package validators
import ( import (
"testing" "testing"
"github.com/go-playground/validator/v10"
"github.com/go-playground/assert/v2" "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10"
) )
type test struct { type test struct {
@ -24,7 +24,7 @@ func TestNotBlank(t *testing.T) {
// Errors // Errors
var x *int var x *int
invalid := test{ invalid := test{
String: " ", String: " \x1c\x1d\x1e\x1f\r\n",
Array: []int{}, Array: []int{},
Pointer: x, Pointer: x,
Number: 0, Number: 0,

@ -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)
}
}

@ -10,7 +10,7 @@ const (
numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$" numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
numberRegexString = "^[0-9]+$" numberRegexString = "^[0-9]+$"
hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$" hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$"
hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$" 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*\\)$" 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*\\)$" 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*\\)$"
@ -19,6 +19,7 @@ const (
e164RegexString = "^\\+[1-9]?[0-9]{7,14}$" e164RegexString = "^\\+[1-9]?[0-9]{7,14}$"
base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$" base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$"
base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2,4})$"
iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
@ -29,6 +30,17 @@ const (
uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
uLIDRegexString = "^[A-HJKMNP-TV-Z0-9]{26}$"
md4RegexString = "^[0-9a-f]{32}$"
md5RegexString = "^[0-9a-f]{32}$"
sha256RegexString = "^[0-9a-f]{64}$"
sha384RegexString = "^[0-9a-f]{96}$"
sha512RegexString = "^[0-9a-f]{128}$"
ripemd128RegexString = "^[0-9a-f]{32}$"
ripemd160RegexString = "^[0-9a-f]{40}$"
tiger128RegexString = "^[0-9a-f]{32}$"
tiger160RegexString = "^[0-9a-f]{40}$"
tiger192RegexString = "^[0-9a-f]{48}$"
aSCIIRegexString = "^[\x00-\x7F]*$" aSCIIRegexString = "^[\x00-\x7F]*$"
printableASCIIRegexString = "^[\x20-\x7E]*$" printableASCIIRegexString = "^[\x20-\x7E]*$"
multibyteRegexString = "[^\x00-\x7F]" multibyteRegexString = "[^\x00-\x7F]"
@ -36,19 +48,26 @@ const (
latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$` sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$`
hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952 hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123 hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62}){1}(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.') fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32 btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$` // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
ethAddressRegexString = `^0x[0-9a-fA-F]{40}$` ethAddressRegexString = `^0x[0-9a-fA-F]{40}$`
ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` ethAddressUpperRegexString = `^0x[0-9A-F]{40}$`
ethAddressLowerRegexString = `^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})|(&gt)|(&lt)|(&quot)|(&amp)+[;]?` hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(&gt)|(&lt)|(&quot)|(&amp)+[;]?`
hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
splitParamsRegexString = `'[^']*'|\S+` splitParamsRegexString = `'[^']*'|\S+`
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html
mongodbRegexString = "^[a-f\\d]{24}$"
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
) )
var ( var (
@ -59,7 +78,7 @@ var (
numericRegex = regexp.MustCompile(numericRegexString) numericRegex = regexp.MustCompile(numericRegexString)
numberRegex = regexp.MustCompile(numberRegexString) numberRegex = regexp.MustCompile(numberRegexString)
hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString) hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString)
hexcolorRegex = regexp.MustCompile(hexcolorRegexString) hexColorRegex = regexp.MustCompile(hexColorRegexString)
rgbRegex = regexp.MustCompile(rgbRegexString) rgbRegex = regexp.MustCompile(rgbRegexString)
rgbaRegex = regexp.MustCompile(rgbaRegexString) rgbaRegex = regexp.MustCompile(rgbaRegexString)
hslRegex = regexp.MustCompile(hslRegexString) hslRegex = regexp.MustCompile(hslRegexString)
@ -68,6 +87,7 @@ var (
emailRegex = regexp.MustCompile(emailRegexString) emailRegex = regexp.MustCompile(emailRegexString)
base64Regex = regexp.MustCompile(base64RegexString) base64Regex = regexp.MustCompile(base64RegexString)
base64URLRegex = regexp.MustCompile(base64URLRegexString) base64URLRegex = regexp.MustCompile(base64URLRegexString)
base64RawURLRegex = regexp.MustCompile(base64RawURLRegexString)
iSBN10Regex = regexp.MustCompile(iSBN10RegexString) iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
iSBN13Regex = regexp.MustCompile(iSBN13RegexString) iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
uUID3Regex = regexp.MustCompile(uUID3RegexString) uUID3Regex = regexp.MustCompile(uUID3RegexString)
@ -78,6 +98,17 @@ var (
uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString) uUID4RFC4122Regex = regexp.MustCompile(uUID4RFC4122RegexString)
uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString) uUID5RFC4122Regex = regexp.MustCompile(uUID5RFC4122RegexString)
uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString) uUIDRFC4122Regex = regexp.MustCompile(uUIDRFC4122RegexString)
uLIDRegex = regexp.MustCompile(uLIDRegexString)
md4Regex = regexp.MustCompile(md4RegexString)
md5Regex = regexp.MustCompile(md5RegexString)
sha256Regex = regexp.MustCompile(sha256RegexString)
sha384Regex = regexp.MustCompile(sha384RegexString)
sha512Regex = regexp.MustCompile(sha512RegexString)
ripemd128Regex = regexp.MustCompile(ripemd128RegexString)
ripemd160Regex = regexp.MustCompile(ripemd160RegexString)
tiger128Regex = regexp.MustCompile(tiger128RegexString)
tiger160Regex = regexp.MustCompile(tiger160RegexString)
tiger192Regex = regexp.MustCompile(tiger192RegexString)
aSCIIRegex = regexp.MustCompile(aSCIIRegexString) aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString) printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
multibyteRegex = regexp.MustCompile(multibyteRegexString) multibyteRegex = regexp.MustCompile(multibyteRegexString)
@ -92,10 +123,15 @@ var (
btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32) btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32)
btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32) btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32)
ethAddressRegex = regexp.MustCompile(ethAddressRegexString) ethAddressRegex = regexp.MustCompile(ethAddressRegexString)
ethaddressRegexUpper = regexp.MustCompile(ethAddressUpperRegexString)
ethAddressRegexLower = regexp.MustCompile(ethAddressLowerRegexString)
uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString)
hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString)
hTMLRegex = regexp.MustCompile(hTMLRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString)
jWTRegex = regexp.MustCompile(jWTRegexString)
splitParamsRegex = regexp.MustCompile(splitParamsRegexString) splitParamsRegex = regexp.MustCompile(splitParamsRegexString)
bicRegex = regexp.MustCompile(bicRegexString)
semverRegex = regexp.MustCompile(semverRegexString)
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
cveRegex = regexp.MustCompile(cveRegexString)
mongodbRegex = regexp.MustCompile(mongodbRegexString)
cronRegex = regexp.MustCompile(cronRegexString)
) )

@ -23,18 +23,18 @@ func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
// to validate a struct // to validate a struct
type StructLevel interface { 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 // this is so you don't have to use anonymous functions to get access to the validate
// instance. // instance.
Validator() *Validate Validator() *Validate
// returns the top level struct, if any // Top returns the top level struct, if any
Top() reflect.Value Top() reflect.Value
// returns the current fields parent struct, if any // Parent returns the current fields parent struct, if any
Parent() reflect.Value Parent() reflect.Value
// returns the current struct. // Current returns the current struct.
Current() reflect.Value Current() reflect.Value
// ExtractType gets the actual underlying type of field value. // ExtractType gets the actual underlying type of field value.
@ -42,7 +42,7 @@ type StructLevel interface {
// underlying value and its kind. // underlying value and its kind.
ExtractType(field reflect.Value) (value reflect.Value, kind reflect.Kind, nullable bool) 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: // NOTES:
// //
@ -54,7 +54,7 @@ type StructLevel interface {
// and process on the flip side it's up to you. // and process on the flip side it's up to you.
ReportError(field interface{}, fieldName, structFieldName string, tag, param string) 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: // NOTES:
// //

File diff suppressed because it is too large Load Diff

@ -0,0 +1,695 @@
package ar
import (
"testing"
"time"
. "github.com/go-playground/assert/v2"
english "github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
eng := english.New()
uni := ut.New(eng, eng)
trans, _ := uni.GetTranslator("en")
validate := validator.New()
err := RegisterDefaultTranslations(validate, trans)
Equal(t, err, nil)
type Inner struct {
EqCSFieldString string
NeCSFieldString string
GtCSFieldString string
GteCSFieldString string
LtCSFieldString string
LteCSFieldString string
}
type Test struct {
Inner Inner
RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"`
LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"`
MinString string `validate:"min=1"`
MinNumber float64 `validate:"min=1113.00"`
MinMultiple []string `validate:"min=7"`
MaxString string `validate:"max=3"`
MaxNumber float64 `validate:"max=1113.00"`
MaxMultiple []string `validate:"max=7"`
EqString string `validate:"eq=3"`
EqNumber float64 `validate:"eq=2.33"`
EqMultiple []string `validate:"eq=7"`
NeString string `validate:"ne="`
NeNumber float64 `validate:"ne=0.00"`
NeMultiple []string `validate:"ne=0"`
LtString string `validate:"lt=3"`
LtNumber float64 `validate:"lt=5.56"`
LtMultiple []string `validate:"lt=2"`
LtTime time.Time `validate:"lt"`
LteString string `validate:"lte=3"`
LteNumber float64 `validate:"lte=5.56"`
LteMultiple []string `validate:"lte=2"`
LteTime time.Time `validate:"lte"`
GtString string `validate:"gt=3"`
GtNumber float64 `validate:"gt=5.56"`
GtMultiple []string `validate:"gt=2"`
GtTime time.Time `validate:"gt"`
GteString string `validate:"gte=3"`
GteNumber float64 `validate:"gte=5.56"`
GteMultiple []string `validate:"gte=2"`
GteTime time.Time `validate:"gte"`
EqFieldString string `validate:"eqfield=MaxString"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
NeFieldString string `validate:"nefield=EqFieldString"`
GtFieldString string `validate:"gtfield=MaxString"`
GteFieldString string `validate:"gtefield=MaxString"`
LtFieldString string `validate:"ltfield=MaxString"`
LteFieldString string `validate:"ltefield=MaxString"`
AlphaString string `validate:"alpha"`
AlphanumString string `validate:"alphanum"`
NumericString string `validate:"numeric"`
NumberString string `validate:"number"`
HexadecimalString string `validate:"hexadecimal"`
HexColorString string `validate:"hexcolor"`
RGBColorString string `validate:"rgb"`
RGBAColorString string `validate:"rgba"`
HSLColorString string `validate:"hsl"`
HSLAColorString string `validate:"hsla"`
Email string `validate:"email"`
URL string `validate:"url"`
URI string `validate:"uri"`
Base64 string `validate:"base64"`
Contains string `validate:"contains=purpose"`
ContainsAny string `validate:"containsany=!@#$"`
Excludes string `validate:"excludes=text"`
ExcludesAll string `validate:"excludesall=!@#$"`
ExcludesRune string `validate:"excludesrune=☻"`
ISBN string `validate:"isbn"`
ISBN10 string `validate:"isbn10"`
ISBN13 string `validate:"isbn13"`
UUID string `validate:"uuid"`
UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"`
DataURI string `validate:"datauri"`
Latitude string `validate:"latitude"`
Longitude string `validate:"longitude"`
SSN string `validate:"ssn"`
IP string `validate:"ip"`
IPv4 string `validate:"ipv4"`
IPv6 string `validate:"ipv6"`
CIDR string `validate:"cidr"`
CIDRv4 string `validate:"cidrv4"`
CIDRv6 string `validate:"cidrv6"`
TCPAddr string `validate:"tcp_addr"`
TCPAddrv4 string `validate:"tcp4_addr"`
TCPAddrv6 string `validate:"tcp6_addr"`
UDPAddr string `validate:"udp_addr"`
UDPAddrv4 string `validate:"udp4_addr"`
UDPAddrv6 string `validate:"udp6_addr"`
IPAddr string `validate:"ip_addr"`
IPAddrv4 string `validate:"ip4_addr"`
IPAddrv6 string `validate:"ip6_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
MAC string `validate:"mac"`
IsColor string `validate:"iscolor"`
StrPtrMinLen *string `validate:"min=10"`
StrPtrMaxLen *string `validate:"max=1"`
StrPtrLen *string `validate:"len=2"`
StrPtrLt *string `validate:"lt=1"`
StrPtrLte *string `validate:"lte=1"`
StrPtrGt *string `validate:"gt=10"`
StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
JSONString string `validate:"json"`
JWTString string `validate:"jwt"`
LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"`
Datetime string `validate:"datetime=2006-01-02"`
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
}
var test Test
test.Inner.EqCSFieldString = "1234"
test.Inner.GtCSFieldString = "1234"
test.Inner.GteCSFieldString = "1234"
test.MaxString = "1234"
test.MaxNumber = 2000
test.MaxMultiple = make([]string, 9)
test.LtString = "1234"
test.LtNumber = 6
test.LtMultiple = make([]string, 3)
test.LtTime = time.Now().Add(time.Hour * 24)
test.LteString = "1234"
test.LteNumber = 6
test.LteMultiple = make([]string, 3)
test.LteTime = time.Now().Add(time.Hour * 24)
test.LtFieldString = "12345"
test.LteFieldString = "12345"
test.LtCSFieldString = "1234"
test.LteCSFieldString = "1234"
test.AlphaString = "abc3"
test.AlphanumString = "abc3!"
test.NumericString = "12E.00"
test.NumberString = "12E"
test.Excludes = "this is some test text"
test.ExcludesAll = "This is Great!"
test.ExcludesRune = "Love it ☻"
test.ASCII = "カタカナ"
test.PrintableASCII = "カタカナ"
test.MultiByte = "1234feerf"
test.LowercaseString = "ABCDEFG"
test.UppercaseString = "abcdefg"
s := "toolong"
test.StrPtrMaxLen = &s
test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
test.Datetime = "2008-Feb-01"
err = validate.Struct(test)
NotEqual(t, err, nil)
errs, ok := err.(validator.ValidationErrors)
Equal(t, ok, true)
tests := []struct {
ns string
expected string
}{
{
ns: "Test.IsColor",
expected: "يجب أن يكون IsColor لون صالح",
},
{
ns: "Test.MAC",
expected: "يجب أن يحتوي MAC على عنوان MAC صالح",
},
{
ns: "Test.IPAddr",
expected: "يجب أن يكون IPAddr عنوان IP قابل للحل",
},
{
ns: "Test.IPAddrv4",
expected: "يجب أن يكون IPAddrv4 عنوان IP قابل للحل",
},
{
ns: "Test.IPAddrv6",
expected: "يجب أن يكون IPAddrv6 عنوان IPv6 قابل للحل",
},
{
ns: "Test.UDPAddr",
expected: "يجب أن يكون UDPAddr عنوان UDP صالح",
},
{
ns: "Test.UDPAddrv4",
expected: "يجب أن يكون UDPAddrv4 عنوان IPv4 UDP صالح",
},
{
ns: "Test.UDPAddrv6",
expected: "يجب أن يكون UDPAddrv6 عنوان IPv6 UDP صالح",
},
{
ns: "Test.TCPAddr",
expected: "يجب أن يكون TCPAddr عنوان TCP صالح",
},
{
ns: "Test.TCPAddrv4",
expected: "يجب أن يكون TCPAddrv4 عنوان IPv4 TCP صالح",
},
{
ns: "Test.TCPAddrv6",
expected: "يجب أن يكون TCPAddrv6 عنوان IPv6 TCP صالح",
},
{
ns: "Test.CIDR",
expected: "يجب أن يحتوي CIDR على علامة CIDR صالحة",
},
{
ns: "Test.CIDRv4",
expected: "يجب أن يحتوي CIDRv4 على علامة CIDR صالحة لعنوان IPv4",
},
{
ns: "Test.CIDRv6",
expected: "يجب أن يحتوي CIDRv6 على علامة CIDR صالحة لعنوان IPv6",
},
{
ns: "Test.SSN",
expected: "يجب أن يكون SSN رقم SSN صالح",
},
{
ns: "Test.IP",
expected: "يجب أن يكون IP عنوان IP صالح",
},
{
ns: "Test.IPv4",
expected: "يجب أن يكون IPv4 عنوان IPv4 صالح",
},
{
ns: "Test.IPv6",
expected: "يجب أن يكون IPv6 عنوان IPv6 صالح",
},
{
ns: "Test.DataURI",
expected: "يجب أن يحتوي DataURI على URI صالح للبيانات",
},
{
ns: "Test.Latitude",
expected: "يجب أن يحتوي Latitude على إحداثيات خط عرض صالحة",
},
{
ns: "Test.Longitude",
expected: "يجب أن يحتوي Longitude على إحداثيات خط طول صالحة",
},
{
ns: "Test.MultiByte",
expected: "يجب أن يحتوي MultiByte على أحرف متعددة البايت",
},
{
ns: "Test.ASCII",
expected: "يجب أن يحتوي ASCII على أحرف ascii فقط",
},
{
ns: "Test.PrintableASCII",
expected: "يجب أن يحتوي PrintableASCII على أحرف ascii قابلة للطباعة فقط",
},
{
ns: "Test.UUID",
expected: "يجب أن يكون UUID UUID صالح",
},
{
ns: "Test.UUID3",
expected: "يجب أن يكون UUID3 UUID صالح من النسخة 3",
},
{
ns: "Test.UUID4",
expected: "يجب أن يكون UUID4 UUID صالح من النسخة 4",
},
{
ns: "Test.UUID5",
expected: "يجب أن يكون UUID5 UUID صالح من النسخة 5",
},
{
ns: "Test.ULID",
expected: "يجب أن يكون ULID ULID صالح من نسخة",
},
{
ns: "Test.ISBN",
expected: "يجب أن يكون ISBN رقم ISBN صالح",
},
{
ns: "Test.ISBN10",
expected: "يجب أن يكون ISBN10 رقم ISBN-10 صالح",
},
{
ns: "Test.ISBN13",
expected: "يجب أن يكون ISBN13 رقم ISBN-13 صالح",
},
{
ns: "Test.Excludes",
expected: "لا يمكن أن يحتوي Excludes على النص 'text'",
},
{
ns: "Test.ExcludesAll",
expected: "لا يمكن أن يحتوي ExcludesAll على أي من الأحرف التالية '!@#$'",
},
{
ns: "Test.ExcludesRune",
expected: "لا يمكن أن يحتوي ExcludesRune على التالي '☻'",
},
{
ns: "Test.ContainsAny",
expected: "يجب أن يحتوي ContainsAny على حرف واحد على الأقل من الأحرف التالية '!@#$'",
},
{
ns: "Test.Contains",
expected: "يجب أن يحتوي Contains على النص 'purpose'",
},
{
ns: "Test.Base64",
expected: "يجب أن يكون Base64 سلسلة Base64 صالحة",
},
{
ns: "Test.Email",
expected: "يجب أن يكون Email عنوان بريد إلكتروني صالح",
},
{
ns: "Test.URL",
expected: "يجب أن يكون URL رابط إنترنت صالح",
},
{
ns: "Test.URI",
expected: "يجب أن يكون URI URI صالح",
},
{
ns: "Test.RGBColorString",
expected: "يجب أن يكون RGBColorString لون RGB صالح",
},
{
ns: "Test.RGBAColorString",
expected: "يجب أن يكون RGBAColorString لون RGBA صالح",
},
{
ns: "Test.HSLColorString",
expected: "يجب أن يكون HSLColorString لون HSL صالح",
},
{
ns: "Test.HSLAColorString",
expected: "يجب أن يكون HSLAColorString لون HSLA صالح",
},
{
ns: "Test.HexadecimalString",
expected: "يجب أن يكون HexadecimalString عددًا سداسيًا عشريًا صالحاً",
},
{
ns: "Test.HexColorString",
expected: "يجب أن يكون HexColorString لون HEX صالح",
},
{
ns: "Test.NumberString",
expected: "يجب أن يكون NumberString رقم صالح",
},
{
ns: "Test.NumericString",
expected: "يجب أن يكون NumericString قيمة رقمية صالحة",
},
{
ns: "Test.AlphanumString",
expected: "يمكن أن يحتوي AlphanumString على أحرف أبجدية رقمية فقط",
},
{
ns: "Test.AlphaString",
expected: "يمكن أن يحتوي AlphaString على أحرف أبجدية فقط",
},
{
ns: "Test.LtFieldString",
expected: "يجب أن يكون LtFieldString أصغر من MaxString",
},
{
ns: "Test.LteFieldString",
expected: "يجب أن يكون LteFieldString أصغر من أو يساوي MaxString",
},
{
ns: "Test.GtFieldString",
expected: "يجب أن يكون GtFieldString أكبر من MaxString",
},
{
ns: "Test.GteFieldString",
expected: "يجب أن يكون GteFieldString أكبر من أو يساوي MaxString",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString لا يمكن أن يساوي EqFieldString",
},
{
ns: "Test.LtCSFieldString",
expected: "يجب أن يكون LtCSFieldString أصغر من Inner.LtCSFieldString",
},
{
ns: "Test.LteCSFieldString",
expected: "يجب أن يكون LteCSFieldString أصغر من أو يساوي Inner.LteCSFieldString",
},
{
ns: "Test.GtCSFieldString",
expected: "يجب أن يكون GtCSFieldString أكبر من Inner.GtCSFieldString",
},
{
ns: "Test.GteCSFieldString",
expected: "يجب أن يكون GteCSFieldString أكبر من أو يساوي Inner.GteCSFieldString",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString لا يمكن أن يساوي Inner.NeCSFieldString",
},
{
ns: "Test.EqCSFieldString",
expected: "يجب أن يكون EqCSFieldString مساويا ل Inner.EqCSFieldString",
},
{
ns: "Test.EqFieldString",
expected: "يجب أن يكون EqFieldString مساويا ل MaxString",
},
{
ns: "Test.GteString",
expected: "يجب أن يكون طول GteString على الأقل 3 أحرف",
},
{
ns: "Test.GteNumber",
expected: "GteNumber يجب أن يكون 5.56 أو أكبر",
},
{
ns: "Test.GteMultiple",
expected: "يجب أن يحتوي GteMultiple على 2 عناصر على الأقل",
},
{
ns: "Test.GteTime",
expected: "يجب أن يكون GteTime أكبر من أو يساوي التاريخ والوقت الحاليين",
},
{
ns: "Test.GtString",
expected: "يجب أن يكون طول GtString أكبر من 3 أحرف",
},
{
ns: "Test.GtNumber",
expected: "يجب أن يكون GtNumber أكبر من 5.56",
},
{
ns: "Test.GtMultiple",
expected: "يجب أن يحتوي GtMultiple على أكثر من 2 عناصر",
},
{
ns: "Test.GtTime",
expected: "يجب أن يكون GtTime أكبر من التاريخ والوقت الحاليين",
},
{
ns: "Test.LteString",
expected: "يجب أن يكون طول LteString كحد أقصى 3 أحرف",
},
{
ns: "Test.LteNumber",
expected: "LteNumber يجب أن يكون 5.56 أو اقل",
},
{
ns: "Test.LteMultiple",
expected: "يجب أن يحتوي LteMultiple على 2 عناصر كحد أقصى",
},
{
ns: "Test.LteTime",
expected: "يجب أن يكون LteTime أقل من أو يساوي التاريخ والوقت الحاليين",
},
{
ns: "Test.LtString",
expected: "يجب أن يكون طول LtString أقل من 3 أحرف",
},
{
ns: "Test.LtNumber",
expected: "يجب أن يكون LtNumber أقل من 5.56",
},
{
ns: "Test.LtMultiple",
expected: "يجب أن يحتوي LtMultiple على أقل من 2 عناصر",
},
{
ns: "Test.LtTime",
expected: "يجب أن يكون LtTime أقل من التاريخ والوقت الحاليين",
},
{
ns: "Test.NeString",
expected: "NeString يجب ألا يساوي ",
},
{
ns: "Test.NeNumber",
expected: "NeNumber يجب ألا يساوي 0.00",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple يجب ألا يساوي 0",
},
{
ns: "Test.EqString",
expected: "EqString لا يساوي 3",
},
{
ns: "Test.EqNumber",
expected: "EqNumber لا يساوي 2.33",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple لا يساوي 7",
},
{
ns: "Test.MaxString",
expected: "يجب أن يكون طول MaxString بحد أقصى 3 أحرف",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber يجب أن يكون 1,113.00 أو اقل",
},
{
ns: "Test.MaxMultiple",
expected: "يجب أن يحتوي MaxMultiple على 7 عناصر كحد أقصى",
},
{
ns: "Test.MinString",
expected: "MinString يجب أن يكون 1 حرف أو اقل",
},
{
ns: "Test.MinNumber",
expected: "MinNumber يجب أن يكون 1,113.00 أو اقل",
},
{
ns: "Test.MinMultiple",
expected: "يجب أن يحتوي MinMultiple على 7 عناصر على الأقل",
},
{
ns: "Test.LenString",
expected: "يجب أن يكون طول LenString مساويا ل 1 حرف",
},
{
ns: "Test.LenNumber",
expected: "يجب أن يكون LenNumber مساويا ل 1,113.00",
},
{
ns: "Test.LenMultiple",
expected: "يجب أن يحتوي LenMultiple على 7 عناصر",
},
{
ns: "Test.RequiredString",
expected: "حقل RequiredString مطلوب",
},
{
ns: "Test.RequiredNumber",
expected: "حقل RequiredNumber مطلوب",
},
{
ns: "Test.RequiredMultiple",
expected: "حقل RequiredMultiple مطلوب",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen يجب أن يكون 10 أحرف أو اقل",
},
{
ns: "Test.StrPtrMaxLen",
expected: "يجب أن يكون طول StrPtrMaxLen بحد أقصى 1 حرف",
},
{
ns: "Test.StrPtrLen",
expected: "يجب أن يكون طول StrPtrLen مساويا ل 2 أحرف",
},
{
ns: "Test.StrPtrLt",
expected: "يجب أن يكون طول StrPtrLt أقل من 1 حرف",
},
{
ns: "Test.StrPtrLte",
expected: "يجب أن يكون طول StrPtrLte كحد أقصى 1 حرف",
},
{
ns: "Test.StrPtrGt",
expected: "يجب أن يكون طول StrPtrGt أكبر من 10 أحرف",
},
{
ns: "Test.StrPtrGte",
expected: "يجب أن يكون طول StrPtrGte على الأقل 10 أحرف",
},
{
ns: "Test.OneOfString",
expected: "يجب أن يكون OneOfString واحدا من [red green]",
},
{
ns: "Test.OneOfInt",
expected: "يجب أن يكون OneOfInt واحدا من [5 63]",
},
{
ns: "Test.UniqueSlice",
expected: "يجب أن يحتوي UniqueSlice على قيم فريدة",
},
{
ns: "Test.UniqueArray",
expected: "يجب أن يحتوي UniqueArray على قيم فريدة",
},
{
ns: "Test.UniqueMap",
expected: "يجب أن يحتوي UniqueMap على قيم فريدة",
},
{
ns: "Test.JSONString",
expected: "يجب أن يكون JSONString نص json صالح",
},
{
ns: "Test.JWTString",
expected: "يجب أن يكون JWTString نص jwt صالح",
},
{
ns: "Test.LowercaseString",
expected: "يجب أن يكون LowercaseString نص حروف صغيرة",
},
{
ns: "Test.UppercaseString",
expected: "يجب أن يكون UppercaseString نص حروف كبيرة",
},
{
ns: "Test.Datetime",
expected: "لا يتطابق Datetime مع تنسيق 2006-01-02",
},
{
ns: "Test.PostCode",
expected: "لا يتطابق PostCode مع تنسيق الرمز البريدي للبلد SG",
},
{
ns: "Test.PostCodeByField",
expected: "لا يتطابق PostCodeByField مع تنسيق الرمز البريدي للبلد في حقل PostCodeCountry",
},
}
for _, tt := range tests {
var fe validator.FieldError
for _, e := range errs {
if tt.ns == e.Namespace() {
fe = e
break
}
}
NotEqual(t, fe, nil)
Equal(t, tt.expected, fe.Translate(trans))
}
}

@ -16,7 +16,6 @@ import (
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
// for all built in tag's in validator; you may add your own as desired. // 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) { func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) {
translations := []struct { translations := []struct {
tag string tag string
translation string translation string
@ -29,10 +28,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} is a required field", translation: "{0} is a required field",
override: false, override: false,
}, },
{
tag: "required_if",
translation: "{0} is a required field",
override: false,
},
{ {
tag: "len", tag: "len",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil { if err = ut.Add("len-string", "{0} must be {1} in length", false); err != nil {
return return
} }
@ -61,10 +64,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
} }
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
@ -123,7 +124,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "min", tag: "min",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil { if err = ut.Add("min-string", "{0} must be at least {1} in length", false); err != nil {
return return
} }
@ -152,10 +152,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
} }
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
@ -214,7 +212,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "max", tag: "max",
customRegisFunc: func(ut ut.Translator) (err error) { 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 { if err = ut.Add("max-string", "{0} must be a maximum of {1} in length", false); err != nil {
return return
} }
@ -243,10 +240,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
} }
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
@ -307,7 +302,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} is not equal to {1}", translation: "{0} is not equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
fmt.Printf("warning: error translating FieldError: %#v", fe) fmt.Printf("warning: error translating FieldError: %#v", fe)
@ -322,7 +316,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} should not be equal to {1}", translation: "{0} should not be equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
fmt.Printf("warning: error translating FieldError: %#v", fe) fmt.Printf("warning: error translating FieldError: %#v", fe)
@ -335,7 +328,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "lt", tag: "lt",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil { if err = ut.Add("lt-string", "{0} must be less than {1} in length", false); err != nil {
return return
} }
@ -369,10 +361,8 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
} }
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
var f64 float64 var f64 float64
@ -380,7 +370,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
var kind reflect.Kind var kind reflect.Kind
fn := func() (err error) { fn := func() (err error) {
if idx := strings.Index(fe.Param(), "."); idx != -1 { if idx := strings.Index(fe.Param(), "."); idx != -1 {
digits = uint64(len(fe.Param()[idx+1:])) digits = uint64(len(fe.Param()[idx+1:]))
} }
@ -456,7 +445,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "lte", tag: "lte",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil { if err = ut.Add("lte-string", "{0} must be at maximum {1} in length", false); err != nil {
return return
} }
@ -492,7 +480,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
var f64 float64 var f64 float64
@ -500,7 +487,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
var kind reflect.Kind var kind reflect.Kind
fn := func() (err error) { fn := func() (err error) {
if idx := strings.Index(fe.Param(), "."); idx != -1 { if idx := strings.Index(fe.Param(), "."); idx != -1 {
digits = uint64(len(fe.Param()[idx+1:])) digits = uint64(len(fe.Param()[idx+1:]))
} }
@ -576,7 +562,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "gt", tag: "gt",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil { if err = ut.Add("gt-string", "{0} must be greater than {1} in length", false); err != nil {
return return
} }
@ -612,7 +597,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
var f64 float64 var f64 float64
@ -620,7 +604,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
var kind reflect.Kind var kind reflect.Kind
fn := func() (err error) { fn := func() (err error) {
if idx := strings.Index(fe.Param(), "."); idx != -1 { if idx := strings.Index(fe.Param(), "."); idx != -1 {
digits = uint64(len(fe.Param()[idx+1:])) digits = uint64(len(fe.Param()[idx+1:]))
} }
@ -696,7 +679,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "gte", tag: "gte",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil { if err = ut.Add("gte-string", "{0} must be at least {1} in length", false); err != nil {
return return
} }
@ -732,7 +714,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
var f64 float64 var f64 float64
@ -740,7 +721,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
var kind reflect.Kind var kind reflect.Kind
fn := func() (err error) { fn := func() (err error) {
if idx := strings.Index(fe.Param(), "."); idx != -1 { if idx := strings.Index(fe.Param(), "."); idx != -1 {
digits = uint64(len(fe.Param()[idx+1:])) digits = uint64(len(fe.Param()[idx+1:]))
} }
@ -818,7 +798,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be equal to {1}", translation: "{0} must be equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -833,7 +812,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be equal to {1}", translation: "{0} must be equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -848,7 +826,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} cannot be equal to {1}", translation: "{0} cannot be equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -863,7 +840,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be greater than {1}", translation: "{0} must be greater than {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -878,7 +854,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be greater than or equal to {1}", translation: "{0} must be greater than or equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -893,7 +868,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be less than {1}", translation: "{0} must be less than {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -908,7 +882,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be less than or equal to {1}", translation: "{0} must be less than or equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -923,7 +896,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} cannot be equal to {1}", translation: "{0} cannot be equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -938,7 +910,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be greater than {1}", translation: "{0} must be greater than {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -953,7 +924,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be greater than or equal to {1}", translation: "{0} must be greater than or equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -968,7 +938,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be less than {1}", translation: "{0} must be less than {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -983,7 +952,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be less than or equal to {1}", translation: "{0} must be less than or equal to {1}",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1073,7 +1041,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must contain the text '{1}'", translation: "{0} must contain the text '{1}'",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1088,7 +1055,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must contain at least one of the following characters '{1}'", translation: "{0} must contain at least one of the following characters '{1}'",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1103,7 +1069,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} cannot contain the text '{1}'", translation: "{0} cannot contain the text '{1}'",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1118,7 +1083,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} cannot contain any of the following characters '{1}'", translation: "{0} cannot contain any of the following characters '{1}'",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1133,7 +1097,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} cannot contain the following '{1}'", translation: "{0} cannot contain the following '{1}'",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1178,6 +1141,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid version 5 UUID", translation: "{0} must be a valid version 5 UUID",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} must be a valid ULID",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} must contain only ascii characters", translation: "{0} must contain only ascii characters",
@ -1298,6 +1266,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must contain a valid MAC address", translation: "{0} must contain a valid MAC address",
override: false, override: false,
}, },
{
tag: "fqdn",
translation: "{0} must be a valid FQDN",
override: false,
},
{ {
tag: "unique", tag: "unique",
translation: "{0} must contain unique values", translation: "{0} must contain unique values",
@ -1308,6 +1281,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid color", translation: "{0} must be a valid color",
override: false, override: false,
}, },
{
tag: "cron",
translation: "{0} must be a valid cron expression",
override: false,
},
{ {
tag: "oneof", tag: "oneof",
translation: "{0} must be one of [{1}]", translation: "{0} must be one of [{1}]",
@ -1325,8 +1303,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
tag: "json", tag: "json",
translation: "{0} must be a valid json string", translation: "{0} must be a valid json string",
override: false, override: false,
}, },
{ {
tag: "jwt",
translation: "{0} must be a valid jwt string",
override: false,
},
{
tag: "lowercase", tag: "lowercase",
translation: "{0} must be a lowercase string", translation: "{0} must be a lowercase string",
override: false, override: false,
@ -1341,7 +1324,34 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} does not match the {1} format", translation: "{0} does not match the {1} format",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { 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()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1351,22 +1361,26 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return t return t
}, },
}, },
{
tag: "boolean",
translation: "{0} must be a valid boolean value",
override: false,
},
{
tag: "cve",
translation: "{0} must be a valid cve identifier",
override: false,
},
} }
for _, t := range translations { for _, t := range translations {
if t.customTransFunc != nil && t.customRegisFunc != nil { if t.customTransFunc != nil && t.customRegisFunc != nil {
err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc)
} else if t.customTransFunc != nil && t.customRegisFunc == nil { } else if t.customTransFunc != nil && t.customRegisFunc == nil {
err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc)
} else if t.customTransFunc == nil && t.customRegisFunc != nil { } else if t.customTransFunc == nil && t.customRegisFunc != nil {
err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc)
} else { } else {
err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc)
} }
@ -1380,21 +1394,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
} }
func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc {
return func(ut ut.Translator) (err error) { return func(ut ut.Translator) (err error) {
if err = ut.Add(tag, translation, override); err != nil { if err = ut.Add(tag, translation, override); err != nil {
return return
} }
return return
} }
} }
func translateFunc(ut ut.Translator, fe validator.FieldError) string { func translateFunc(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field()) t, err := ut.T(fe.Tag(), fe.Field())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)

@ -11,7 +11,6 @@ import (
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
eng := english.New() eng := english.New()
uni := ut.New(eng, eng) uni := ut.New(eng, eng)
trans, _ := uni.GetTranslator("en") trans, _ := uni.GetTranslator("en")
@ -28,6 +27,7 @@ func TestTranslations(t *testing.T) {
GteCSFieldString string GteCSFieldString string
LtCSFieldString string LtCSFieldString string
LteCSFieldString string LteCSFieldString string
RequiredIf string
} }
type Test struct { type Test struct {
@ -35,6 +35,7 @@ func TestTranslations(t *testing.T) {
RequiredString string `validate:"required"` RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"` RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"` RequiredMultiple []string `validate:"required"`
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"`
LenString string `validate:"len=1"` LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"` LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"` LenMultiple []string `validate:"len=7"`
@ -104,6 +105,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -128,6 +130,7 @@ func TestTranslations(t *testing.T) {
IPAddrv6 string `validate:"ip6_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 UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
MAC string `validate:"mac"` MAC string `validate:"mac"`
FQDN string `validate:"fqdn"`
IsColor string `validate:"iscolor"` IsColor string `validate:"iscolor"`
StrPtrMinLen *string `validate:"min=10"` StrPtrMinLen *string `validate:"min=10"`
StrPtrMaxLen *string `validate:"max=1"` StrPtrMaxLen *string `validate:"max=1"`
@ -142,9 +145,15 @@ func TestTranslations(t *testing.T) {
UniqueArray [3]string `validate:"unique"` UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"`
JSONString string `validate:"json"` JSONString string `validate:"json"`
JWTString string `validate:"jwt"`
LowercaseString string `validate:"lowercase"` LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"` UppercaseString string `validate:"uppercase"`
Datetime string `validate:"datetime=2006-01-02"` Datetime string `validate:"datetime=2006-01-02"`
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
BooleanString string `validate:"boolean"`
CveString string `validate:"cve"`
} }
var test Test var test Test
@ -197,6 +206,10 @@ func TestTranslations(t *testing.T) {
test.UniqueSlice = []string{"1234", "1234"} test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"} test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
test.Datetime = "2008-Feb-01" test.Datetime = "2008-Feb-01"
test.BooleanString = "A"
test.CveString = "A"
test.Inner.RequiredIf = "abcd"
err = validate.Struct(test) err = validate.Struct(test)
NotEqual(t, err, nil) NotEqual(t, err, nil)
@ -216,6 +229,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.MAC", ns: "Test.MAC",
expected: "MAC must contain a valid MAC address", expected: "MAC must contain a valid MAC address",
}, },
{
ns: "Test.FQDN",
expected: "FQDN must be a valid FQDN",
},
{ {
ns: "Test.IPAddr", ns: "Test.IPAddr",
expected: "IPAddr must be a resolvable IP address", expected: "IPAddr must be a resolvable IP address",
@ -320,6 +337,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 must be a valid version 5 UUID", expected: "UUID5 must be a valid version 5 UUID",
}, },
{
ns: "Test.ULID",
expected: "ULID must be a valid ULID",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN must be a valid ISBN number", expected: "ISBN must be a valid ISBN number",
@ -584,6 +605,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.RequiredString", ns: "Test.RequiredString",
expected: "RequiredString is a required field", expected: "RequiredString is a required field",
}, },
{
ns: "Test.RequiredIf",
expected: "RequiredIf is a required field",
},
{ {
ns: "Test.RequiredNumber", ns: "Test.RequiredNumber",
expected: "RequiredNumber is a required field", expected: "RequiredNumber is a required field",
@ -644,6 +669,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.JSONString", ns: "Test.JSONString",
expected: "JSONString must be a valid json string", expected: "JSONString must be a valid json string",
}, },
{
ns: "Test.JWTString",
expected: "JWTString must be a valid jwt string",
},
{ {
ns: "Test.LowercaseString", ns: "Test.LowercaseString",
expected: "LowercaseString must be a lowercase string", expected: "LowercaseString must be a lowercase string",
@ -656,6 +685,22 @@ func TestTranslations(t *testing.T) {
ns: "Test.Datetime", ns: "Test.Datetime",
expected: "Datetime does not match the 2006-01-02 format", 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",
},
{
ns: "Test.BooleanString",
expected: "BooleanString must be a valid boolean value",
},
{
ns: "Test.CveString",
expected: "CveString must be a valid cve identifier",
},
} }
for _, tt := range tests { for _, tt := range tests {
@ -672,5 +717,4 @@ func TestTranslations(t *testing.T) {
NotEqual(t, fe, nil) NotEqual(t, fe, nil)
Equal(t, tt.expected, fe.Translate(trans)) Equal(t, tt.expected, fe.Translate(trans))
} }
} }

@ -29,6 +29,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} es un campo requerido", translation: "{0} es un campo requerido",
override: false, override: false,
}, },
{
tag: "required_if",
translation: "{0} es un campo requerido",
override: false,
},
{ {
tag: "len", tag: "len",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
@ -1178,6 +1183,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} debe ser una versión válida 5 UUID", translation: "{0} debe ser una versión válida 5 UUID",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} debe ser un ULID válido",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} debe contener sólo caracteres ascii", translation: "{0} debe contener sólo caracteres ascii",

@ -4,9 +4,9 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
spanish "github.com/go-playground/locales/es" spanish "github.com/go-playground/locales/es"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
@ -35,6 +35,7 @@ func TestTranslations(t *testing.T) {
RequiredString string `validate:"required"` RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"` RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"` RequiredMultiple []string `validate:"required"`
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"`
LenString string `validate:"len=1"` LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"` LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"` LenMultiple []string `validate:"len=7"`
@ -104,6 +105,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -312,6 +314,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 debe ser una versión válida 5 UUID", expected: "UUID5 debe ser una versión válida 5 UUID",
}, },
{
ns: "Test.ULID",
expected: "ULID debe ser un ULID válido",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN debe ser un número ISBN válido", expected: "ISBN debe ser un número ISBN válido",

File diff suppressed because it is too large Load Diff

@ -0,0 +1,690 @@
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"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"`
DataURI string `validate:"datauri"`
Latitude string `validate:"latitude"`
Longitude string `validate:"longitude"`
SSN string `validate:"ssn"`
IP string `validate:"ip"`
IPv4 string `validate:"ipv4"`
IPv6 string `validate:"ipv6"`
CIDR string `validate:"cidr"`
CIDRv4 string `validate:"cidrv4"`
CIDRv6 string `validate:"cidrv6"`
TCPAddr string `validate:"tcp_addr"`
TCPAddrv4 string `validate:"tcp4_addr"`
TCPAddrv6 string `validate:"tcp6_addr"`
UDPAddr string `validate:"udp_addr"`
UDPAddrv4 string `validate:"udp4_addr"`
UDPAddrv6 string `validate:"udp6_addr"`
IPAddr string `validate:"ip_addr"`
IPAddrv4 string `validate:"ip4_addr"`
IPAddrv6 string `validate:"ip6_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
MAC string `validate:"mac"`
IsColor string `validate:"iscolor"`
StrPtrMinLen *string `validate:"min=10"`
StrPtrMaxLen *string `validate:"max=1"`
StrPtrLen *string `validate:"len=2"`
StrPtrLt *string `validate:"lt=1"`
StrPtrLte *string `validate:"lte=1"`
StrPtrGt *string `validate:"gt=10"`
StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
JSONString string `validate:"json"`
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.ULID",
expected: "ULID باید یک ULID معتبر باشد",
},
{
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))
}
}

@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} doit être un UUID version 5 valid", translation: "{0} doit être un UUID version 5 valid",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} doit être une ULID valide",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} ne doit contenir que des caractères ascii", translation: "{0} ne doit contenir que des caractères ascii",

@ -4,9 +4,9 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
french "github.com/go-playground/locales/fr" french "github.com/go-playground/locales/fr"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 doit être un UUID version 5 valid", expected: "UUID5 doit être un UUID version 5 valid",
}, },
{
ns: "Test.ULID",
expected: "ULID doit être une ULID valide",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN doit être un numéro ISBN valid", expected: "ISBN doit être un numéro ISBN valid",
@ -536,7 +541,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MaxNumber", ns: "Test.MaxNumber",
expected: "MaxNumber doit être égal à 1 113,00 ou moins", expected: "MaxNumber doit être égal à 1113,00 ou moins",
}, },
{ {
ns: "Test.MaxMultiple", ns: "Test.MaxMultiple",
@ -548,7 +553,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MinNumber", ns: "Test.MinNumber",
expected: "MinNumber doit être égal à 1 113,00 ou plus", expected: "MinNumber doit être égal à 1113,00 ou plus",
}, },
{ {
ns: "Test.MinMultiple", ns: "Test.MinMultiple",
@ -560,7 +565,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.LenNumber", ns: "Test.LenNumber",
expected: "LenNumber doit être égal à 1 113,00", expected: "LenNumber doit être égal à 1113,00",
}, },
{ {
ns: "Test.LenMultiple", ns: "Test.LenMultiple",

@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} harus berupa UUID versi 5 yang valid", translation: "{0} harus berupa UUID versi 5 yang valid",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} harus berupa ULID yang valid",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} hanya boleh berisi karakter ascii", translation: "{0} hanya boleh berisi karakter ascii",

@ -4,9 +4,9 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
indonesia "github.com/go-playground/locales/id" indonesia "github.com/go-playground/locales/id"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 harus berupa UUID versi 5 yang valid", expected: "UUID5 harus berupa UUID versi 5 yang valid",
}, },
{
ns: "Test.ULID",
expected: "ULID harus berupa ULID yang valid",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN harus berupa nomor ISBN yang valid", expected: "ISBN harus berupa nomor ISBN yang valid",

File diff suppressed because it is too large Load Diff

@ -0,0 +1,725 @@
package it
import (
"testing"
"time"
. "github.com/go-playground/assert/v2"
italian "github.com/go-playground/locales/it"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
ita := italian.New()
uni := ut.New(ita, ita)
trans, _ := uni.GetTranslator("it")
validate := validator.New()
err := RegisterDefaultTranslations(validate, trans)
Equal(t, err, nil)
type Inner struct {
EqCSFieldString string
NeCSFieldString string
GtCSFieldString string
GteCSFieldString string
LtCSFieldString string
LteCSFieldString string
}
type Test struct {
Inner Inner
RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"`
LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"`
MinString string `validate:"min=1"`
MinNumber float64 `validate:"min=1113.00"`
MinMultiple []string `validate:"min=7"`
MaxString string `validate:"max=3"`
MaxNumber float64 `validate:"max=1113.00"`
MaxMultiple []string `validate:"max=7"`
EqString string `validate:"eq=3"`
EqNumber float64 `validate:"eq=2.33"`
EqMultiple []string `validate:"eq=7"`
NeString string `validate:"ne="`
NeNumber float64 `validate:"ne=0.00"`
NeMultiple []string `validate:"ne=0"`
LtString string `validate:"lt=3"`
LtNumber float64 `validate:"lt=5.56"`
LtMultiple []string `validate:"lt=2"`
LtTime time.Time `validate:"lt"`
LteString string `validate:"lte=3"`
LteNumber float64 `validate:"lte=5.56"`
LteMultiple []string `validate:"lte=2"`
LteTime time.Time `validate:"lte"`
GtString string `validate:"gt=3"`
GtNumber float64 `validate:"gt=5.56"`
GtMultiple []string `validate:"gt=2"`
GtTime time.Time `validate:"gt"`
GteString string `validate:"gte=3"`
GteNumber float64 `validate:"gte=5.56"`
GteMultiple []string `validate:"gte=2"`
GteTime time.Time `validate:"gte"`
EqFieldString string `validate:"eqfield=MaxString"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
NeFieldString string `validate:"nefield=EqFieldString"`
GtFieldString string `validate:"gtfield=MaxString"`
GteFieldString string `validate:"gtefield=MaxString"`
LtFieldString string `validate:"ltfield=MaxString"`
LteFieldString string `validate:"ltefield=MaxString"`
AlphaString string `validate:"alpha"`
AlphanumString string `validate:"alphanum"`
NumericString string `validate:"numeric"`
NumberString string `validate:"number"`
HexadecimalString string `validate:"hexadecimal"`
HexColorString string `validate:"hexcolor"`
RGBColorString string `validate:"rgb"`
RGBAColorString string `validate:"rgba"`
HSLColorString string `validate:"hsl"`
HSLAColorString string `validate:"hsla"`
Email string `validate:"email"`
URL string `validate:"url"`
URI string `validate:"uri"`
Base64 string `validate:"base64"`
Contains string `validate:"contains=purpose"`
ContainsAny string `validate:"containsany=!@#$"`
Excludes string `validate:"excludes=text"`
ExcludesAll string `validate:"excludesall=!@#$"`
ExcludesRune string `validate:"excludesrune=☻"`
ISBN string `validate:"isbn"`
ISBN10 string `validate:"isbn10"`
ISBN13 string `validate:"isbn13"`
UUID string `validate:"uuid"`
UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"`
DataURI string `validate:"datauri"`
Latitude string `validate:"latitude"`
Longitude string `validate:"longitude"`
SSN string `validate:"ssn"`
IP string `validate:"ip"`
IPv4 string `validate:"ipv4"`
IPv6 string `validate:"ipv6"`
CIDR string `validate:"cidr"`
CIDRv4 string `validate:"cidrv4"`
CIDRv6 string `validate:"cidrv6"`
TCPAddr string `validate:"tcp_addr"`
TCPAddrv4 string `validate:"tcp4_addr"`
TCPAddrv6 string `validate:"tcp6_addr"`
UDPAddr string `validate:"udp_addr"`
UDPAddrv4 string `validate:"udp4_addr"`
UDPAddrv6 string `validate:"udp6_addr"`
IPAddr string `validate:"ip_addr"`
IPAddrv4 string `validate:"ip4_addr"`
IPAddrv6 string `validate:"ip6_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
MAC string `validate:"mac"`
IsColor string `validate:"iscolor"`
StrPtrMinLen *string `validate:"min=10"`
StrPtrMaxLen *string `validate:"max=1"`
StrPtrLen *string `validate:"len=2"`
StrPtrLt *string `validate:"lt=1"`
StrPtrLte *string `validate:"lte=1"`
StrPtrGt *string `validate:"gt=10"`
StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
BooleanString string `validate:"boolean"`
JSONString string `validate:"json"`
JWTString string `validate:"jwt"`
LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"`
StartsWithString string `validate:"startswith=foo"`
StartsNotWithString string `validate:"startsnotwith=foo"`
EndsWithString string `validate:"endswith=foo"`
EndsNotWithString string `validate:"endsnotwith=foo"`
Datetime string `validate:"datetime=2006-01-02"`
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
}
var test Test
test.Inner.EqCSFieldString = "1234"
test.Inner.GtCSFieldString = "1234"
test.Inner.GteCSFieldString = "1234"
test.MaxString = "1234"
test.MaxNumber = 2000
test.MaxMultiple = make([]string, 9)
test.LtString = "1234"
test.LtNumber = 6
test.LtMultiple = make([]string, 3)
test.LtTime = time.Now().Add(time.Hour * 24)
test.LteString = "1234"
test.LteNumber = 6
test.LteMultiple = make([]string, 3)
test.LteTime = time.Now().Add(time.Hour * 24)
test.LtFieldString = "12345"
test.LteFieldString = "12345"
test.LtCSFieldString = "1234"
test.LteCSFieldString = "1234"
test.AlphaString = "abc3"
test.AlphanumString = "abc3!"
test.NumericString = "12E.00"
test.NumberString = "12E"
test.Excludes = "this is some test text"
test.ExcludesAll = "This is Great!"
test.ExcludesRune = "Love it ☻"
test.ASCII = "カタカナ"
test.PrintableASCII = "カタカナ"
test.MultiByte = "1234feerf"
test.LowercaseString = "ABCDEFG"
test.UppercaseString = "abcdefg"
test.StartsWithString = "hello"
test.StartsNotWithString = "foo-hello"
test.EndsWithString = "hello"
test.EndsNotWithString = "hello-foo"
s := "toolong"
test.StrPtrMaxLen = &s
test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
test.Datetime = "2008-Feb-01"
err = validate.Struct(test)
NotEqual(t, err, nil)
errs, ok := err.(validator.ValidationErrors)
Equal(t, ok, true)
tests := []struct {
ns string
expected string
}{
{
ns: "Test.IsColor",
expected: "IsColor deve essere un colore valido",
},
{
ns: "Test.MAC",
expected: "MAC deve contenere un indirizzo MAC valido",
},
{
ns: "Test.IPAddr",
expected: "IPAddr deve essere un indirizzo IP risolvibile",
},
{
ns: "Test.IPAddrv4",
expected: "IPAddrv4 deve essere un indirizzo IPv4 risolvibile",
},
{
ns: "Test.IPAddrv6",
expected: "IPAddrv6 deve essere un indirizzo IPv6 risolvibile",
},
{
ns: "Test.UDPAddr",
expected: "UDPAddr deve essere un indirizzo UDP valido",
},
{
ns: "Test.UDPAddrv4",
expected: "UDPAddrv4 deve essere un indirizzo IPv4 UDP valido",
},
{
ns: "Test.UDPAddrv6",
expected: "UDPAddrv6 deve essere un indirizzo IPv6 UDP valido",
},
{
ns: "Test.TCPAddr",
expected: "TCPAddr deve essere un indirizzo TCP valido",
},
{
ns: "Test.TCPAddrv4",
expected: "TCPAddrv4 deve essere un indirizzo IPv4 TCP valido",
},
{
ns: "Test.TCPAddrv6",
expected: "TCPAddrv6 deve essere un indirizzo IPv6 TCP valido",
},
{
ns: "Test.CIDR",
expected: "CIDR deve contenere una notazione CIDR valida",
},
{
ns: "Test.CIDRv4",
expected: "CIDRv4 deve contenere una notazione CIDR per un indirizzo IPv4 valida",
},
{
ns: "Test.CIDRv6",
expected: "CIDRv6 deve contenere una notazione CIDR per un indirizzo IPv6 valida",
},
{
ns: "Test.SSN",
expected: "SSN deve essere un numero SSN valido",
},
{
ns: "Test.IP",
expected: "IP deve essere un indirizzo IP valido",
},
{
ns: "Test.IPv4",
expected: "IPv4 deve essere un indirizzo IPv4 valido",
},
{
ns: "Test.IPv6",
expected: "IPv6 deve essere un indirizzo IPv6 valido",
},
{
ns: "Test.DataURI",
expected: "DataURI deve contenere un Data URI valido",
},
{
ns: "Test.Latitude",
expected: "Latitude deve contenere una latitudine valida",
},
{
ns: "Test.Longitude",
expected: "Longitude deve contenere una longitudine valida",
},
{
ns: "Test.MultiByte",
expected: "MultiByte deve contenere caratteri multibyte",
},
{
ns: "Test.ASCII",
expected: "ASCII deve contenere solo caratteri ascii",
},
{
ns: "Test.PrintableASCII",
expected: "PrintableASCII deve contenere solo caratteri ascii stampabili",
},
{
ns: "Test.UUID",
expected: "UUID deve essere un UUID valido",
},
{
ns: "Test.UUID3",
expected: "UUID3 deve essere un UUID versione 3 valido",
},
{
ns: "Test.UUID4",
expected: "UUID4 deve essere un UUID versione 4 valido",
},
{
ns: "Test.UUID5",
expected: "UUID5 deve essere un UUID versione 5 valido",
},
{
ns: "Test.ULID",
expected: "ULID deve essere un ULID valido",
},
{
ns: "Test.ISBN",
expected: "ISBN deve essere un numero ISBN valido",
},
{
ns: "Test.ISBN10",
expected: "ISBN10 deve essere un numero ISBN-10 valido",
},
{
ns: "Test.ISBN13",
expected: "ISBN13 deve essere un numero ISBN-13 valido",
},
{
ns: "Test.Excludes",
expected: "Excludes non deve contenere il testo 'text'",
},
{
ns: "Test.ExcludesAll",
expected: "ExcludesAll non deve contenere alcuno dei seguenti caratteri '!@#$'",
},
{
ns: "Test.ExcludesRune",
expected: "ExcludesRune non deve contenere '☻'",
},
{
ns: "Test.ContainsAny",
expected: "ContainsAny deve contenere almeno uno dei seguenti caratteri '!@#$'",
},
{
ns: "Test.Contains",
expected: "Contains deve contenere il testo 'purpose'",
},
{
ns: "Test.Base64",
expected: "Base64 deve essere una stringa Base64 valida",
},
{
ns: "Test.Email",
expected: "Email deve essere un indirizzo email valido",
},
{
ns: "Test.URL",
expected: "URL deve essere un URL valido",
},
{
ns: "Test.URI",
expected: "URI deve essere un URI valido",
},
{
ns: "Test.RGBColorString",
expected: "RGBColorString deve essere un colore RGB valido",
},
{
ns: "Test.RGBAColorString",
expected: "RGBAColorString deve essere un colore RGBA valido",
},
{
ns: "Test.HSLColorString",
expected: "HSLColorString deve essere un colore HSL valido",
},
{
ns: "Test.HSLAColorString",
expected: "HSLAColorString deve essere un colore HSLA valido",
},
{
ns: "Test.HexadecimalString",
expected: "HexadecimalString deve essere un esadecimale valido",
},
{
ns: "Test.HexColorString",
expected: "HexColorString deve essere un colore HEX valido",
},
{
ns: "Test.NumberString",
expected: "NumberString deve essere un numero valido",
},
{
ns: "Test.NumericString",
expected: "NumericString deve essere un valore numerico valido",
},
{
ns: "Test.AlphanumString",
expected: "AlphanumString può contenere solo caratteri alfanumerici",
},
{
ns: "Test.AlphaString",
expected: "AlphaString può contenere solo caratteri alfabetici",
},
{
ns: "Test.LtFieldString",
expected: "LtFieldString deve essere minore di MaxString",
},
{
ns: "Test.LteFieldString",
expected: "LteFieldString deve essere minore o uguale a MaxString",
},
{
ns: "Test.GtFieldString",
expected: "GtFieldString deve essere maggiore di MaxString",
},
{
ns: "Test.GteFieldString",
expected: "GteFieldString deve essere maggiore o uguale a MaxString",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString deve essere diverso da EqFieldString",
},
{
ns: "Test.LtCSFieldString",
expected: "LtCSFieldString deve essere minore di Inner.LtCSFieldString",
},
{
ns: "Test.LteCSFieldString",
expected: "LteCSFieldString deve essere minore o uguale a Inner.LteCSFieldString",
},
{
ns: "Test.GtCSFieldString",
expected: "GtCSFieldString deve essere maggiore di Inner.GtCSFieldString",
},
{
ns: "Test.GteCSFieldString",
expected: "GteCSFieldString deve essere maggiore o uguale a Inner.GteCSFieldString",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString deve essere diverso da Inner.NeCSFieldString",
},
{
ns: "Test.EqCSFieldString",
expected: "EqCSFieldString deve essere uguale a Inner.EqCSFieldString",
},
{
ns: "Test.EqFieldString",
expected: "EqFieldString deve essere uguale a MaxString",
},
{
ns: "Test.GteString",
expected: "GteString deve essere lungo almeno 3 caratteri",
},
{
ns: "Test.GteNumber",
expected: "GteNumber deve essere maggiore o uguale a 5,56",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple deve contenere almeno 2 elementi",
},
{
ns: "Test.GteTime",
expected: "GteTime deve essere uguale o successivo alla Data/Ora corrente",
},
{
ns: "Test.GtString",
expected: "GtString deve essere lungo più di 3 caratteri",
},
{
ns: "Test.GtNumber",
expected: "GtNumber deve essere maggiore di 5,56",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple deve contenere più di 2 elementi",
},
{
ns: "Test.GtTime",
expected: "GtTime deve essere successivo alla Data/Ora corrente",
},
{
ns: "Test.LteString",
expected: "LteString deve essere lungo al massimo 3 caratteri",
},
{
ns: "Test.LteNumber",
expected: "LteNumber deve essere minore o uguale a 5,56",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple deve contenere al massimo 2 elementi",
},
{
ns: "Test.LteTime",
expected: "LteTime deve essere uguale o precedente alla Data/Ora corrente",
},
{
ns: "Test.LtString",
expected: "LtString deve essere lungo meno di 3 caratteri",
},
{
ns: "Test.LtNumber",
expected: "LtNumber deve essere minore di 5,56",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple deve contenere meno di 2 elementi",
},
{
ns: "Test.LtTime",
expected: "LtTime deve essere precedente alla Data/Ora corrente",
},
{
ns: "Test.NeString",
expected: "NeString deve essere diverso da ",
},
{
ns: "Test.NeNumber",
expected: "NeNumber deve essere diverso da 0.00",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple deve essere diverso da 0",
},
{
ns: "Test.EqString",
expected: "EqString non è uguale a 3",
},
{
ns: "Test.EqNumber",
expected: "EqNumber non è uguale a 2.33",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple non è uguale a 7",
},
{
ns: "Test.MaxString",
expected: "MaxString deve essere lungo al massimo 3 caratteri",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber deve essere minore o uguale a 1.113,00",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple deve contenere al massimo 7 elementi",
},
{
ns: "Test.MinString",
expected: "MinString deve essere lungo almeno 1 carattere",
},
{
ns: "Test.MinNumber",
expected: "MinNumber deve essere maggiore o uguale a 1.113,00",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple deve contenere almeno 7 elementi",
},
{
ns: "Test.LenString",
expected: "LenString deve essere lungo 1 carattere",
},
{
ns: "Test.LenNumber",
expected: "LenNumber deve essere uguale a 1.113,00",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple deve contenere 7 elementi",
},
{
ns: "Test.RequiredString",
expected: "RequiredString è un campo obbligatorio",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber è un campo obbligatorio",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple è un campo obbligatorio",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen deve essere lungo almeno 10 caratteri",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen deve essere lungo al massimo 1 carattere",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen deve essere lungo 2 caratteri",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt deve essere lungo meno di 1 carattere",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte deve essere lungo al massimo 1 carattere",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt deve essere lungo più di 10 caratteri",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte deve essere lungo almeno 10 caratteri",
},
{
ns: "Test.OneOfString",
expected: "OneOfString deve essere uno di [red green]",
},
{
ns: "Test.OneOfInt",
expected: "OneOfInt deve essere uno di [5 63]",
},
{
ns: "Test.UniqueSlice",
expected: "UniqueSlice deve contenere valori unici",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArray deve contenere valori unici",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMap deve contenere valori unici",
},
{
ns: "Test.BooleanString",
expected: "BooleanString deve rappresentare un valore booleano",
},
{
ns: "Test.JSONString",
expected: "JSONString deve essere una stringa json valida",
},
{
ns: "Test.JWTString",
expected: "JWTString deve essere una stringa jwt valida",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseString deve essere una stringa minuscola",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseString deve essere una stringa maiuscola",
},
{
ns: "Test.StartsWithString",
expected: "StartsWithString deve iniziare con foo",
},
{
ns: "Test.StartsNotWithString",
expected: "StartsNotWithString non deve iniziare con foo",
},
{
ns: "Test.EndsWithString",
expected: "EndsWithString deve terminare con foo",
},
{
ns: "Test.EndsNotWithString",
expected: "EndsNotWithString non deve terminare con foo",
},
{
ns: "Test.Datetime",
expected: "Datetime non corrisponde al formato 2006-01-02",
},
{
ns: "Test.PostCode",
expected: "PostCode non corrisponde al formato del codice postale dello stato SG",
},
{
ns: "Test.PostCodeByField",
expected: "PostCodeByField non corrisponde al formato del codice postale dello stato nel campo PostCodeCountry",
},
}
for _, tt := range tests {
var fe validator.FieldError
for _, e := range errs {
if tt.ns == e.Namespace() {
fe = e
break
}
}
NotEqual(t, fe, nil)
Equal(t, tt.expected, fe.Translate(trans))
}
}

@ -16,7 +16,6 @@ import (
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
// for all built in tag's in validator; you may add your own as desired. // 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) { func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error) {
translations := []struct { translations := []struct {
tag string tag string
translation string translation string
@ -29,10 +28,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は必須フィールドです", translation: "{0}は必須フィールドです",
override: false, override: false,
}, },
{
tag: "required_if",
translation: "{0}は必須フィールドです",
override: false,
},
{ {
tag: "len", tag: "len",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("len-string", "{0}の長さは{1}でなければなりません", false); err != nil { if err = ut.Add("len-string", "{0}の長さは{1}でなければなりません", false); err != nil {
return return
} }
@ -64,7 +67,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
@ -123,7 +125,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "min", tag: "min",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("min-string", "{0}の長さは少なくとも{1}はなければなりません", false); err != nil { if err = ut.Add("min-string", "{0}の長さは少なくとも{1}はなければなりません", false); err != nil {
return return
} }
@ -136,7 +137,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.Add("min-number", "{0}は{1}かより大きくなければなりません", false); err != nil { if err = ut.Add("min-number", "{0}は{1}以上でなければなりません", false); err != nil {
return return
} }
@ -155,7 +156,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
}, },
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
var err error var err error
var t string var t string
@ -214,7 +214,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "max", tag: "max",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("max-string", "{0}の長さは最大でも{1}でなければなりません", false); err != nil { if err = ut.Add("max-string", "{0}の長さは最大でも{1}でなければなりません", false); err != nil {
return return
} }
@ -227,7 +226,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.Add("max-number", "{0}は{1}かより小さくなければなりません", false); err != nil { if err = ut.Add("max-number", "{0}は{1}以下でなければなりません", false); err != nil {
return return
} }
@ -307,7 +306,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}と等しくありません", translation: "{0}は{1}と等しくありません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
fmt.Printf("warning: error translating FieldError: %#v", fe) fmt.Printf("warning: error translating FieldError: %#v", fe)
@ -391,7 +389,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "lt", tag: "lt",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("lt-string", "{0}の長さは{1}よりも少なくなければなりません", false); err != nil { if err = ut.Add("lt-string", "{0}の長さは{1}よりも少なくなければなりません", false); err != nil {
return return
} }
@ -512,7 +509,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "lte", tag: "lte",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("lte-string", "{0}の長さは最大でも{1}でなければなりません", false); err != nil { if err = ut.Add("lte-string", "{0}の長さは最大でも{1}でなければなりません", false); err != nil {
return return
} }
@ -525,7 +521,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.Add("lte-number", "{0}は{1}かより小さくなければなりません", false); err != nil { if err = ut.Add("lte-number", "{0}は{1}以下でなければなりません", false); err != nil {
return return
} }
@ -632,7 +628,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "gt", tag: "gt",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("gt-string", "{0}の長さは{1}よりも多くなければなりません", false); err != nil { if err = ut.Add("gt-string", "{0}の長さは{1}よりも多くなければなりません", false); err != nil {
return return
} }
@ -752,7 +747,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
{ {
tag: "gte", tag: "gte",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
if err = ut.Add("gte-string", "{0}の長さは少なくとも{1}以上はなければなりません", false); err != nil { if err = ut.Add("gte-string", "{0}の長さは少なくとも{1}以上はなければなりません", false); err != nil {
return return
} }
@ -765,7 +759,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.Add("gte-number", "{0}は{1}かより大きくなければなりません", false); err != nil { if err = ut.Add("gte-number", "{0}は{1}以上でなければなりません", false); err != nil {
return return
} }
@ -874,7 +868,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}と等しくなければなりません", translation: "{0}は{1}と等しくなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -889,7 +882,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}と等しくなければなりません", translation: "{0}は{1}と等しくなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -904,7 +896,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}とは異ならなければなりません", translation: "{0}は{1}とは異ならなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -919,7 +910,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}よりも大きくなければなりません", translation: "{0}は{1}よりも大きくなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -934,7 +924,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}以上でなければなりません", translation: "{0}は{1}以上でなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -949,7 +938,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}よりも小さくなければなりません", translation: "{0}は{1}よりも小さくなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -964,7 +952,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}以下でなければなりません", translation: "{0}は{1}以下でなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -979,7 +966,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}とは異ならなければなりません", translation: "{0}は{1}とは異ならなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -994,7 +980,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}よりも大きくなければなりません", translation: "{0}は{1}よりも大きくなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1009,7 +994,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}以上でなければなりません", translation: "{0}は{1}以上でなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1024,7 +1008,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}よりも小さくなければなりません", translation: "{0}は{1}よりも小さくなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1039,7 +1022,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は{1}以下でなければなりません", translation: "{0}は{1}以下でなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1124,7 +1106,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は'{1}'を含まなければなりません", translation: "{0}は'{1}'を含まなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1139,7 +1120,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は'{1}'の少なくとも1つを含まなければなりません", translation: "{0}は'{1}'の少なくとも1つを含まなければなりません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1154,7 +1134,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}には'{1}'というテキストを含むことはできません", translation: "{0}には'{1}'というテキストを含むことはできません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1169,7 +1148,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}には'{1}'のどれも含めることはできません", translation: "{0}には'{1}'のどれも含めることはできません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1184,7 +1162,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}には'{1}'を含めることはできません", translation: "{0}には'{1}'を含めることはできません",
override: false, override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string { customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param()) t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)
@ -1226,7 +1203,12 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
}, },
{ {
tag: "uuid5", tag: "uuid5",
translation: "{0}はバージョンが4の正しいUUIDでなければなりません", translation: "{0}はバージョンが5の正しいUUIDでなければなりません",
override: false,
},
{
tag: "ulid",
translation: "{0}は正しいULIDでなければなりません",
override: false, override: false,
}, },
{ {
@ -1349,6 +1331,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}は正しいMACアドレスを含まなければなりません", translation: "{0}は正しいMACアドレスを含まなければなりません",
override: false, override: false,
}, },
{
tag: "unique",
translation: "{0}は一意な値のみを含まなければなりません",
override: false,
},
{ {
tag: "iscolor", tag: "iscolor",
translation: "{0}は正しい色でなければなりません", translation: "{0}は正しい色でなければなりません",
@ -1367,22 +1354,83 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return s return s
}, },
}, },
{
tag: "json",
translation: "{0}は正しいJSON文字列でなければなりません",
override: false,
},
{
tag: "jwt",
translation: "{0}は正しいJWT文字列でなければなりません",
override: false,
},
{
tag: "lowercase",
translation: "{0}は小文字でなければなりません",
override: false,
},
{
tag: "uppercase",
translation: "{0}は大文字でなければなりません",
override: false,
},
{
tag: "datetime",
translation: "{0}は{1}の書式と一致しません",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{
tag: "postcode_iso3166_alpha2",
translation: "{0}は国名コード{1}の郵便番号形式と一致しません",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{
tag: "postcode_iso3166_alpha2_field",
translation: "{0}は{1}フィールドで指定された国名コードの郵便番号形式と一致しません",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{
tag: "boolean",
translation: "{0}は正しいブール値でなければなりません",
override: false,
},
} }
for _, t := range translations { for _, t := range translations {
if t.customTransFunc != nil && t.customRegisFunc != nil { if t.customTransFunc != nil && t.customRegisFunc != nil {
err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc) err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, t.customTransFunc)
} else if t.customTransFunc != nil && t.customRegisFunc == nil { } else if t.customTransFunc != nil && t.customRegisFunc == nil {
err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc) err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), t.customTransFunc)
} else if t.customTransFunc == nil && t.customRegisFunc != nil { } else if t.customTransFunc == nil && t.customRegisFunc != nil {
err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc) err = v.RegisterTranslation(t.tag, trans, t.customRegisFunc, translateFunc)
} else { } else {
err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc) err = v.RegisterTranslation(t.tag, trans, registrationFunc(t.tag, t.translation, t.override), translateFunc)
} }
@ -1396,9 +1444,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
} }
func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc { func registrationFunc(tag string, translation string, override bool) validator.RegisterTranslationsFunc {
return func(ut ut.Translator) (err error) { return func(ut ut.Translator) (err error) {
if err = ut.Add(tag, translation, override); err != nil { if err = ut.Add(tag, translation, override); err != nil {
return return
} }
@ -1410,7 +1456,6 @@ func registrationFunc(tag string, translation string, override bool) validator.R
} }
func translateFunc(ut ut.Translator, fe validator.FieldError) string { func translateFunc(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field()) t, err := ut.T(fe.Tag(), fe.Field())
if err != nil { if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe) log.Printf("warning: error translating FieldError: %#v", fe)

@ -4,14 +4,13 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
ja_locale "github.com/go-playground/locales/ja" ja_locale "github.com/go-playground/locales/ja"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
japanese := ja_locale.New() japanese := ja_locale.New()
uni := ut.New(japanese, japanese) uni := ut.New(japanese, japanese)
trans, _ := uni.GetTranslator("ja") trans, _ := uni.GetTranslator("ja")
@ -28,116 +27,131 @@ func TestTranslations(t *testing.T) {
GteCSFieldString string GteCSFieldString string
LtCSFieldString string LtCSFieldString string
LteCSFieldString string LteCSFieldString string
RequiredIf string
} }
type Test struct { type Test struct {
Inner Inner Inner Inner
RequiredString string `validate:"required"` RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"` RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"` RequiredMultiple []string `validate:"required"`
LenString string `validate:"len=1"` RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"`
LenNumber float64 `validate:"len=1113.00"` LenString string `validate:"len=1"`
LenMultiple []string `validate:"len=7"` LenNumber float64 `validate:"len=1113.00"`
MinString string `validate:"min=1"` LenMultiple []string `validate:"len=7"`
MinNumber float64 `validate:"min=1113.00"` MinString string `validate:"min=1"`
MinMultiple []string `validate:"min=7"` MinNumber float64 `validate:"min=1113.00"`
MaxString string `validate:"max=3"` MinMultiple []string `validate:"min=7"`
MaxNumber float64 `validate:"max=1113.00"` MaxString string `validate:"max=3"`
MaxMultiple []string `validate:"max=7"` MaxNumber float64 `validate:"max=1113.00"`
EqString string `validate:"eq=3"` MaxMultiple []string `validate:"max=7"`
EqNumber float64 `validate:"eq=2.33"` EqString string `validate:"eq=3"`
EqMultiple []string `validate:"eq=7"` EqNumber float64 `validate:"eq=2.33"`
NeString string `validate:"ne="` EqMultiple []string `validate:"eq=7"`
NeNumber float64 `validate:"ne=0.00"` NeString string `validate:"ne="`
NeMultiple []string `validate:"ne=0"` NeNumber float64 `validate:"ne=0.00"`
LtString string `validate:"lt=3"` NeMultiple []string `validate:"ne=0"`
LtNumber float64 `validate:"lt=5.56"` LtString string `validate:"lt=3"`
LtMultiple []string `validate:"lt=2"` LtNumber float64 `validate:"lt=5.56"`
LtTime time.Time `validate:"lt"` LtMultiple []string `validate:"lt=2"`
LteString string `validate:"lte=3"` LtTime time.Time `validate:"lt"`
LteNumber float64 `validate:"lte=5.56"` LteString string `validate:"lte=3"`
LteMultiple []string `validate:"lte=2"` LteNumber float64 `validate:"lte=5.56"`
LteTime time.Time `validate:"lte"` LteMultiple []string `validate:"lte=2"`
GtString string `validate:"gt=3"` LteTime time.Time `validate:"lte"`
GtNumber float64 `validate:"gt=5.56"` GtString string `validate:"gt=3"`
GtMultiple []string `validate:"gt=2"` GtNumber float64 `validate:"gt=5.56"`
GtTime time.Time `validate:"gt"` GtMultiple []string `validate:"gt=2"`
GteString string `validate:"gte=3"` GtTime time.Time `validate:"gt"`
GteNumber float64 `validate:"gte=5.56"` GteString string `validate:"gte=3"`
GteMultiple []string `validate:"gte=2"` GteNumber float64 `validate:"gte=5.56"`
GteTime time.Time `validate:"gte"` GteMultiple []string `validate:"gte=2"`
EqFieldString string `validate:"eqfield=MaxString"` GteTime time.Time `validate:"gte"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` EqFieldString string `validate:"eqfield=MaxString"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
NeFieldString string `validate:"nefield=EqFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
GtFieldString string `validate:"gtfield=MaxString"` NeFieldString string `validate:"nefield=EqFieldString"`
GteFieldString string `validate:"gtefield=MaxString"` GtFieldString string `validate:"gtfield=MaxString"`
LtFieldString string `validate:"ltfield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"`
LteFieldString string `validate:"ltefield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"`
AlphaString string `validate:"alpha"` LteFieldString string `validate:"ltefield=MaxString"`
AlphanumString string `validate:"alphanum"` AlphaString string `validate:"alpha"`
NumericString string `validate:"numeric"` AlphanumString string `validate:"alphanum"`
NumberString string `validate:"number"` NumericString string `validate:"numeric"`
HexadecimalString string `validate:"hexadecimal"` NumberString string `validate:"number"`
HexColorString string `validate:"hexcolor"` HexadecimalString string `validate:"hexadecimal"`
RGBColorString string `validate:"rgb"` HexColorString string `validate:"hexcolor"`
RGBAColorString string `validate:"rgba"` RGBColorString string `validate:"rgb"`
HSLColorString string `validate:"hsl"` RGBAColorString string `validate:"rgba"`
HSLAColorString string `validate:"hsla"` HSLColorString string `validate:"hsl"`
Email string `validate:"email"` HSLAColorString string `validate:"hsla"`
URL string `validate:"url"` Email string `validate:"email"`
URI string `validate:"uri"` URL string `validate:"url"`
Base64 string `validate:"base64"` URI string `validate:"uri"`
Contains string `validate:"contains=purpose"` Base64 string `validate:"base64"`
ContainsAny string `validate:"containsany=!@#$"` Contains string `validate:"contains=purpose"`
Excludes string `validate:"excludes=text"` ContainsAny string `validate:"containsany=!@#$"`
ExcludesAll string `validate:"excludesall=!@#$"` Excludes string `validate:"excludes=text"`
ExcludesRune string `validate:"excludesrune=☻"` ExcludesAll string `validate:"excludesall=!@#$"`
ISBN string `validate:"isbn"` ExcludesRune string `validate:"excludesrune=☻"`
ISBN10 string `validate:"isbn10"` ISBN string `validate:"isbn"`
ISBN13 string `validate:"isbn13"` ISBN10 string `validate:"isbn10"`
UUID string `validate:"uuid"` ISBN13 string `validate:"isbn13"`
UUID3 string `validate:"uuid3"` UUID string `validate:"uuid"`
UUID4 string `validate:"uuid4"` UUID3 string `validate:"uuid3"`
UUID5 string `validate:"uuid5"` UUID4 string `validate:"uuid4"`
ASCII string `validate:"ascii"` UUID5 string `validate:"uuid5"`
PrintableASCII string `validate:"printascii"` ULID string `validate:"ulid"`
MultiByte string `validate:"multibyte"` ASCII string `validate:"ascii"`
DataURI string `validate:"datauri"` PrintableASCII string `validate:"printascii"`
Latitude string `validate:"latitude"` MultiByte string `validate:"multibyte"`
Longitude string `validate:"longitude"` DataURI string `validate:"datauri"`
SSN string `validate:"ssn"` Latitude string `validate:"latitude"`
IP string `validate:"ip"` Longitude string `validate:"longitude"`
IPv4 string `validate:"ipv4"` SSN string `validate:"ssn"`
IPv6 string `validate:"ipv6"` IP string `validate:"ip"`
CIDR string `validate:"cidr"` IPv4 string `validate:"ipv4"`
CIDRv4 string `validate:"cidrv4"` IPv6 string `validate:"ipv6"`
CIDRv6 string `validate:"cidrv6"` CIDR string `validate:"cidr"`
TCPAddr string `validate:"tcp_addr"` CIDRv4 string `validate:"cidrv4"`
TCPAddrv4 string `validate:"tcp4_addr"` CIDRv6 string `validate:"cidrv6"`
TCPAddrv6 string `validate:"tcp6_addr"` TCPAddr string `validate:"tcp_addr"`
UDPAddr string `validate:"udp_addr"` TCPAddrv4 string `validate:"tcp4_addr"`
UDPAddrv4 string `validate:"udp4_addr"` TCPAddrv6 string `validate:"tcp6_addr"`
UDPAddrv6 string `validate:"udp6_addr"` UDPAddr string `validate:"udp_addr"`
IPAddr string `validate:"ip_addr"` UDPAddrv4 string `validate:"udp4_addr"`
IPAddrv4 string `validate:"ip4_addr"` UDPAddrv6 string `validate:"udp6_addr"`
IPAddrv6 string `validate:"ip6_addr"` IPAddr string `validate:"ip_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future IPAddrv4 string `validate:"ip4_addr"`
MAC string `validate:"mac"` IPAddrv6 string `validate:"ip6_addr"`
IsColor string `validate:"iscolor"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
StrPtrMinLen *string `validate:"min=10"` MAC string `validate:"mac"`
StrPtrMaxLen *string `validate:"max=1"` IsColor string `validate:"iscolor"`
StrPtrLen *string `validate:"len=2"` StrPtrMinLen *string `validate:"min=10"`
StrPtrLt *string `validate:"lt=1"` StrPtrMaxLen *string `validate:"max=1"`
StrPtrLte *string `validate:"lte=1"` StrPtrLen *string `validate:"len=2"`
StrPtrGt *string `validate:"gt=10"` StrPtrLt *string `validate:"lt=1"`
StrPtrGte *string `validate:"gte=10"` StrPtrLte *string `validate:"lte=1"`
OneOfString string `validate:"oneof=red green"` StrPtrGt *string `validate:"gt=10"`
OneOfInt int `validate:"oneof=5 63"` StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
JSONString string `validate:"json"`
JWTString string `validate:"jwt"`
LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"`
Datetime string `validate:"datetime=2006-01-02"`
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
BooleanString string `validate:"boolean"`
} }
var test Test var test Test
@ -180,10 +194,20 @@ func TestTranslations(t *testing.T) {
test.MultiByte = "1234feerf" test.MultiByte = "1234feerf"
test.LowercaseString = "ABCDEFG"
test.UppercaseString = "abcdefg"
s := "toolong" s := "toolong"
test.StrPtrMaxLen = &s test.StrPtrMaxLen = &s
test.StrPtrLen = &s test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
test.Datetime = "2008-Feb-01"
test.BooleanString = "A"
test.Inner.RequiredIf = "abcd"
err = validate.Struct(test) err = validate.Struct(test)
NotEqual(t, err, nil) NotEqual(t, err, nil)
@ -304,7 +328,11 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5はバージョンが4の正しいUUIDでなければなりません", expected: "UUID5はバージョンが5の正しいUUIDでなければなりません",
},
{
ns: "Test.ULID",
expected: "ULIDは正しいULIDでなければなりません",
}, },
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
@ -448,7 +476,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.GteNumber", ns: "Test.GteNumber",
expected: "GteNumberは5.56かより大きくなければなりません", expected: "GteNumberは5.56以上でなければなりません",
}, },
{ {
ns: "Test.GteMultiple", ns: "Test.GteMultiple",
@ -480,7 +508,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.LteNumber", ns: "Test.LteNumber",
expected: "LteNumberは5.56かより小さくなければなりません", expected: "LteNumberは5.56以下でなければなりません",
}, },
{ {
ns: "Test.LteMultiple", ns: "Test.LteMultiple",
@ -536,7 +564,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MaxNumber", ns: "Test.MaxNumber",
expected: "MaxNumberは1,113.00かより小さくなければなりません", expected: "MaxNumberは1,113.00以下でなければなりません",
}, },
{ {
ns: "Test.MaxMultiple", ns: "Test.MaxMultiple",
@ -548,7 +576,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MinNumber", ns: "Test.MinNumber",
expected: "MinNumberは1,113.00かより大きくなければなりません", expected: "MinNumberは1,113.00以上でなければなりません",
}, },
{ {
ns: "Test.MinMultiple", ns: "Test.MinMultiple",
@ -570,6 +598,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.RequiredString", ns: "Test.RequiredString",
expected: "RequiredStringは必須フィールドです", expected: "RequiredStringは必須フィールドです",
}, },
{
ns: "Test.RequiredIf",
expected: "RequiredIfは必須フィールドです",
},
{ {
ns: "Test.RequiredNumber", ns: "Test.RequiredNumber",
expected: "RequiredNumberは必須フィールドです", expected: "RequiredNumberは必須フィールドです",
@ -614,6 +646,50 @@ func TestTranslations(t *testing.T) {
ns: "Test.OneOfInt", ns: "Test.OneOfInt",
expected: "OneOfIntは[5 63]のうちのいずれかでなければなりません", expected: "OneOfIntは[5 63]のうちのいずれかでなければなりません",
}, },
{
ns: "Test.UniqueSlice",
expected: "UniqueSliceは一意な値のみを含まなければなりません",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArrayは一意な値のみを含まなければなりません",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMapは一意な値のみを含まなければなりません",
},
{
ns: "Test.JSONString",
expected: "JSONStringは正しいJSON文字列でなければなりません",
},
{
ns: "Test.JWTString",
expected: "JWTStringは正しいJWT文字列でなければなりません",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseStringは小文字でなければなりません",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseStringは大文字でなければなりません",
},
{
ns: "Test.Datetime",
expected: "Datetimeは2006-01-02の書式と一致しません",
},
{
ns: "Test.PostCode",
expected: "PostCodeは国名コードSGの郵便番号形式と一致しません",
},
{
ns: "Test.PostCodeByField",
expected: "PostCodeByFieldはPostCodeCountryフィールドで指定された国名コードの郵便番号形式と一致しません",
},
{
ns: "Test.BooleanString",
expected: "BooleanStringは正しいブール値でなければなりません",
},
} }
for _, tt := range tests { for _, tt := range tests {

File diff suppressed because it is too large Load Diff

@ -0,0 +1,709 @@
package lv
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
RequiredIf string
}
type Test struct {
Inner Inner
RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"`
RequiredIf string `validate:"required_if=Inner.RequiredIf abcd"`
LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"`
MinString string `validate:"min=1"`
MinNumber float64 `validate:"min=1113.00"`
MinMultiple []string `validate:"min=7"`
MaxString string `validate:"max=3"`
MaxNumber float64 `validate:"max=1113.00"`
MaxMultiple []string `validate:"max=7"`
EqString string `validate:"eq=3"`
EqNumber float64 `validate:"eq=2.33"`
EqMultiple []string `validate:"eq=7"`
NeString string `validate:"ne="`
NeNumber float64 `validate:"ne=0.00"`
NeMultiple []string `validate:"ne=0"`
LtString string `validate:"lt=3"`
LtNumber float64 `validate:"lt=5.56"`
LtMultiple []string `validate:"lt=2"`
LtTime time.Time `validate:"lt"`
LteString string `validate:"lte=3"`
LteNumber float64 `validate:"lte=5.56"`
LteMultiple []string `validate:"lte=2"`
LteTime time.Time `validate:"lte"`
GtString string `validate:"gt=3"`
GtNumber float64 `validate:"gt=5.56"`
GtMultiple []string `validate:"gt=2"`
GtTime time.Time `validate:"gt"`
GteString string `validate:"gte=3"`
GteNumber float64 `validate:"gte=5.56"`
GteMultiple []string `validate:"gte=2"`
GteTime time.Time `validate:"gte"`
EqFieldString string `validate:"eqfield=MaxString"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
NeFieldString string `validate:"nefield=EqFieldString"`
GtFieldString string `validate:"gtfield=MaxString"`
GteFieldString string `validate:"gtefield=MaxString"`
LtFieldString string `validate:"ltfield=MaxString"`
LteFieldString string `validate:"ltefield=MaxString"`
AlphaString string `validate:"alpha"`
AlphanumString string `validate:"alphanum"`
NumericString string `validate:"numeric"`
NumberString string `validate:"number"`
HexadecimalString string `validate:"hexadecimal"`
HexColorString string `validate:"hexcolor"`
RGBColorString string `validate:"rgb"`
RGBAColorString string `validate:"rgba"`
HSLColorString string `validate:"hsl"`
HSLAColorString string `validate:"hsla"`
Email string `validate:"email"`
URL string `validate:"url"`
URI string `validate:"uri"`
Base64 string `validate:"base64"`
Contains string `validate:"contains=purpose"`
ContainsAny string `validate:"containsany=!@#$"`
Excludes string `validate:"excludes=text"`
ExcludesAll string `validate:"excludesall=!@#$"`
ExcludesRune string `validate:"excludesrune=☻"`
ISBN string `validate:"isbn"`
ISBN10 string `validate:"isbn10"`
ISBN13 string `validate:"isbn13"`
UUID string `validate:"uuid"`
UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"`
DataURI string `validate:"datauri"`
Latitude string `validate:"latitude"`
Longitude string `validate:"longitude"`
SSN string `validate:"ssn"`
IP string `validate:"ip"`
IPv4 string `validate:"ipv4"`
IPv6 string `validate:"ipv6"`
CIDR string `validate:"cidr"`
CIDRv4 string `validate:"cidrv4"`
CIDRv6 string `validate:"cidrv6"`
TCPAddr string `validate:"tcp_addr"`
TCPAddrv4 string `validate:"tcp4_addr"`
TCPAddrv6 string `validate:"tcp6_addr"`
UDPAddr string `validate:"udp_addr"`
UDPAddrv4 string `validate:"udp4_addr"`
UDPAddrv6 string `validate:"udp6_addr"`
IPAddr string `validate:"ip_addr"`
IPAddrv4 string `validate:"ip4_addr"`
IPAddrv6 string `validate:"ip6_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
MAC string `validate:"mac"`
IsColor string `validate:"iscolor"`
StrPtrMinLen *string `validate:"min=10"`
StrPtrMaxLen *string `validate:"max=1"`
StrPtrLen *string `validate:"len=2"`
StrPtrLt *string `validate:"lt=1"`
StrPtrLte *string `validate:"lte=1"`
StrPtrGt *string `validate:"gt=10"`
StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
JSONString string `validate:"json"`
JWTString string `validate:"jwt"`
LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"`
Datetime string `validate:"datetime=2006-01-02"`
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
BooleanString string `validate:"boolean"`
}
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"
test.BooleanString = "A"
test.Inner.RequiredIf = "abcd"
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 jābūt derīgai krāsai",
},
{
ns: "Test.MAC",
expected: "MAC jābūt derīgai MAC adresei",
},
{
ns: "Test.IPAddr",
expected: "IPAddr jābūt atrisināmai IP adresei",
},
{
ns: "Test.IPAddrv4",
expected: "IPAddrv4 jābūt atrisināmai IPv4 adresei",
},
{
ns: "Test.IPAddrv6",
expected: "IPAddrv6 jābūt atrisināmai IPv6 adresei",
},
{
ns: "Test.UDPAddr",
expected: "UDPAddr jābūt derīgai UDP adresei",
},
{
ns: "Test.UDPAddrv4",
expected: "UDPAddrv4 jābūt derīgai IPv4 UDP adresei",
},
{
ns: "Test.UDPAddrv6",
expected: "UDPAddrv6 jābūt derīgai IPv6 UDP adresei",
},
{
ns: "Test.TCPAddr",
expected: "TCPAddr jābūt derīgai TCP adresei",
},
{
ns: "Test.TCPAddrv4",
expected: "TCPAddrv4 jābūt derīgai IPv4 TCP adresei",
},
{
ns: "Test.TCPAddrv6",
expected: "TCPAddrv6 jābūt derīgai IPv6 TCP adresei",
},
{
ns: "Test.CIDR",
expected: "CIDR jāsatur derīgu CIDR notāciju",
},
{
ns: "Test.CIDRv4",
expected: "CIDRv4 jāsatur derīgu CIDR notāciju IPv4 adresei",
},
{
ns: "Test.CIDRv6",
expected: "CIDRv6 jāsatur derīgu CIDR notāciju IPv6 adresei",
},
{
ns: "Test.SSN",
expected: "SSN jābūt derīgam SSN numuram",
},
{
ns: "Test.IP",
expected: "IP jābūt derīgai IP adresei",
},
{
ns: "Test.IPv4",
expected: "IPv4 jābūt derīgai IPv4 adresei",
},
{
ns: "Test.IPv6",
expected: "IPv6 jābūt derīgai IPv6 adresei",
},
{
ns: "Test.DataURI",
expected: "DataURI jāsatur derīgs Data URI",
},
{
ns: "Test.Latitude",
expected: "Latitude jāsatur derīgus platuma grādus",
},
{
ns: "Test.Longitude",
expected: "Longitude jāsatur derīgus garuma grādus",
},
{
ns: "Test.MultiByte",
expected: "MultiByte jāsatur multibyte rakstu zīmes",
},
{
ns: "Test.ASCII",
expected: "ASCII jāsatur tikai ascii rakstu zīmes",
},
{
ns: "Test.PrintableASCII",
expected: "PrintableASCII jāsatur tikai drukājamas ascii rakstu zīmes",
},
{
ns: "Test.UUID",
expected: "UUID jābūt derīgam UUID",
},
{
ns: "Test.UUID3",
expected: "UUID3 jābūt derīgam 3. versijas UUID",
},
{
ns: "Test.UUID4",
expected: "UUID4 jābūt derīgam 4. versijas UUID",
},
{
ns: "Test.UUID5",
expected: "UUID5 jābūt derīgam 5. versijas UUID",
},
{
ns: "Test.ULID",
expected: "ULID jābūt derīgam ULID",
},
{
ns: "Test.ISBN",
expected: "ISBN jābūt derīgam ISBN numuram",
},
{
ns: "Test.ISBN10",
expected: "ISBN10 jābūt derīgam ISBN-10 numuram",
},
{
ns: "Test.ISBN13",
expected: "ISBN13 jābūt derīgam ISBN-13 numuram",
},
{
ns: "Test.Excludes",
expected: "Excludes nedrīkst saturēt tekstu 'text'",
},
{
ns: "Test.ExcludesAll",
expected: "ExcludesAll nedrīkst saturēt nevienu no sekojošām rakstu zīmēm '!@#$'",
},
{
ns: "Test.ExcludesRune",
expected: "ExcludesRune nedrīkst saturēt sekojošo '☻'",
},
{
ns: "Test.ContainsAny",
expected: "ContainsAny jāsatur minimums 1 no rakstu zīmēm '!@#$'",
},
{
ns: "Test.Contains",
expected: "Contains jāsatur teksts 'purpose'",
},
{
ns: "Test.Base64",
expected: "Base64 jābūt derīgai Base64 virknei",
},
{
ns: "Test.Email",
expected: "Email jābūt derīgai e-pasta adresei",
},
{
ns: "Test.URL",
expected: "URL jābūt derīgam URL",
},
{
ns: "Test.URI",
expected: "URI jābūt derīgam URI",
},
{
ns: "Test.RGBColorString",
expected: "RGBColorString jābūt derīgai RGB krāsai",
},
{
ns: "Test.RGBAColorString",
expected: "RGBAColorString jābūt derīgai RGBA krāsai",
},
{
ns: "Test.HSLColorString",
expected: "HSLColorString jābūt derīgai HSL krāsai",
},
{
ns: "Test.HSLAColorString",
expected: "HSLAColorString jābūt derīgai HSLA krāsai",
},
{
ns: "Test.HexadecimalString",
expected: "HexadecimalString jābūt heksadecimālam skaitlim",
},
{
ns: "Test.HexColorString",
expected: "HexColorString jābūt derīgai HEX krāsai",
},
{
ns: "Test.NumberString",
expected: "NumberString jāsatur derīgs skaitlis",
},
{
ns: "Test.NumericString",
expected: "NumericString jāsatur tikai cipari",
},
{
ns: "Test.AlphanumString",
expected: "AlphanumString jāsatur tikai simboli no alfabēta vai cipari (Alphanumeric)",
},
{
ns: "Test.AlphaString",
expected: "AlphaString jāsatur tikai simboli no alfabēta",
},
{
ns: "Test.LtFieldString",
expected: "LtFieldString jābūt mazākam par MaxString",
},
{
ns: "Test.LteFieldString",
expected: "LteFieldString jābūt mazākam par MaxString vai vienādam",
},
{
ns: "Test.GtFieldString",
expected: "GtFieldString jābūt lielākam par MaxString",
},
{
ns: "Test.GteFieldString",
expected: "GteFieldString jābūt lielākam par MaxString vai vienādam",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString nedrīkst būt vienāds ar EqFieldString",
},
{
ns: "Test.LtCSFieldString",
expected: "LtCSFieldString jābūt mazākam par Inner.LtCSFieldString",
},
{
ns: "Test.LteCSFieldString",
expected: "LteCSFieldString jābūt mazākam par Inner.LteCSFieldString vai vienādam",
},
{
ns: "Test.GtCSFieldString",
expected: "GtCSFieldString jābūt lielākam par Inner.GtCSFieldString",
},
{
ns: "Test.GteCSFieldString",
expected: "GteCSFieldString jābūt lielākam par Inner.GteCSFieldString vai vienādam",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString nedrīkst būt vienāds ar Inner.NeCSFieldString",
},
{
ns: "Test.EqCSFieldString",
expected: "EqCSFieldString jābūt vienādam ar Inner.EqCSFieldString",
},
{
ns: "Test.EqFieldString",
expected: "EqFieldString jābūt vienādam ar MaxString",
},
{
ns: "Test.GteString",
expected: "GteString garumam jābūt minimums 3 rakstu zīmes",
},
{
ns: "Test.GteNumber",
expected: "GteNumber jābūt 5.56 vai lielākam",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple jāsatur minimums 2 elementi",
},
{
ns: "Test.GteTime",
expected: "GteTime jābūt lielākam par šī brīža Datumu un laiku vai vienādam",
},
{
ns: "Test.GtString",
expected: "GtString ir jābūt garākam par 3 rakstu zīmēm",
},
{
ns: "Test.GtNumber",
expected: "GtNumber jābūt lielākam par 5.56",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple jāsatur vairāk par 2 elementiem",
},
{
ns: "Test.GtTime",
expected: "GtTime jābūt lielākam par šī brīža Datumu un laiku",
},
{
ns: "Test.LteString",
expected: "LteString garumam jābūt maksimums 3 rakstu zīmes",
},
{
ns: "Test.LteNumber",
expected: "LteNumber jābūt 5.56 vai mazākam",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple jāsatur maksimums 2 elementi",
},
{
ns: "Test.LteTime",
expected: "LteTime jābūt mazākam par šī brīža Datumu un laiku vai vienādam",
},
{
ns: "Test.LtString",
expected: "LtString garumam jābūt mazākam par 3 rakstu zīmēm",
},
{
ns: "Test.LtNumber",
expected: "LtNumber jābūt mazākam par 5.56",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple jāsatur mazāk par 2 elementiem",
},
{
ns: "Test.LtTime",
expected: "LtTime jābūt mazākam par šī brīža Datumu un laiku",
},
{
ns: "Test.NeString",
expected: "NeString nedrīkst būt vienāds ar ",
},
{
ns: "Test.NeNumber",
expected: "NeNumber nedrīkst būt vienāds ar 0.00",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple nedrīkst būt vienāds ar 0",
},
{
ns: "Test.EqString",
expected: "EqString nav vienāds ar 3",
},
{
ns: "Test.EqNumber",
expected: "EqNumber nav vienāds ar 2.33",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple nav vienāds ar 7",
},
{
ns: "Test.MaxString",
expected: "MaxString vērtība pārsniedz maksimālo garumu 3 rakstu zīmes",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber vērtībai jābūt 1,113.00 vai mazākai",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple jāsatur maksimums 7 elementi",
},
{
ns: "Test.MinString",
expected: "MinString garumam jābūt minimums 1 rakstu zīme",
},
{
ns: "Test.MinNumber",
expected: "MinNumber vērtībai jābūt 1,113.00 vai lielākai",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple jāsatur minimums 7 elementi",
},
{
ns: "Test.LenString",
expected: "LenString garumam jābūt 1 rakstu zīme",
},
{
ns: "Test.LenNumber",
expected: "LenNumber vērtībai jābūt 1,113.00",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple vērtībai jāsatur 7 elementi",
},
{
ns: "Test.RequiredString",
expected: "RequiredString ir obligāts lauks",
},
{
ns: "Test.RequiredIf",
expected: "RequiredIf ir obligāts lauks",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber ir obligāts lauks",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple ir obligāts lauks",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen garumam jābūt minimums 10 rakstu zīmes",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen vērtība pārsniedz maksimālo garumu 1 rakstu zīme",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen garumam jābūt 2 rakstu zīmes",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt garumam jābūt mazākam par 1 rakstu zīmi",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte garumam jābūt maksimums 1 rakstu zīme",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt ir jābūt garākam par 10 rakstu zīmēm",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte garumam jābūt minimums 10 rakstu zīmes",
},
{
ns: "Test.OneOfString",
expected: "OneOfString jābūt vienam no [red green]",
},
{
ns: "Test.OneOfInt",
expected: "OneOfInt jābūt vienam no [5 63]",
},
{
ns: "Test.UniqueSlice",
expected: "UniqueSlice jāsatur unikālas vērtības",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArray jāsatur unikālas vērtības",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMap jāsatur unikālas vērtības",
},
{
ns: "Test.JSONString",
expected: "JSONString jābūt derīgai json virknei",
},
{
ns: "Test.JWTString",
expected: "JWTString jābūt derīgai jwt virknei",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseString jābūt mazo burtu virknei",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseString jābūt lielo burtu virknei",
},
{
ns: "Test.Datetime",
expected: "Datetime neatbilst formātam 2006-01-02",
},
{
ns: "Test.PostCode",
expected: "PostCode neatbilst pasta indeksa formātam valstī SG",
},
{
ns: "Test.PostCodeByField",
expected: "PostCodeByField neatbilst pasta indeksa formātam valstī, kura norādīta laukā PostCodeCountry",
},
{
ns: "Test.BooleanString",
expected: "BooleanString jābūt derīgai boolean vērtībai",
},
}
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))
}
}

@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} moet een geldige versie 5 UUID zijn", translation: "{0} moet een geldige versie 5 UUID zijn",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} moet een geldige ULID zijn",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} mag alleen ascii karakters bevatten", translation: "{0} mag alleen ascii karakters bevatten",

@ -4,9 +4,9 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
english "github.com/go-playground/locales/en" english "github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -306,6 +307,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 moet een geldige versie 5 UUID zijn", expected: "UUID5 moet een geldige versie 5 UUID zijn",
}, },
{
ns: "Test.ULID",
expected: "ULID moet een geldige ULID zijn",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN moet een geldig ISBN nummer zijn", expected: "ISBN moet een geldig ISBN nummer zijn",

@ -1178,6 +1178,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} deve ser um UUID versão 5 válido", translation: "{0} deve ser um UUID versão 5 válido",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} deve ser um ULID válido",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} deve conter apenas caracteres ascii", translation: "{0} deve conter apenas caracteres ascii",

@ -105,6 +105,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -321,6 +322,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 deve ser um UUID versão 5 válido", expected: "UUID5 deve ser um UUID versão 5 válido",
}, },
{
ns: "Test.ULID",
expected: "ULID deve ser um ULID válido",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN deve ser um número de ISBN válido", expected: "ISBN deve ser um número de ISBN válido",

@ -26,7 +26,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
}{ }{
{ {
tag: "required", tag: "required",
translation: "{0} é um campo requerido", translation: "{0} é um campo obrigatório",
override: false, override: false,
}, },
{ {
@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} deve ser um UUID versão 5 válido", translation: "{0} deve ser um UUID versão 5 válido",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} deve ser uma ULID válida",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} deve conter apenas caracteres ascii", translation: "{0} deve conter apenas caracteres ascii",
@ -1311,6 +1316,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return s return s
}, },
}, },
{
tag: "boolean",
translation: "{0} deve ser um valor booleano válido",
override: false,
},
{
tag: "cve",
translation: "{0} deve ser um identificador cve válido",
override: false,
},
} }
for _, t := range translations { for _, t := range translations {

@ -4,10 +4,10 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
brazilian_portuguese "github.com/go-playground/locales/pt_BR" brazilian_portuguese "github.com/go-playground/locales/pt_BR"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
. "github.com/go-playground/assert/v2"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -138,6 +139,8 @@ func TestTranslations(t *testing.T) {
StrPtrGte *string `validate:"gte=10"` StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"` OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"` OneOfInt int `validate:"oneof=5 63"`
BooleanString string `validate:"boolean"`
CveString string `validate:"cve"`
} }
var test Test var test Test
@ -170,6 +173,8 @@ func TestTranslations(t *testing.T) {
test.AlphanumString = "abc3!" test.AlphanumString = "abc3!"
test.NumericString = "12E.00" test.NumericString = "12E.00"
test.NumberString = "12E" test.NumberString = "12E"
test.BooleanString = "A"
test.CveString = "A"
test.Excludes = "este é um texto de teste" test.Excludes = "este é um texto de teste"
test.ExcludesAll = "Isso é Ótimo!" test.ExcludesAll = "Isso é Ótimo!"
@ -306,6 +311,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 deve ser um UUID versão 5 válido", expected: "UUID5 deve ser um UUID versão 5 válido",
}, },
{
ns: "Test.ULID",
expected: "ULID deve ser uma ULID válida",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN deve ser um número ISBN válido", expected: "ISBN deve ser um número ISBN válido",
@ -568,15 +577,15 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.RequiredString", ns: "Test.RequiredString",
expected: "RequiredString é um campo requerido", expected: "RequiredString é um campo obrigatório",
}, },
{ {
ns: "Test.RequiredNumber", ns: "Test.RequiredNumber",
expected: "RequiredNumber é um campo requerido", expected: "RequiredNumber é um campo obrigatório",
}, },
{ {
ns: "Test.RequiredMultiple", ns: "Test.RequiredMultiple",
expected: "RequiredMultiple é um campo requerido", expected: "RequiredMultiple é um campo obrigatório",
}, },
{ {
ns: "Test.StrPtrMinLen", ns: "Test.StrPtrMinLen",
@ -614,6 +623,14 @@ func TestTranslations(t *testing.T) {
ns: "Test.OneOfInt", ns: "Test.OneOfInt",
expected: "OneOfInt deve ser um de [5 63]", expected: "OneOfInt deve ser um de [5 63]",
}, },
{
ns: "Test.BooleanString",
expected: "BooleanString deve ser um valor booleano válido",
},
{
ns: "Test.CveString",
expected: "CveString deve ser um identificador cve válido",
},
} }
for _, tt := range tests { for _, tt := range tests {

@ -41,6 +41,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("len-string-character", "{0} символа", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("len-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("len-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("len-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -52,10 +60,19 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
if err = ut.Add("len-items", "{0} должен содержать {1}", false); err != nil { if err = ut.Add("len-items", "{0} должен содержать {1}", false); err != nil {
return return
} }
if err = ut.AddCardinal("len-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil { if err = ut.AddCardinal("len-items-item", "{0} элемент", locales.PluralRuleOne, false); err != nil {
return return
} }
if err = ut.AddCardinal("len-items-item", "{0} элемента", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("len-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("len-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("len-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -132,6 +149,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("min-string-character", "{0} символа", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("min-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("min-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("min-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -147,6 +172,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("min-items-item", "{0} элемента", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("min-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("min-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("min-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -223,6 +256,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("max-string-character", "{0} символа", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("max-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("max-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("max-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -238,6 +279,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("max-items-item", "{0} элемента", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("max-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("max-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("max-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -344,6 +393,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("lt-string-character", "{0} символов", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("lt-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("lt-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("lt-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -360,6 +417,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("lt-items-item", "{0} элементов", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("lt-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("lt-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("lt-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -465,6 +530,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("lte-string-character", "{0} символа", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("lte-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("lte-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("lte-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -481,6 +554,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("lte-items-item", "{0} элемента", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("lte-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("lte-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("lte-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -585,6 +666,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("gt-string-character", "{0} символов", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("gt-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("gt-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("gt-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -601,6 +690,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("gt-items-item", "{0} элементов", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("gt-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("gt-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("gt-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -705,6 +802,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("gte-string-character", "{0} символа", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("gte-string-character", "{0} символов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("gte-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("gte-string-character", "{0} символы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -721,6 +826,14 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return return
} }
if err = ut.AddCardinal("gte-items-item", "{0} элемента", locales.PluralRuleFew, false); err != nil {
return
}
if err = ut.AddCardinal("gte-items-item", "{0} элементов", locales.PluralRuleMany, false); err != nil {
return
}
if err = ut.AddCardinal("gte-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil { if err = ut.AddCardinal("gte-items-item", "{0} элементы", locales.PluralRuleOther, false); err != nil {
return return
} }
@ -1178,6 +1291,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} должен быть UUID 5 версии", translation: "{0} должен быть UUID 5 версии",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} должен быть ULID",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} должен содержать только ascii символы", translation: "{0} должен содержать только ascii символы",

@ -7,7 +7,7 @@ import (
"time" "time"
. "github.com/go-playground/assert/v2" . "github.com/go-playground/assert/v2"
russian "github.com/go-playground/locales/en" russian "github.com/go-playground/locales/ru"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
@ -33,116 +33,137 @@ func TestTranslations(t *testing.T) {
} }
type Test struct { type Test struct {
Inner Inner Inner Inner
RequiredString string `validate:"required"` RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"` RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"` RequiredMultiple []string `validate:"required"`
LenString string `validate:"len=1"` LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"` LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"` LenMultiple []string `validate:"len=7"`
MinString string `validate:"min=1"` LenMultipleSecond []string `validate:"len=2"`
MinNumber float64 `validate:"min=1113.00"` MinString string `validate:"min=1"`
MinMultiple []string `validate:"min=7"` MinStringMultiple string `validate:"min=2"`
MaxString string `validate:"max=3"` MinStringMultipleSecond string `validate:"min=7"`
MaxNumber float64 `validate:"max=1113.00"` MinNumber float64 `validate:"min=1113.00"`
MaxMultiple []string `validate:"max=7"` MinMultiple []string `validate:"min=7"`
EqString string `validate:"eq=3"` MinMultipleSecond []string `validate:"min=2"`
EqNumber float64 `validate:"eq=2.33"` MaxString string `validate:"max=3"`
EqMultiple []string `validate:"eq=7"` MaxStringSecond string `validate:"max=7"`
NeString string `validate:"ne="` MaxNumber float64 `validate:"max=1113.00"`
NeNumber float64 `validate:"ne=0.00"` MaxMultiple []string `validate:"max=7"`
NeMultiple []string `validate:"ne=0"` MaxMultipleSecond []string `validate:"max=2"`
LtString string `validate:"lt=3"` EqString string `validate:"eq=3"`
LtNumber float64 `validate:"lt=5.56"` EqNumber float64 `validate:"eq=2.33"`
LtMultiple []string `validate:"lt=2"` EqMultiple []string `validate:"eq=7"`
LtTime time.Time `validate:"lt"` NeString string `validate:"ne="`
LteString string `validate:"lte=3"` NeNumber float64 `validate:"ne=0.00"`
LteNumber float64 `validate:"lte=5.56"` NeMultiple []string `validate:"ne=0"`
LteMultiple []string `validate:"lte=2"` LtString string `validate:"lt=3"`
LteTime time.Time `validate:"lte"` LtStringSecond string `validate:"lt=7"`
GtString string `validate:"gt=3"` LtNumber float64 `validate:"lt=5.56"`
GtNumber float64 `validate:"gt=5.56"` LtMultiple []string `validate:"lt=2"`
GtMultiple []string `validate:"gt=2"` LtMultipleSecond []string `validate:"lt=7"`
GtTime time.Time `validate:"gt"` LtTime time.Time `validate:"lt"`
GteString string `validate:"gte=3"` LteString string `validate:"lte=3"`
GteNumber float64 `validate:"gte=5.56"` LteStringSecond string `validate:"lte=7"`
GteMultiple []string `validate:"gte=2"` LteNumber float64 `validate:"lte=5.56"`
GteTime time.Time `validate:"gte"` LteMultiple []string `validate:"lte=2"`
EqFieldString string `validate:"eqfield=MaxString"` LteMultipleSecond []string `validate:"lte=7"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` LteTime time.Time `validate:"lte"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` GtString string `validate:"gt=3"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GtStringSecond string `validate:"gt=7"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` GtNumber float64 `validate:"gt=5.56"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` GtMultiple []string `validate:"gt=2"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` GtMultipleSecond []string `validate:"gt=7"`
NeFieldString string `validate:"nefield=EqFieldString"` GtTime time.Time `validate:"gt"`
GtFieldString string `validate:"gtfield=MaxString"` GteString string `validate:"gte=3"`
GteFieldString string `validate:"gtefield=MaxString"` GteStringSecond string `validate:"gte=7"`
LtFieldString string `validate:"ltfield=MaxString"` GteNumber float64 `validate:"gte=5.56"`
LteFieldString string `validate:"ltefield=MaxString"` GteMultiple []string `validate:"gte=2"`
AlphaString string `validate:"alpha"` GteMultipleSecond []string `validate:"gte=7"`
AlphanumString string `validate:"alphanum"` GteTime time.Time `validate:"gte"`
NumericString string `validate:"numeric"` EqFieldString string `validate:"eqfield=MaxString"`
NumberString string `validate:"number"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
HexadecimalString string `validate:"hexadecimal"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
HexColorString string `validate:"hexcolor"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
RGBColorString string `validate:"rgb"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
RGBAColorString string `validate:"rgba"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
HSLColorString string `validate:"hsl"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
HSLAColorString string `validate:"hsla"` NeFieldString string `validate:"nefield=EqFieldString"`
Email string `validate:"email"` GtFieldString string `validate:"gtfield=MaxString"`
URL string `validate:"url"` GteFieldString string `validate:"gtefield=MaxString"`
URI string `validate:"uri"` LtFieldString string `validate:"ltfield=MaxString"`
Base64 string `validate:"base64"` LteFieldString string `validate:"ltefield=MaxString"`
Contains string `validate:"contains=purpose"` AlphaString string `validate:"alpha"`
ContainsAny string `validate:"containsany=!@#$"` AlphanumString string `validate:"alphanum"`
Excludes string `validate:"excludes=text"` NumericString string `validate:"numeric"`
ExcludesAll string `validate:"excludesall=!@#$"` NumberString string `validate:"number"`
ExcludesRune string `validate:"excludesrune=☻"` HexadecimalString string `validate:"hexadecimal"`
ISBN string `validate:"isbn"` HexColorString string `validate:"hexcolor"`
ISBN10 string `validate:"isbn10"` RGBColorString string `validate:"rgb"`
ISBN13 string `validate:"isbn13"` RGBAColorString string `validate:"rgba"`
UUID string `validate:"uuid"` HSLColorString string `validate:"hsl"`
UUID3 string `validate:"uuid3"` HSLAColorString string `validate:"hsla"`
UUID4 string `validate:"uuid4"` Email string `validate:"email"`
UUID5 string `validate:"uuid5"` URL string `validate:"url"`
ASCII string `validate:"ascii"` URI string `validate:"uri"`
PrintableASCII string `validate:"printascii"` Base64 string `validate:"base64"`
MultiByte string `validate:"multibyte"` Contains string `validate:"contains=purpose"`
DataURI string `validate:"datauri"` ContainsAny string `validate:"containsany=!@#$"`
Latitude string `validate:"latitude"` Excludes string `validate:"excludes=text"`
Longitude string `validate:"longitude"` ExcludesAll string `validate:"excludesall=!@#$"`
SSN string `validate:"ssn"` ExcludesRune string `validate:"excludesrune=☻"`
IP string `validate:"ip"` ISBN string `validate:"isbn"`
IPv4 string `validate:"ipv4"` ISBN10 string `validate:"isbn10"`
IPv6 string `validate:"ipv6"` ISBN13 string `validate:"isbn13"`
CIDR string `validate:"cidr"` UUID string `validate:"uuid"`
CIDRv4 string `validate:"cidrv4"` UUID3 string `validate:"uuid3"`
CIDRv6 string `validate:"cidrv6"` UUID4 string `validate:"uuid4"`
TCPAddr string `validate:"tcp_addr"` UUID5 string `validate:"uuid5"`
TCPAddrv4 string `validate:"tcp4_addr"` ULID string `validate:"ulid"`
TCPAddrv6 string `validate:"tcp6_addr"` ASCII string `validate:"ascii"`
UDPAddr string `validate:"udp_addr"` PrintableASCII string `validate:"printascii"`
UDPAddrv4 string `validate:"udp4_addr"` MultiByte string `validate:"multibyte"`
UDPAddrv6 string `validate:"udp6_addr"` DataURI string `validate:"datauri"`
IPAddr string `validate:"ip_addr"` Latitude string `validate:"latitude"`
IPAddrv4 string `validate:"ip4_addr"` Longitude string `validate:"longitude"`
IPAddrv6 string `validate:"ip6_addr"` SSN string `validate:"ssn"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future IP string `validate:"ip"`
MAC string `validate:"mac"` IPv4 string `validate:"ipv4"`
IsColor string `validate:"iscolor"` IPv6 string `validate:"ipv6"`
StrPtrMinLen *string `validate:"min=10"` CIDR string `validate:"cidr"`
StrPtrMaxLen *string `validate:"max=1"` CIDRv4 string `validate:"cidrv4"`
StrPtrLen *string `validate:"len=2"` CIDRv6 string `validate:"cidrv6"`
StrPtrLt *string `validate:"lt=1"` TCPAddr string `validate:"tcp_addr"`
StrPtrLte *string `validate:"lte=1"` TCPAddrv4 string `validate:"tcp4_addr"`
StrPtrGt *string `validate:"gt=10"` TCPAddrv6 string `validate:"tcp6_addr"`
StrPtrGte *string `validate:"gte=10"` UDPAddr string `validate:"udp_addr"`
OneOfString string `validate:"oneof=red green"` UDPAddrv4 string `validate:"udp4_addr"`
OneOfInt int `validate:"oneof=5 63"` UDPAddrv6 string `validate:"udp6_addr"`
UniqueSlice []string `validate:"unique"` IPAddr string `validate:"ip_addr"`
UniqueArray [3]string `validate:"unique"` IPAddrv4 string `validate:"ip4_addr"`
UniqueMap map[string]string `validate:"unique"` 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"`
StrPtrMinLenSecond *string `validate:"min=2"`
StrPtrMaxLen *string `validate:"max=1"`
StrPtrLen *string `validate:"len=2"`
StrPtrLenSecond *string `validate:"len=7"`
StrPtrLt *string `validate:"lt=1"`
StrPtrLte *string `validate:"lte=1"`
StrPtrLteMultiple *string `validate:"lte=2"`
StrPtrLteMultipleSecond *string `validate:"lte=7"`
StrPtrGt *string `validate:"gt=10"`
StrPtrGte *string `validate:"gte=10"`
StrPtrGtSecond *string `validate:"gt=2"`
StrPtrGteSecond *string `validate:"gte=2"`
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"`
} }
var test Test var test Test
@ -152,17 +173,23 @@ func TestTranslations(t *testing.T) {
test.Inner.GteCSFieldString = "1234" test.Inner.GteCSFieldString = "1234"
test.MaxString = "1234" test.MaxString = "1234"
test.MaxStringSecond = "12345678"
test.MaxNumber = 2000 test.MaxNumber = 2000
test.MaxMultiple = make([]string, 9) test.MaxMultiple = make([]string, 9)
test.MaxMultipleSecond = make([]string, 3)
test.LtString = "1234" test.LtString = "1234"
test.LtStringSecond = "12345678"
test.LtNumber = 6 test.LtNumber = 6
test.LtMultiple = make([]string, 3) test.LtMultiple = make([]string, 3)
test.LtMultipleSecond = make([]string, 8)
test.LtTime = time.Now().Add(time.Hour * 24) test.LtTime = time.Now().Add(time.Hour * 24)
test.LteString = "1234" test.LteString = "1234"
test.LteStringSecond = "12345678"
test.LteNumber = 6 test.LteNumber = 6
test.LteMultiple = make([]string, 3) test.LteMultiple = make([]string, 3)
test.LteMultipleSecond = make([]string, 8)
test.LteTime = time.Now().Add(time.Hour * 24) test.LteTime = time.Now().Add(time.Hour * 24)
test.LtFieldString = "12345" test.LtFieldString = "12345"
@ -314,6 +341,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 должен быть UUID 5 версии", expected: "UUID5 должен быть UUID 5 версии",
}, },
{
ns: "Test.ULID",
expected: "ULID должен быть ULID",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN должен быть ISBN номером", expected: "ISBN должен быть ISBN номером",
@ -452,15 +483,23 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.GteString", ns: "Test.GteString",
expected: "GteString должен содержать минимум 3 символы", expected: "GteString должен содержать минимум 3 символа",
},
{
ns: "Test.GteStringSecond",
expected: "GteStringSecond должен содержать минимум 7 символов",
}, },
{ {
ns: "Test.GteNumber", ns: "Test.GteNumber",
expected: "GteNumber должен быть больше или равно 5.56", expected: "GteNumber должен быть больше или равно 5,56",
}, },
{ {
ns: "Test.GteMultiple", ns: "Test.GteMultiple",
expected: "GteMultiple должен содержать минимум 2 элементы", expected: "GteMultiple должен содержать минимум 2 элемента",
},
{
ns: "Test.GteMultipleSecond",
expected: "GteMultipleSecond должен содержать минимум 7 элементов",
}, },
{ {
ns: "Test.GteTime", ns: "Test.GteTime",
@ -468,15 +507,23 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.GtString", ns: "Test.GtString",
expected: "GtString должен быть длиннее 3 символы", expected: "GtString должен быть длиннее 3 символов",
},
{
ns: "Test.GtStringSecond",
expected: "GtStringSecond должен быть длиннее 7 символов",
}, },
{ {
ns: "Test.GtNumber", ns: "Test.GtNumber",
expected: "GtNumber должен быть больше 5.56", expected: "GtNumber должен быть больше 5,56",
}, },
{ {
ns: "Test.GtMultiple", ns: "Test.GtMultiple",
expected: "GtMultiple должен содержать более 2 элементы", expected: "GtMultiple должен содержать более 2 элементов",
},
{
ns: "Test.GtMultipleSecond",
expected: "GtMultipleSecond должен содержать более 7 элементов",
}, },
{ {
ns: "Test.GtTime", ns: "Test.GtTime",
@ -484,15 +531,23 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.LteString", ns: "Test.LteString",
expected: "LteString должен содержать максимум 3 символы", expected: "LteString должен содержать максимум 3 символа",
},
{
ns: "Test.LteStringSecond",
expected: "LteStringSecond должен содержать максимум 7 символов",
}, },
{ {
ns: "Test.LteNumber", ns: "Test.LteNumber",
expected: "LteNumber должен быть менее или равен 5.56", expected: "LteNumber должен быть менее или равен 5,56",
}, },
{ {
ns: "Test.LteMultiple", ns: "Test.LteMultiple",
expected: "LteMultiple должен содержать максимум 2 элементы", expected: "LteMultiple должен содержать максимум 2 элемента",
},
{
ns: "Test.LteMultipleSecond",
expected: "LteMultipleSecond должен содержать максимум 7 элементов",
}, },
{ {
ns: "Test.LteTime", ns: "Test.LteTime",
@ -500,15 +555,23 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.LtString", ns: "Test.LtString",
expected: "LtString должен иметь менее 3 символы", expected: "LtString должен иметь менее 3 символов",
},
{
ns: "Test.LtStringSecond",
expected: "LtStringSecond должен иметь менее 7 символов",
}, },
{ {
ns: "Test.LtNumber", ns: "Test.LtNumber",
expected: "LtNumber должен быть менее 5.56", expected: "LtNumber должен быть менее 5,56",
}, },
{ {
ns: "Test.LtMultiple", ns: "Test.LtMultiple",
expected: "LtMultiple должен содержать менее 2 элементы", expected: "LtMultiple должен содержать менее 2 элементов",
},
{
ns: "Test.LtMultipleSecond",
expected: "LtMultipleSecond должен содержать менее 7 элементов",
}, },
{ {
ns: "Test.LtTime", ns: "Test.LtTime",
@ -540,27 +603,47 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MaxString", ns: "Test.MaxString",
expected: "MaxString должен содержать максимум 3 символы", expected: "MaxString должен содержать максимум 3 символа",
},
{
ns: "Test.MaxStringSecond",
expected: "MaxStringSecond должен содержать максимум 7 символов",
}, },
{ {
ns: "Test.MaxNumber", ns: "Test.MaxNumber",
expected: "MaxNumber должен быть меньше или равно 1,113.00", expected: "MaxNumber должен быть меньше или равно 1 113,00",
}, },
{ {
ns: "Test.MaxMultiple", ns: "Test.MaxMultiple",
expected: "MaxMultiple должен содержать максимум 7 элементы", expected: "MaxMultiple должен содержать максимум 7 элементов",
},
{
ns: "Test.MaxMultipleSecond",
expected: "MaxMultipleSecond должен содержать максимум 2 элемента",
}, },
{ {
ns: "Test.MinString", ns: "Test.MinString",
expected: "MinString должен содержать минимум 1 символ", expected: "MinString должен содержать минимум 1 символ",
}, },
{
ns: "Test.MinStringMultiple",
expected: "MinStringMultiple должен содержать минимум 2 символа",
},
{
ns: "Test.MinStringMultipleSecond",
expected: "MinStringMultipleSecond должен содержать минимум 7 символов",
},
{ {
ns: "Test.MinNumber", ns: "Test.MinNumber",
expected: "MinNumber должен быть больше или равно 1,113.00", expected: "MinNumber должен быть больше или равно 1 113,00",
}, },
{ {
ns: "Test.MinMultiple", ns: "Test.MinMultiple",
expected: "MinMultiple должен содержать минимум 7 элементы", expected: "MinMultiple должен содержать минимум 7 элементов",
},
{
ns: "Test.MinMultipleSecond",
expected: "MinMultipleSecond должен содержать минимум 2 элемента",
}, },
{ {
ns: "Test.LenString", ns: "Test.LenString",
@ -568,11 +651,15 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.LenNumber", ns: "Test.LenNumber",
expected: "LenNumber должен быть равен 1,113.00", expected: "LenNumber должен быть равен 1 113,00",
}, },
{ {
ns: "Test.LenMultiple", ns: "Test.LenMultiple",
expected: "LenMultiple должен содержать 7 элементы", expected: "LenMultiple должен содержать 7 элементов",
},
{
ns: "Test.LenMultipleSecond",
expected: "LenMultipleSecond должен содержать 2 элемента",
}, },
{ {
ns: "Test.RequiredString", ns: "Test.RequiredString",
@ -588,7 +675,11 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.StrPtrMinLen", ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen должен содержать минимум 10 символы", expected: "StrPtrMinLen должен содержать минимум 10 символов",
},
{
ns: "Test.StrPtrMinLenSecond",
expected: "StrPtrMinLenSecond должен содержать минимум 2 символа",
}, },
{ {
ns: "Test.StrPtrMaxLen", ns: "Test.StrPtrMaxLen",
@ -596,7 +687,11 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.StrPtrLen", ns: "Test.StrPtrLen",
expected: "StrPtrLen должен быть длиной в 2 символы", expected: "StrPtrLen должен быть длиной в 2 символа",
},
{
ns: "Test.StrPtrLenSecond",
expected: "StrPtrLenSecond должен быть длиной в 7 символов",
}, },
{ {
ns: "Test.StrPtrLt", ns: "Test.StrPtrLt",
@ -606,13 +701,29 @@ func TestTranslations(t *testing.T) {
ns: "Test.StrPtrLte", ns: "Test.StrPtrLte",
expected: "StrPtrLte должен содержать максимум 1 символ", expected: "StrPtrLte должен содержать максимум 1 символ",
}, },
{
ns: "Test.StrPtrLteMultiple",
expected: "StrPtrLteMultiple должен содержать максимум 2 символа",
},
{
ns: "Test.StrPtrLteMultipleSecond",
expected: "StrPtrLteMultipleSecond должен содержать максимум 7 символов",
},
{ {
ns: "Test.StrPtrGt", ns: "Test.StrPtrGt",
expected: "StrPtrGt должен быть длиннее 10 символы", expected: "StrPtrGt должен быть длиннее 10 символов",
},
{
ns: "Test.StrPtrGtSecond",
expected: "StrPtrGtSecond должен быть длиннее 2 символов",
}, },
{ {
ns: "Test.StrPtrGte", ns: "Test.StrPtrGte",
expected: "StrPtrGte должен содержать минимум 10 символы", expected: "StrPtrGte должен содержать минимум 10 символов",
},
{
ns: "Test.StrPtrGteSecond",
expected: "StrPtrGteSecond должен содержать минимум 2 символа",
}, },
{ {
ns: "Test.OneOfString", ns: "Test.OneOfString",

@ -1173,6 +1173,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} geçerli bir sürüm 5 UUID olmalıdır", translation: "{0} geçerli bir sürüm 5 UUID olmalıdır",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0} geçerli bir ULID olmalıdır",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0} yalnızca ascii karakterler içermelidir", translation: "{0} yalnızca ascii karakterler içermelidir",

@ -4,9 +4,9 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
turkish "github.com/go-playground/locales/tr" turkish "github.com/go-playground/locales/tr"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
) )
@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -312,6 +313,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5 geçerli bir sürüm 5 UUID olmalıdır", expected: "UUID5 geçerli bir sürüm 5 UUID olmalıdır",
}, },
{
ns: "Test.ULID",
expected: "ULID geçerli bir ULID olmalıdır",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN geçerli bir ISBN numarası olmalıdır", expected: "ISBN geçerli bir ISBN numarası olmalıdır",

File diff suppressed because it is too large Load Diff

@ -0,0 +1,690 @@
package vi
import (
"testing"
"time"
. "github.com/go-playground/assert/v2"
vietnamese "github.com/go-playground/locales/vi"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
vie := vietnamese.New()
uni := ut.New(vie, vie)
trans, _ := uni.GetTranslator("vi")
validate := validator.New()
err := RegisterDefaultTranslations(validate, trans)
Equal(t, err, nil)
type Inner struct {
EqCSFieldString string
NeCSFieldString string
GtCSFieldString string
GteCSFieldString string
LtCSFieldString string
LteCSFieldString string
}
type Test struct {
Inner Inner
RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"`
LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"`
MinString string `validate:"min=1"`
MinNumber float64 `validate:"min=1113.00"`
MinMultiple []string `validate:"min=7"`
MaxString string `validate:"max=3"`
MaxNumber float64 `validate:"max=1113.00"`
MaxMultiple []string `validate:"max=7"`
EqString string `validate:"eq=3"`
EqNumber float64 `validate:"eq=2.33"`
EqMultiple []string `validate:"eq=7"`
NeString string `validate:"ne="`
NeNumber float64 `validate:"ne=0.00"`
NeMultiple []string `validate:"ne=0"`
LtString string `validate:"lt=3"`
LtNumber float64 `validate:"lt=5.56"`
LtMultiple []string `validate:"lt=2"`
LtTime time.Time `validate:"lt"`
LteString string `validate:"lte=3"`
LteNumber float64 `validate:"lte=5.56"`
LteMultiple []string `validate:"lte=2"`
LteTime time.Time `validate:"lte"`
GtString string `validate:"gt=3"`
GtNumber float64 `validate:"gt=5.56"`
GtMultiple []string `validate:"gt=2"`
GtTime time.Time `validate:"gt"`
GteString string `validate:"gte=3"`
GteNumber float64 `validate:"gte=5.56"`
GteMultiple []string `validate:"gte=2"`
GteTime time.Time `validate:"gte"`
EqFieldString string `validate:"eqfield=MaxString"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
NeFieldString string `validate:"nefield=EqFieldString"`
GtFieldString string `validate:"gtfield=MaxString"`
GteFieldString string `validate:"gtefield=MaxString"`
LtFieldString string `validate:"ltfield=MaxString"`
LteFieldString string `validate:"ltefield=MaxString"`
AlphaString string `validate:"alpha"`
AlphanumString string `validate:"alphanum"`
NumericString string `validate:"numeric"`
NumberString string `validate:"number"`
HexadecimalString string `validate:"hexadecimal"`
HexColorString string `validate:"hexcolor"`
RGBColorString string `validate:"rgb"`
RGBAColorString string `validate:"rgba"`
HSLColorString string `validate:"hsl"`
HSLAColorString string `validate:"hsla"`
Email string `validate:"email"`
URL string `validate:"url"`
URI string `validate:"uri"`
Base64 string `validate:"base64"`
Contains string `validate:"contains=purpose"`
ContainsAny string `validate:"containsany=!@#$"`
Excludes string `validate:"excludes=text"`
ExcludesAll string `validate:"excludesall=!@#$"`
ExcludesRune string `validate:"excludesrune=☻"`
ISBN string `validate:"isbn"`
ISBN10 string `validate:"isbn10"`
ISBN13 string `validate:"isbn13"`
UUID string `validate:"uuid"`
UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"`
ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"`
DataURI string `validate:"datauri"`
Latitude string `validate:"latitude"`
Longitude string `validate:"longitude"`
SSN string `validate:"ssn"`
IP string `validate:"ip"`
IPv4 string `validate:"ipv4"`
IPv6 string `validate:"ipv6"`
CIDR string `validate:"cidr"`
CIDRv4 string `validate:"cidrv4"`
CIDRv6 string `validate:"cidrv6"`
TCPAddr string `validate:"tcp_addr"`
TCPAddrv4 string `validate:"tcp4_addr"`
TCPAddrv6 string `validate:"tcp6_addr"`
UDPAddr string `validate:"udp_addr"`
UDPAddrv4 string `validate:"udp4_addr"`
UDPAddrv6 string `validate:"udp6_addr"`
IPAddr string `validate:"ip_addr"`
IPAddrv4 string `validate:"ip4_addr"`
IPAddrv6 string `validate:"ip6_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
MAC string `validate:"mac"`
IsColor string `validate:"iscolor"`
StrPtrMinLen *string `validate:"min=10"`
StrPtrMaxLen *string `validate:"max=1"`
StrPtrLen *string `validate:"len=2"`
StrPtrLt *string `validate:"lt=1"`
StrPtrLte *string `validate:"lte=1"`
StrPtrGt *string `validate:"gt=10"`
StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
UniqueSlice []string `validate:"unique"`
UniqueArray [3]string `validate:"unique"`
UniqueMap map[string]string `validate:"unique"`
JSONString string `validate:"json"`
JWTString string `validate:"jwt"`
LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"`
Datetime string `validate:"datetime=2006-01-02"`
PostCode string `validate:"postcode_iso3166_alpha2=SG"`
PostCodeCountry string
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
}
var test Test
test.Inner.EqCSFieldString = "1234"
test.Inner.GtCSFieldString = "1234"
test.Inner.GteCSFieldString = "1234"
test.MaxString = "1234"
test.MaxNumber = 2000
test.MaxMultiple = make([]string, 9)
test.LtString = "1234"
test.LtNumber = 6
test.LtMultiple = make([]string, 3)
test.LtTime = time.Now().Add(time.Hour * 24)
test.LteString = "1234"
test.LteNumber = 6
test.LteMultiple = make([]string, 3)
test.LteTime = time.Now().Add(time.Hour * 24)
test.LtFieldString = "12345"
test.LteFieldString = "12345"
test.LtCSFieldString = "1234"
test.LteCSFieldString = "1234"
test.AlphaString = "abc3"
test.AlphanumString = "abc3!"
test.NumericString = "12E.00"
test.NumberString = "12E"
test.Excludes = "this is some test text"
test.ExcludesAll = "This is Great!"
test.ExcludesRune = "Love it ☻"
test.ASCII = "カタカナ"
test.PrintableASCII = "カタカナ"
test.MultiByte = "1234feerf"
test.LowercaseString = "ABCDEFG"
test.UppercaseString = "abcdefg"
s := "toolong"
test.StrPtrMaxLen = &s
test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
test.Datetime = "2008-Feb-01"
err = validate.Struct(test)
NotEqual(t, err, nil)
errs, ok := err.(validator.ValidationErrors)
Equal(t, ok, true)
tests := []struct {
ns string
expected string
}{
{
ns: "Test.IsColor",
expected: "IsColor phải là màu sắc hợp lệ",
},
{
ns: "Test.MAC",
expected: "MAC chỉ được chứa địa chỉ MAC",
},
{
ns: "Test.IPAddr",
expected: "IPAddr phải là địa chỉ IP có thể phân giải",
},
{
ns: "Test.IPAddrv4",
expected: "IPAddrv4 phải là địa chỉ IPv4 có thể phân giải",
},
{
ns: "Test.IPAddrv6",
expected: "IPAddrv6 phải là địa chỉ IPv6 có thể phân giải",
},
{
ns: "Test.UDPAddr",
expected: "UDPAddr phải là địa chỉ UDP",
},
{
ns: "Test.UDPAddrv4",
expected: "UDPAddrv4 phải là địa chỉ IPv4 UDP",
},
{
ns: "Test.UDPAddrv6",
expected: "UDPAddrv6 phải là địa chỉ IPv6 UDP",
},
{
ns: "Test.TCPAddr",
expected: "TCPAddr phải là địa chỉ TCP",
},
{
ns: "Test.TCPAddrv4",
expected: "TCPAddrv4 phải là địa chỉ IPv4 TCP",
},
{
ns: "Test.TCPAddrv6",
expected: "TCPAddrv6 phải là địa chỉ IPv6 TCP",
},
{
ns: "Test.CIDR",
expected: "CIDR chỉ được chứa CIDR notation",
},
{
ns: "Test.CIDRv4",
expected: "CIDRv4 chỉ được chứa CIDR notation của một địa chỉ IPv4",
},
{
ns: "Test.CIDRv6",
expected: "CIDRv6 chỉ được chứa CIDR notation của một địa chỉ IPv6",
},
{
ns: "Test.SSN",
expected: "SSN phải là SSN number",
},
{
ns: "Test.IP",
expected: "IP phải là địa chỉ IP",
},
{
ns: "Test.IPv4",
expected: "IPv4 phải là địa chỉ IPv4",
},
{
ns: "Test.IPv6",
expected: "IPv6 phải là địa chỉ IPv6",
},
{
ns: "Test.DataURI",
expected: "DataURI chỉ được chứa Data URI",
},
{
ns: "Test.Latitude",
expected: "Latitude chỉ được chứa latitude (vỹ độ)",
},
{
ns: "Test.Longitude",
expected: "Longitude chỉ được chứa longitude (kinh độ)",
},
{
ns: "Test.MultiByte",
expected: "MultiByte chỉ được chứa ký tự multibyte",
},
{
ns: "Test.ASCII",
expected: "ASCII chỉ được chứa ký tự ASCII",
},
{
ns: "Test.PrintableASCII",
expected: "PrintableASCII chỉ được chứa ký tự ASCII có thể in ấn",
},
{
ns: "Test.UUID",
expected: "UUID phải là giá trị UUID",
},
{
ns: "Test.UUID3",
expected: "UUID3 phải là giá trị UUID phiên bản 3",
},
{
ns: "Test.UUID4",
expected: "UUID4 phải là giá trị UUID phiên bản 4",
},
{
ns: "Test.UUID5",
expected: "UUID5 phải là giá trị UUID phiên bản 5",
},
{
ns: "Test.ISBN",
expected: "ISBN phải là số ISBN",
},
{
ns: "Test.ISBN10",
expected: "ISBN10 phải là số ISBN-10",
},
{
ns: "Test.ISBN13",
expected: "ISBN13 phải là số ISBN-13",
},
{
ns: "Test.Excludes",
expected: "Excludes không được chứa chuỗi 'text'",
},
{
ns: "Test.ExcludesAll",
expected: "ExcludesAll không được chứa bất kỳ ký tự nào trong nhóm ký tự '!@#$'",
},
{
ns: "Test.ExcludesRune",
expected: "ExcludesRune không được chứa '☻'",
},
{
ns: "Test.ContainsAny",
expected: "ContainsAny phải chứa ít nhất 1 trong cách ký tự sau '!@#$'",
},
{
ns: "Test.Contains",
expected: "Contains phải chứa chuỗi 'purpose'",
},
{
ns: "Test.Base64",
expected: "Base64 phải là giá trị chuỗi Base64",
},
{
ns: "Test.Email",
expected: "Email phải là giá trị email address",
},
{
ns: "Test.URL",
expected: "URL phải là giá trị URL",
},
{
ns: "Test.URI",
expected: "URI phải là giá trị URI",
},
{
ns: "Test.RGBColorString",
expected: "RGBColorString phải là giá trị RGB color",
},
{
ns: "Test.RGBAColorString",
expected: "RGBAColorString phải là giá trị RGBA color",
},
{
ns: "Test.HSLColorString",
expected: "HSLColorString phải là giá trị HSL color",
},
{
ns: "Test.HSLAColorString",
expected: "HSLAColorString phải là giá trị HSLA color",
},
{
ns: "Test.HexadecimalString",
expected: "HexadecimalString phải là giá trị hexadecimal",
},
{
ns: "Test.HexColorString",
expected: "HexColorString phải là giá trị HEX color",
},
{
ns: "Test.NumberString",
expected: "NumberString chỉ được chứa giá trị số",
},
{
ns: "Test.NumericString",
expected: "NumericString chỉ được chứa giá trị số hoặc số dưới dạng chữ",
},
{
ns: "Test.AlphanumString",
expected: "AlphanumString chỉ được chứa ký tự dạng alphanumeric",
},
{
ns: "Test.AlphaString",
expected: "AlphaString chỉ được chứa ký tự dạng alphabetic",
},
{
ns: "Test.LtFieldString",
expected: "LtFieldString chỉ được nhỏ hơn MaxString",
},
{
ns: "Test.LteFieldString",
expected: "LteFieldString chỉ được nhỏ hơn hoặc bằng MaxString",
},
{
ns: "Test.GtFieldString",
expected: "GtFieldString phải lớn hơn MaxString",
},
{
ns: "Test.GteFieldString",
expected: "GteFieldString phải lớn hơn hoặc bằng MaxString",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString không được phép bằng EqFieldString",
},
{
ns: "Test.LtCSFieldString",
expected: "LtCSFieldString chỉ được nhỏ hơn Inner.LtCSFieldString",
},
{
ns: "Test.LteCSFieldString",
expected: "LteCSFieldString chỉ được nhỏ hơn hoặc bằng Inner.LteCSFieldString",
},
{
ns: "Test.GtCSFieldString",
expected: "GtCSFieldString phải lớn hơn Inner.GtCSFieldString",
},
{
ns: "Test.GteCSFieldString",
expected: "GteCSFieldString phải lớn hơn hoặc bằng Inner.GteCSFieldString",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString không được phép bằng Inner.NeCSFieldString",
},
{
ns: "Test.EqCSFieldString",
expected: "EqCSFieldString phải bằng Inner.EqCSFieldString",
},
{
ns: "Test.EqFieldString",
expected: "EqFieldString phải bằng MaxString",
},
{
ns: "Test.GteString",
expected: "GteString phải có độ dài ít nhất 3 ký tự",
},
{
ns: "Test.GteNumber",
expected: "GteNumber phải là 5,56 hoặc lớn hơn",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple phải chứa ít nhất 2 phần tử",
},
{
ns: "Test.GteTime",
expected: "GteTime phải lớn hơn hoặc bằng Ngày & Giờ hiện tại",
},
{
ns: "Test.GtString",
expected: "GtString phải có độ dài lớn hơn 3 ký tự",
},
{
ns: "Test.GtNumber",
expected: "GtNumber phải lớn hơn 5,56",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple phải chứa nhiều hơn 2 phần tử",
},
{
ns: "Test.GtTime",
expected: "GtTime phải lớn hơn Ngày & Giờ hiện tại",
},
{
ns: "Test.LteString",
expected: "LteString chỉ được có độ dài tối đa là 3 ký tự",
},
{
ns: "Test.LteNumber",
expected: "LteNumber phải là 5,56 hoặc nhỏ hơn",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple chỉ được chứa nhiều nhất 2 phần tử",
},
{
ns: "Test.LteTime",
expected: "LteTime chỉ được nhỏ hơn hoặc bằng Ngày & Giờ hiện tại",
},
{
ns: "Test.LtString",
expected: "LtString phải có độ dài nhỏ hơn 3 ký tự",
},
{
ns: "Test.LtNumber",
expected: "LtNumber phải nhỏ hơn 5,56",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple chỉ được chứa ít hơn 2 phần tử",
},
{
ns: "Test.LtTime",
expected: "LtTime phải nhỏ hơn Ngày & Giờ hiện tại",
},
{
ns: "Test.NeString",
expected: "NeString không được bằng ",
},
{
ns: "Test.NeNumber",
expected: "NeNumber không được bằng 0.00",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple không được bằng 0",
},
{
ns: "Test.EqString",
expected: "EqString không bằng 3",
},
{
ns: "Test.EqNumber",
expected: "EqNumber không bằng 2.33",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple không bằng 7",
},
{
ns: "Test.MaxString",
expected: "MaxString chỉ được chứa tối đa 3 ký tự",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber phải là 1.113,00 hoặc nhỏ hơn",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple chỉ được chứa tối đa 7 phần tử",
},
{
ns: "Test.MinString",
expected: "MinString phải chứa ít nhất 1 ký tự",
},
{
ns: "Test.MinNumber",
expected: "MinNumber phải bằng 1.113,00 hoặc lớn hơn",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple phải chứa ít nhất 7 phần tử",
},
{
ns: "Test.LenString",
expected: "LenString phải có độ dài là 1 ký tự",
},
{
ns: "Test.LenNumber",
expected: "LenNumber phải bằng 1.113,00",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple phải chứa 7 phần tử",
},
{
ns: "Test.RequiredString",
expected: "RequiredString không được bỏ trống",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber không được bỏ trống",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple không được bỏ trống",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen phải chứa ít nhất 10 ký tự",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen chỉ được chứa tối đa 1 ký tự",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen phải có độ dài là 2 ký tự",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt phải có độ dài nhỏ hơn 1 ký tự",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte chỉ được có độ dài tối đa là 1 ký tự",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt phải có độ dài lớn hơn 10 ký tự",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte phải có độ dài ít nhất 10 ký tự",
},
{
ns: "Test.OneOfString",
expected: "OneOfString phải là trong những giá trị [red green]",
},
{
ns: "Test.OneOfInt",
expected: "OneOfInt phải là trong những giá trị [5 63]",
},
{
ns: "Test.UniqueSlice",
expected: "UniqueSlice chỉ được chứa những giá trị không trùng lặp",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArray chỉ được chứa những giá trị không trùng lặp",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMap chỉ được chứa những giá trị không trùng lặp",
},
{
ns: "Test.JSONString",
expected: "JSONString phải là một chuỗi json hợp lệ",
},
{
ns: "Test.JWTString",
expected: "JWTString phải là một chuỗi jwt hợp lệ",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseString phải được viết thường",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseString phải được viết hoa",
},
{
ns: "Test.Datetime",
expected: "Datetime không trùng định dạng ngày tháng 2006-01-02",
},
{
ns: "Test.PostCode",
expected: "PostCode sai định dạng postcode của quốc gia SG",
},
{
ns: "Test.PostCodeByField",
expected: "PostCodeByField sai định dạng postcode của quốc gia tương ứng thuộc trường PostCodeCountry",
},
}
for _, tt := range tests {
var fe validator.FieldError
for _, e := range errs {
if tt.ns == e.Namespace() {
fe = e
break
}
}
NotEqual(t, fe, nil)
Equal(t, tt.expected, fe.Translate(trans))
}
}

@ -29,6 +29,36 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}为必填字段", translation: "{0}为必填字段",
override: false, override: false,
}, },
{
tag: "required_if",
translation: "{0}为必填字段",
override: false,
},
{
tag: "required_unless",
translation: "{0}为必填字段",
override: false,
},
{
tag: "required_with",
translation: "{0}为必填字段",
override: false,
},
{
tag: "required_with_all",
translation: "{0}为必填字段",
override: false,
},
{
tag: "required_without",
translation: "{0}为必填字段",
override: false,
},
{
tag: "required_without_all",
translation: "{0}为必填字段",
override: false,
},
{ {
tag: "len", tag: "len",
customRegisFunc: func(ut ut.Translator) (err error) { customRegisFunc: func(ut ut.Translator) (err error) {
@ -1000,6 +1030,16 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}只能包含字母和数字", translation: "{0}只能包含字母和数字",
override: false, override: false,
}, },
{
tag: "alphanumunicode",
translation: "{0}只能包含字母数字和Unicode字符",
override: false,
},
{
tag: "alphaunicode",
translation: "{0}只能包含字母和Unicode字符",
override: false,
},
{ {
tag: "numeric", tag: "numeric",
translation: "{0}必须是一个有效的数值", translation: "{0}必须是一个有效的数值",
@ -1090,6 +1130,21 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return t return t
}, },
}, },
{
tag: "containsrune",
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("警告: 翻译字段错误: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{ {
tag: "excludes", tag: "excludes",
translation: "{0}不能包含文本'{1}'", translation: "{0}不能包含文本'{1}'",
@ -1135,6 +1190,36 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return t return t
}, },
}, },
{
tag: "endswith",
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("警告: 翻译字段错误: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{
tag: "startswith",
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("警告: 翻译字段错误: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{ {
tag: "isbn", tag: "isbn",
translation: "{0}必须是一个有效的ISBN编号", translation: "{0}必须是一个有效的ISBN编号",
@ -1170,6 +1255,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}必须是一个有效的V5 UUID", translation: "{0}必须是一个有效的V5 UUID",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0}必须是一个有效的ULID",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0}必须只包含ascii字符", translation: "{0}必须只包含ascii字符",

@ -31,117 +31,123 @@ func TestTranslations(t *testing.T) {
} }
type Test struct { type Test struct {
Inner Inner Inner Inner
RequiredString string `validate:"required"` RequiredString string `validate:"required"`
RequiredNumber int `validate:"required"` RequiredNumber int `validate:"required"`
RequiredMultiple []string `validate:"required"` RequiredMultiple []string `validate:"required"`
LenString string `validate:"len=1"` LenString string `validate:"len=1"`
LenNumber float64 `validate:"len=1113.00"` LenNumber float64 `validate:"len=1113.00"`
LenMultiple []string `validate:"len=7"` LenMultiple []string `validate:"len=7"`
MinString string `validate:"min=1"` MinString string `validate:"min=1"`
MinNumber float64 `validate:"min=1113.00"` MinNumber float64 `validate:"min=1113.00"`
MinMultiple []string `validate:"min=7"` MinMultiple []string `validate:"min=7"`
MaxString string `validate:"max=3"` MaxString string `validate:"max=3"`
MaxNumber float64 `validate:"max=1113.00"` MaxNumber float64 `validate:"max=1113.00"`
MaxMultiple []string `validate:"max=7"` MaxMultiple []string `validate:"max=7"`
EqString string `validate:"eq=3"` EqString string `validate:"eq=3"`
EqNumber float64 `validate:"eq=2.33"` EqNumber float64 `validate:"eq=2.33"`
EqMultiple []string `validate:"eq=7"` EqMultiple []string `validate:"eq=7"`
NeString string `validate:"ne="` NeString string `validate:"ne="`
NeNumber float64 `validate:"ne=0.00"` NeNumber float64 `validate:"ne=0.00"`
NeMultiple []string `validate:"ne=0"` NeMultiple []string `validate:"ne=0"`
LtString string `validate:"lt=3"` LtString string `validate:"lt=3"`
LtNumber float64 `validate:"lt=5.56"` LtNumber float64 `validate:"lt=5.56"`
LtMultiple []string `validate:"lt=2"` LtMultiple []string `validate:"lt=2"`
LtTime time.Time `validate:"lt"` LtTime time.Time `validate:"lt"`
LteString string `validate:"lte=3"` LteString string `validate:"lte=3"`
LteNumber float64 `validate:"lte=5.56"` LteNumber float64 `validate:"lte=5.56"`
LteMultiple []string `validate:"lte=2"` LteMultiple []string `validate:"lte=2"`
LteTime time.Time `validate:"lte"` LteTime time.Time `validate:"lte"`
GtString string `validate:"gt=3"` GtString string `validate:"gt=3"`
GtNumber float64 `validate:"gt=5.56"` GtNumber float64 `validate:"gt=5.56"`
GtMultiple []string `validate:"gt=2"` GtMultiple []string `validate:"gt=2"`
GtTime time.Time `validate:"gt"` GtTime time.Time `validate:"gt"`
GteString string `validate:"gte=3"` GteString string `validate:"gte=3"`
GteNumber float64 `validate:"gte=5.56"` GteNumber float64 `validate:"gte=5.56"`
GteMultiple []string `validate:"gte=2"` GteMultiple []string `validate:"gte=2"`
GteTime time.Time `validate:"gte"` GteTime time.Time `validate:"gte"`
EqFieldString string `validate:"eqfield=MaxString"` EqFieldString string `validate:"eqfield=MaxString"`
EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"` EqCSFieldString string `validate:"eqcsfield=Inner.EqCSFieldString"`
NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"` NeCSFieldString string `validate:"necsfield=Inner.NeCSFieldString"`
GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"` GtCSFieldString string `validate:"gtcsfield=Inner.GtCSFieldString"`
GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"` GteCSFieldString string `validate:"gtecsfield=Inner.GteCSFieldString"`
LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"` LtCSFieldString string `validate:"ltcsfield=Inner.LtCSFieldString"`
LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"` LteCSFieldString string `validate:"ltecsfield=Inner.LteCSFieldString"`
NeFieldString string `validate:"nefield=EqFieldString"` NeFieldString string `validate:"nefield=EqFieldString"`
GtFieldString string `validate:"gtfield=MaxString"` GtFieldString string `validate:"gtfield=MaxString"`
GteFieldString string `validate:"gtefield=MaxString"` GteFieldString string `validate:"gtefield=MaxString"`
LtFieldString string `validate:"ltfield=MaxString"` LtFieldString string `validate:"ltfield=MaxString"`
LteFieldString string `validate:"ltefield=MaxString"` LteFieldString string `validate:"ltefield=MaxString"`
AlphaString string `validate:"alpha"` AlphaString string `validate:"alpha"`
AlphanumString string `validate:"alphanum"` AlphanumString string `validate:"alphanum"`
NumericString string `validate:"numeric"` AlphanumUnicodeString string `validate:"alphanumunicode"`
NumberString string `validate:"number"` AlphaUnicodeString string `validate:"alphaunicode"`
HexadecimalString string `validate:"hexadecimal"` NumericString string `validate:"numeric"`
HexColorString string `validate:"hexcolor"` NumberString string `validate:"number"`
RGBColorString string `validate:"rgb"` HexadecimalString string `validate:"hexadecimal"`
RGBAColorString string `validate:"rgba"` HexColorString string `validate:"hexcolor"`
HSLColorString string `validate:"hsl"` RGBColorString string `validate:"rgb"`
HSLAColorString string `validate:"hsla"` RGBAColorString string `validate:"rgba"`
Email string `validate:"email"` HSLColorString string `validate:"hsl"`
URL string `validate:"url"` HSLAColorString string `validate:"hsla"`
URI string `validate:"uri"` Email string `validate:"email"`
Base64 string `validate:"base64"` URL string `validate:"url"`
Contains string `validate:"contains=purpose"` URI string `validate:"uri"`
ContainsAny string `validate:"containsany=!@#$"` Base64 string `validate:"base64"`
Excludes string `validate:"excludes=text"` Contains string `validate:"contains=purpose"`
ExcludesAll string `validate:"excludesall=!@#$"` ContainsAny string `validate:"containsany=!@#$"`
ExcludesRune string `validate:"excludesrune=☻"` ContainsRune string `validate:"containsrune=☻"`
ISBN string `validate:"isbn"` Excludes string `validate:"excludes=text"`
ISBN10 string `validate:"isbn10"` ExcludesAll string `validate:"excludesall=!@#$"`
ISBN13 string `validate:"isbn13"` ExcludesRune string `validate:"excludesrune=☻"`
UUID string `validate:"uuid"` EndsWith string `validate:"endswith=end"`
UUID3 string `validate:"uuid3"` StartsWith string `validate:"startswith=start"`
UUID4 string `validate:"uuid4"` ISBN string `validate:"isbn"`
UUID5 string `validate:"uuid5"` ISBN10 string `validate:"isbn10"`
ASCII string `validate:"ascii"` ISBN13 string `validate:"isbn13"`
PrintableASCII string `validate:"printascii"` UUID string `validate:"uuid"`
MultiByte string `validate:"multibyte"` UUID3 string `validate:"uuid3"`
DataURI string `validate:"datauri"` UUID4 string `validate:"uuid4"`
Latitude string `validate:"latitude"` UUID5 string `validate:"uuid5"`
Longitude string `validate:"longitude"` ULID string `validate:"ulid"`
SSN string `validate:"ssn"` ASCII string `validate:"ascii"`
IP string `validate:"ip"` PrintableASCII string `validate:"printascii"`
IPv4 string `validate:"ipv4"` MultiByte string `validate:"multibyte"`
IPv6 string `validate:"ipv6"` DataURI string `validate:"datauri"`
CIDR string `validate:"cidr"` Latitude string `validate:"latitude"`
CIDRv4 string `validate:"cidrv4"` Longitude string `validate:"longitude"`
CIDRv6 string `validate:"cidrv6"` SSN string `validate:"ssn"`
TCPAddr string `validate:"tcp_addr"` IP string `validate:"ip"`
TCPAddrv4 string `validate:"tcp4_addr"` IPv4 string `validate:"ipv4"`
TCPAddrv6 string `validate:"tcp6_addr"` IPv6 string `validate:"ipv6"`
UDPAddr string `validate:"udp_addr"` CIDR string `validate:"cidr"`
UDPAddrv4 string `validate:"udp4_addr"` CIDRv4 string `validate:"cidrv4"`
UDPAddrv6 string `validate:"udp6_addr"` CIDRv6 string `validate:"cidrv6"`
IPAddr string `validate:"ip_addr"` TCPAddr string `validate:"tcp_addr"`
IPAddrv4 string `validate:"ip4_addr"` TCPAddrv4 string `validate:"tcp4_addr"`
IPAddrv6 string `validate:"ip6_addr"` TCPAddrv6 string `validate:"tcp6_addr"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future UDPAddr string `validate:"udp_addr"`
MAC string `validate:"mac"` UDPAddrv4 string `validate:"udp4_addr"`
IsColor string `validate:"iscolor"` UDPAddrv6 string `validate:"udp6_addr"`
StrPtrMinLen *string `validate:"min=10"` IPAddr string `validate:"ip_addr"`
StrPtrMaxLen *string `validate:"max=1"` IPAddrv4 string `validate:"ip4_addr"`
StrPtrLen *string `validate:"len=2"` IPAddrv6 string `validate:"ip6_addr"`
StrPtrLt *string `validate:"lt=1"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
StrPtrLte *string `validate:"lte=1"` MAC string `validate:"mac"`
StrPtrGt *string `validate:"gt=10"` IsColor string `validate:"iscolor"`
StrPtrGte *string `validate:"gte=10"` StrPtrMinLen *string `validate:"min=10"`
OneOfString string `validate:"oneof=red green"` StrPtrMaxLen *string `validate:"max=1"`
OneOfInt int `validate:"oneof=5 63"` StrPtrLen *string `validate:"len=2"`
JsonString string `validate:"json"` StrPtrLt *string `validate:"lt=1"`
LowercaseString string `validate:"lowercase"` StrPtrLte *string `validate:"lte=1"`
UppercaseString string `validate:"uppercase"` StrPtrGt *string `validate:"gt=10"`
Datetime string `validate:"datetime=2006-01-02"` StrPtrGte *string `validate:"gte=10"`
OneOfString string `validate:"oneof=red green"`
OneOfInt int `validate:"oneof=5 63"`
JsonString string `validate:"json"`
LowercaseString string `validate:"lowercase"`
UppercaseString string `validate:"uppercase"`
Datetime string `validate:"datetime=2006-01-02"`
} }
var test Test var test Test
@ -172,6 +178,8 @@ func TestTranslations(t *testing.T) {
test.AlphaString = "abc3" test.AlphaString = "abc3"
test.AlphanumString = "abc3!" test.AlphanumString = "abc3!"
test.AlphanumUnicodeString = "abc3啊!"
test.AlphaUnicodeString = "abc3啊"
test.NumericString = "12E.00" test.NumericString = "12E.00"
test.NumberString = "12E" test.NumberString = "12E"
@ -179,6 +187,9 @@ func TestTranslations(t *testing.T) {
test.ExcludesAll = "This is Great!" test.ExcludesAll = "This is Great!"
test.ExcludesRune = "Love it ☻" test.ExcludesRune = "Love it ☻"
test.EndsWith = "this is some test text"
test.StartsWith = "this is some test text"
test.ASCII = "カタカナ" test.ASCII = "カタカナ"
test.PrintableASCII = "カタカナ" test.PrintableASCII = "カタカナ"
@ -317,6 +328,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5必须是一个有效的V5 UUID", expected: "UUID5必须是一个有效的V5 UUID",
}, },
{
ns: "Test.ULID",
expected: "ULID必须是一个有效的ULID",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN必须是一个有效的ISBN编号", expected: "ISBN必须是一个有效的ISBN编号",
@ -329,6 +344,14 @@ func TestTranslations(t *testing.T) {
ns: "Test.ISBN13", ns: "Test.ISBN13",
expected: "ISBN13必须是一个有效的ISBN-13编号", expected: "ISBN13必须是一个有效的ISBN-13编号",
}, },
{
ns: "Test.EndsWith",
expected: "EndsWith必须以文本'end'结尾",
},
{
ns: "Test.StartsWith",
expected: "StartsWith必须以文本'start'开头",
},
{ {
ns: "Test.Excludes", ns: "Test.Excludes",
expected: "Excludes不能包含文本'text'", expected: "Excludes不能包含文本'text'",
@ -341,6 +364,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.ExcludesRune", ns: "Test.ExcludesRune",
expected: "ExcludesRune不能包含'☻'", expected: "ExcludesRune不能包含'☻'",
}, },
{
ns: "Test.ContainsRune",
expected: "ContainsRune必须包含字符'☻'",
},
{ {
ns: "Test.ContainsAny", ns: "Test.ContainsAny",
expected: "ContainsAny必须包含至少一个以下字符'!@#$'", expected: "ContainsAny必须包含至少一个以下字符'!@#$'",
@ -397,6 +424,14 @@ func TestTranslations(t *testing.T) {
ns: "Test.NumericString", ns: "Test.NumericString",
expected: "NumericString必须是一个有效的数值", expected: "NumericString必须是一个有效的数值",
}, },
{
ns: "Test.AlphaUnicodeString",
expected: "AlphaUnicodeString只能包含字母和Unicode字符",
},
{
ns: "Test.AlphanumUnicodeString",
expected: "AlphanumUnicodeString只能包含字母数字和Unicode字符",
},
{ {
ns: "Test.AlphanumString", ns: "Test.AlphanumString",
expected: "AlphanumString只能包含字母和数字", expected: "AlphanumString只能包含字母和数字",

@ -1166,6 +1166,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0}必須是一個有效的V5 UUID", translation: "{0}必須是一個有效的V5 UUID",
override: false, override: false,
}, },
{
tag: "ulid",
translation: "{0}必須是一個有效的ULID",
override: false,
},
{ {
tag: "ascii", tag: "ascii",
translation: "{0}必須只包含ascii字元", translation: "{0}必須只包含ascii字元",

@ -104,6 +104,7 @@ func TestTranslations(t *testing.T) {
UUID3 string `validate:"uuid3"` UUID3 string `validate:"uuid3"`
UUID4 string `validate:"uuid4"` UUID4 string `validate:"uuid4"`
UUID5 string `validate:"uuid5"` UUID5 string `validate:"uuid5"`
ULID string `validate:"ulid"`
ASCII string `validate:"ascii"` ASCII string `validate:"ascii"`
PrintableASCII string `validate:"printascii"` PrintableASCII string `validate:"printascii"`
MultiByte string `validate:"multibyte"` MultiByte string `validate:"multibyte"`
@ -309,6 +310,10 @@ func TestTranslations(t *testing.T) {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5必須是一個有效的V5 UUID", expected: "UUID5必須是一個有效的V5 UUID",
}, },
{
ns: "Test.ULID",
expected: "ULID必須是一個有效的ULID",
},
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
expected: "ISBN必須是一個有效的ISBN編號", expected: "ISBN必須是一個有效的ISBN編號",

@ -82,7 +82,7 @@ BEGIN:
fld := namespace fld := namespace
var ns string var ns string
if typ != timeType { if !typ.ConvertibleTo(timeType) {
idx := strings.Index(namespace, namespaceSeparator) idx := strings.Index(namespace, namespaceSeparator)

@ -74,7 +74,7 @@ func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, cur
} }
} }
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)
} }
} }
@ -164,7 +164,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
typ = current.Type() typ = current.Type()
if typ != timeType { if !typ.ConvertibleTo(timeType) {
if ct != nil { if ct != nil {
@ -222,12 +222,12 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
structNs = append(append(structNs, cf.name...), '.') structNs = append(append(structNs, cf.name...), '.')
} }
v.validateStruct(ctx, current, current, typ, ns, structNs, ct) v.validateStruct(ctx, parent, current, typ, ns, structNs, ct)
return return
} }
} }
if !ct.hasTag { if ct == nil || !ct.hasTag {
return return
} }
@ -355,6 +355,10 @@ OUTER:
v.ct = ct v.ct = ct
if ct.fn(ctx, v) { if ct.fn(ctx, v) {
if ct.isBlockEnd {
ct = ct.next
continue OUTER
}
// drain rest of the 'or' values, then continue or leave // drain rest of the 'or' values, then continue or leave
for { for {
@ -368,6 +372,11 @@ OUTER:
if ct.typeof != typeOr { if ct.typeof != typeOr {
continue OUTER continue OUTER
} }
if ct.isBlockEnd {
ct = ct.next
continue OUTER
}
} }
} }
@ -443,7 +452,6 @@ OUTER:
v.ct = ct v.ct = ct
if !ct.fn(ctx, v) { if !ct.fn(ctx, v) {
v.str1 = string(append(ns, cf.altName...)) v.str1 = string(append(ns, cf.altName...))
if v.v.hasTagNameFunc { if v.v.hasTagNameFunc {

@ -29,6 +29,12 @@ const (
requiredWithAllTag = "required_with_all" requiredWithAllTag = "required_with_all"
requiredIfTag = "required_if" requiredIfTag = "required_if"
requiredUnlessTag = "required_unless" requiredUnlessTag = "required_unless"
excludedWithoutAllTag = "excluded_without_all"
excludedWithoutTag = "excluded_without"
excludedWithTag = "excluded_with"
excludedWithAllTag = "excluded_with_all"
excludedIfTag = "excluded_if"
excludedUnlessTag = "excluded_unless"
skipValidationTag = "-" skipValidationTag = "-"
diveTag = "dive" diveTag = "dive"
keysTag = "keys" keysTag = "keys"
@ -80,11 +86,16 @@ type Validate struct {
aliases map[string]string aliases map[string]string
validations map[string]internalValidationFuncWrapper validations map[string]internalValidationFuncWrapper
transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc transTagFunc map[ut.Translator]map[string]TranslationFunc // map[<locale>]map[<tag>]TranslationFunc
rules map[reflect.Type]map[string]string
tagCache *tagCache tagCache *tagCache
structCache *structCache structCache *structCache
} }
// New returns a new instance of 'validate' with sane defaults. // New returns a new instance of 'validate' with sane defaults.
// Validate is designed to be thread-safe and used as a singleton instance.
// It caches information about your struct and validations,
// in essence only parsing your validation tags once per struct type.
// Using multiple instances neglects the benefit of caching.
func New() *Validate { func New() *Validate {
tc := new(tagCache) tc := new(tagCache)
@ -111,7 +122,8 @@ func New() *Validate {
switch k { switch k {
// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour // 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,
excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
_ = v.registerValidation(k, wrapFunc(val), true, true) _ = v.registerValidation(k, wrapFunc(val), true, true)
default: default:
// no need to error check here, baked in will always be valid // no need to error check here, baked in will always be valid
@ -138,17 +150,54 @@ func (v *Validate) SetTagName(name string) {
v.tagName = name 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 ruleObj, ok := rule.(map[string]interface{}); ok {
if dataObj, ok := data[field].(map[string]interface{}); ok {
err := v.ValidateMapCtx(ctx, dataObj, ruleObj)
if len(err) > 0 {
errs[field] = err
}
} else if dataObjs, ok := data[field].([]map[string]interface{}); ok {
for _, obj := range dataObjs {
err := v.ValidateMapCtx(ctx, obj, ruleObj)
if len(err) > 0 {
errs[field] = err
}
}
} else {
errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
}
} else if ruleStr, ok := rule.(string); ok {
err := v.VarCtx(ctx, data[field], ruleStr)
if err != nil {
errs[field] = err
}
}
}
return errs
}
// ValidateMap validates map data from a map of tags
func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
return v.ValidateMapCtx(context.Background(), data, rules)
}
// RegisterTagNameFunc registers a function to get alternate names for StructFields. // RegisterTagNameFunc registers a function to get alternate names for StructFields.
// //
// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names: // eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
// //
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string { // validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] // name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
// if name == "-" { // // skip if tag key says it should be ignored
// return "" // if name == "-" {
// } // return ""
// return name // }
// }) // return name
// })
func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) { func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
v.tagNameFunc = fn v.tagNameFunc = fn
v.hasTagNameFunc = true v.hasTagNameFunc = true
@ -175,11 +224,11 @@ func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationE
func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error {
if len(tag) == 0 { if len(tag) == 0 {
return errors.New("Function Key cannot be empty") return errors.New("function Key cannot be empty")
} }
if fn == nil { if fn == nil {
return errors.New("Function cannot be empty") return errors.New("function cannot be empty")
} }
_, ok := restrictedTags[tag] _, ok := restrictedTags[tag]
@ -235,6 +284,34 @@ func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...i
} }
} }
// RegisterStructValidationMapRules registers validate map rules.
// Be aware that map validation rules supersede those defined on a/the struct if present.
//
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, types ...interface{}) {
if v.rules == nil {
v.rules = make(map[reflect.Type]map[string]string)
}
deepCopyRules := make(map[string]string)
for i, rule := range rules {
deepCopyRules[i] = rule
}
for _, t := range types {
typ := reflect.TypeOf(t)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if typ.Kind() != reflect.Struct {
continue
}
v.rules[typ] = deepCopyRules
}
}
// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
// //
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation // NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
@ -295,7 +372,7 @@ func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {
val = val.Elem() val = val.Elem()
} }
if val.Kind() != reflect.Struct || val.Type() == timeType { if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -340,7 +417,7 @@ func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{}, fn Filt
val = val.Elem() val = val.Elem()
} }
if val.Kind() != reflect.Struct || val.Type() == timeType { if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -388,7 +465,7 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
val = val.Elem() val = val.Elem()
} }
if val.Kind() != reflect.Struct || val.Type() == timeType { if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -409,7 +486,10 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
if len(flds) > 0 { if len(flds) > 0 {
vd.misc = append(vd.misc[0:0], name...) 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 { for _, s := range flds {
@ -475,7 +555,7 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ..
val = val.Elem() val = val.Elem()
} }
if val.Kind() != reflect.Struct || val.Type() == timeType { if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -533,7 +613,7 @@ func (v *Validate) Var(field interface{}, tag string) error {
} }
// VarCtx validates a single variable using tag style validation and allows passing of contextual // VarCtx validates a single variable using tag style validation and allows passing of contextual
// validation validation information via context.Context. // validation information via context.Context.
// eg. // eg.
// var i int // var i int
// validate.Var(i, "gt=1,lt=10") // validate.Var(i, "gt=1,lt=10")
@ -552,6 +632,7 @@ func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (e
} }
ctag := v.fetchCacheTag(tag) ctag := v.fetchCacheTag(tag)
val := reflect.ValueOf(field) val := reflect.ValueOf(field)
vd := v.pool.Get().(*validate) vd := v.pool.Get().(*validate)
vd.top = val vd.top = val

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save