Compare commits

..

1 Commits

Author SHA1 Message Date
Dean Karn 8e998f7f22 update linter and make fixes 5 years ago
  1. 1
      .github/CODEOWNERS
  2. 2
      .github/CONTRIBUTING.md
  3. 5
      .github/ISSUE_TEMPLATE.md
  4. 12
      .github/PULL_REQUEST_TEMPLATE.md
  5. 51
      .github/workflows/workflow.yml
  6. 4
      .gitignore
  7. 16
      MAINTAINERS.md
  8. 4
      Makefile
  9. 231
      README.md
  10. 2
      _examples/custom-validation/main.go
  11. 2
      _examples/custom/main.go
  12. 2
      _examples/dive/main.go
  13. 4
      _examples/gin-upgrading-overriding/v8_to_v9.go
  14. 87
      _examples/map-validation/main.go
  15. 6
      _examples/simple/main.go
  16. 101
      _examples/struct-level/main.go
  17. 92
      _examples/struct-map-rules-validation/main.go
  18. 4
      _examples/translations/main.go
  19. 1610
      baked_in.go
  20. 34
      benchmarks_test.go
  21. 58
      cache.go
  22. 1132
      country_codes.go
  23. 79
      currency_codes.go
  24. 696
      doc.go
  25. 50
      errors.go
  26. 83
      examples_test.go
  27. 67
      field_level.go
  28. 14
      go.mod
  29. 31
      go.sum
  30. 4
      non-standard/validators/notblank.go
  31. 6
      non-standard/validators/notblank_test.go
  32. 173
      postcode_regexes.go
  33. 66
      regexes.go
  34. 12
      struct_level.go
  35. 1389
      translations/ar/ar.go
  36. 695
      translations/ar/ar_test.go
  37. 152
      translations/en/en.go
  38. 76
      translations/en/en_test.go
  39. 1385
      translations/es/es.go
  40. 658
      translations/es/es_test.go
  41. 1384
      translations/fa/fa.go
  42. 690
      translations/fa/fa_test.go
  43. 7
      translations/fr/fr.go
  44. 15
      translations/fr/fr_test.go
  45. 7
      translations/id/id.go
  46. 9
      translations/id/id_test.go
  47. 1261
      translations/it/it.go
  48. 725
      translations/it/it_test.go
  49. 132
      translations/ja/ja.go
  50. 304
      translations/ja/ja_test.go
  51. 1399
      translations/lv/lv.go
  52. 709
      translations/lv/lv_test.go
  53. 7
      translations/nl/nl.go
  54. 9
      translations/nl/nl_test.go
  55. 1410
      translations/pt/pt.go
  56. 682
      translations/pt/pt_test.go
  57. 19
      translations/pt_BR/pt_BR.go
  58. 27
      translations/pt_BR/pt_BR_test.go
  59. 1493
      translations/ru/ru.go
  60. 767
      translations/ru/ru_test.go
  61. 1375
      translations/tr/tr.go
  62. 657
      translations/tr/tr_test.go
  63. 1384
      translations/vi/vi.go
  64. 690
      translations/vi/vi_test.go
  65. 151
      translations/zh/zh.go
  66. 283
      translations/zh/zh_test.go
  67. 53
      translations/zh_tw/zh_tw.go
  68. 20
      translations/zh_tw/zh_tw_test.go
  69. 43
      util.go
  70. 70
      validator.go
  71. 202
      validator_instance.go
  72. 7315
      validator_test.go

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

@ -2,7 +2,7 @@
## Quality Standard ## Quality Standard
To ensure the continued stability of this package, tests are required that cover the change in order for a pull request to be merged. To ensure the continued stability of this package tests are required to be written or already exist in order for a pull request to be merged.
## Reporting issues ## Reporting issues

@ -1,7 +1,4 @@
- [ ] I have looked at the documentation [here](https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation) first? ### Package version eg. v8, v9:
- [ ] I have looked at the examples provided that may showcase my question [here](/_examples)?
### Package version eg. v9, v10:

@ -1,7 +1,13 @@
## Fixes Or Enhances Fixes Or Enhances # .
**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/validator-maintainers Change Details:
-
-
-
@go-playground/admins

@ -1,51 +0,0 @@
on:
push:
branches:
- master
pull_request:
name: Test
jobs:
test:
strategy:
matrix:
go-version: [1.19.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v3
- name: Restore Cache
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-v1-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-v1-go-
- name: Test
run: go test -race -covermode=atomic -coverprofile="profile.cov" ./...
- name: Send Coverage
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.19.x'
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: profile.cov
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19.x
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.50.1

4
.gitignore vendored

@ -6,7 +6,6 @@
# Folders # Folders
_obj _obj
_test _test
bin
# Architecture specific extensions/prefixes # Architecture specific extensions/prefixes
*.[568vq] *.[568vq]
@ -27,5 +26,4 @@ _testmain.go
*.out *.out
*.txt *.txt
cover.html cover.html
README.html README.html
.idea

@ -1,16 +0,0 @@
## 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.

@ -1,9 +1,9 @@
GOCMD=GO111MODULE=on go GOCMD=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.41.1; \ $(GOCMD) get github.com/golangci/golangci-lint/cmd/golangci-lint; \
} }
lint: linters-install lint: linters-install

@ -1,37 +1,37 @@
Package validator Package validator
================= ================
<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) <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-10.12.0-green.svg) ![Project status](https://img.shields.io/badge/version-9.29.1-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/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=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9)
[![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)
[![GoDoc](https://godoc.org/github.com/go-playground/validator?status.svg)](https://pkg.go.dev/github.com/go-playground/validator/v10) [![GoDoc](https://godoc.org/gopkg.in/go-playground/validator.v9?status.svg)](https://godoc.org/gopkg.in/go-playground/validator.v9)
![License](https://img.shields.io/dub/l/vibe-d.svg) ![License](https://img.shields.io/dub/l/vibe-d.svg)
Package validator implements value validations for structs and individual fields based on tags. Package validator implements value validations for structs and individual fields based on tags.
It has the following **unique** features: It has the following **unique** features:
- Cross Field and Cross Struct validations by using validation tags or custom validators. - Cross Field and Cross Struct validations by using validation tags or custom validators.
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. - Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
- Ability to dive into both map keys and values for validation - Ability to dive into both map keys and values for validation
- Handles type interface by determining it's underlying type prior to validation. - Handles type interface by determining it's underlying type prior to validation.
- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) - Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29)
- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs - Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs
- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError - Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError
- Customizable i18n aware error messages. - Customizable i18n aware error messages.
- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) - Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding)
Installation Installation
------------ ------------
Use go get. Use go get.
go get github.com/go-playground/validator/v10 go get gopkg.in/go-playground/validator.v9
Then import the validator package into your own code. Then import the validator package into your own code.
import "github.com/go-playground/validator/v10" import "gopkg.in/go-playground/validator.v9"
Error Return Value Error Return Value
------- -------
@ -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 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: 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:
```go ```go
err := validate.Struct(mystruct) err := validate.Struct(mystruct)
@ -53,207 +53,17 @@ validationErrors := err.(validator.ValidationErrors)
Usage and documentation Usage and documentation
------ ------
Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs. Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usage docs.
##### Examples: ##### Examples:
- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go) - [Simple](https://github.com/go-playground/validator/blob/v9/_examples/simple/main.go)
- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go) - [Custom Field Types](https://github.com/go-playground/validator/blob/v9/_examples/custom/main.go)
- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go) - [Struct Level](https://github.com/go-playground/validator/blob/v9/_examples/struct-level/main.go)
- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go) - [Translations & Custom Errors](https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go)
- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) - [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding)
- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) - [wash - an example application putting it all together](https://github.com/bluesuncorp/wash)
Baked-in Validations
------
### Fields:
| Tag | Description |
| - | - |
| eqcsfield | Field Equals Another Field (relative)|
| eqfield | Field Equals Another Field |
| fieldcontains | Check the indicated characters are present in the Field |
| fieldexcludes | Check the indicated characters are not present in the field |
| gtcsfield | Field Greater Than Another Relative Field |
| gtecsfield | Field Greater Than or Equal To Another Relative Field |
| gtefield | Field Greater Than or Equal To Another Field |
| gtfield | Field Greater Than Another Field |
| ltcsfield | Less Than Another Relative Field |
| ltecsfield | Less Than or Equal To Another Relative Field |
| ltefield | Less Than or Equal To Another Field |
| ltfield | Less Than Another Field |
| necsfield | Field Does Not Equal Another Field (relative) |
| nefield | Field Does Not Equal Another Field |
### Network:
| Tag | Description |
| - | - |
| cidr | Classless Inter-Domain Routing CIDR |
| cidrv4 | Classless Inter-Domain Routing CIDRv4 |
| cidrv6 | Classless Inter-Domain Routing CIDRv6 |
| datauri | Data URL |
| fqdn | Full Qualified Domain Name (FQDN) |
| hostname | Hostname RFC 952 |
| hostname_port | HostPort |
| hostname_rfc1123 | Hostname RFC 1123 |
| ip | Internet Protocol Address IP |
| ip4_addr | Internet Protocol Address IPv4 |
| ip6_addr | Internet Protocol Address IPv6 |
| ip_addr | Internet Protocol Address IP |
| ipv4 | Internet Protocol Address IPv4 |
| ipv6 | Internet Protocol Address IPv6 |
| mac | Media Access Control Address MAC |
| tcp4_addr | Transmission Control Protocol Address TCPv4 |
| tcp6_addr | Transmission Control Protocol Address TCPv6 |
| tcp_addr | Transmission Control Protocol Address TCP |
| udp4_addr | User Datagram Protocol Address UDPv4 |
| udp6_addr | User Datagram Protocol Address UDPv6 |
| udp_addr | User Datagram Protocol Address UDP |
| unix_addr | Unix domain socket end point Address |
| uri | URI String |
| url | URL String |
| http_url | HTTP URL String |
| url_encoded | URL Encoded |
| urn_rfc2141 | Urn RFC 2141 String |
### Strings:
| Tag | Description |
| - | - |
| alpha | Alpha Only |
| alphanum | Alphanumeric |
| alphanumunicode | Alphanumeric Unicode |
| alphaunicode | Alpha Unicode |
| ascii | ASCII |
| boolean | Boolean |
| contains | Contains |
| containsany | Contains Any |
| containsrune | Contains Rune |
| endsnotwith | Ends Not With |
| endswith | Ends With |
| excludes | Excludes |
| excludesall | Excludes All |
| excludesrune | Excludes Rune |
| lowercase | Lowercase |
| multibyte | Multi-Byte Characters |
| number | Number |
| numeric | Numeric |
| printascii | Printable ASCII |
| startsnotwith | Starts Not With |
| startswith | Starts With |
| uppercase | Uppercase |
### Format:
| Tag | Description |
| - | - |
| base64 | Base64 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_bech32 | Bitcoin Bech32 Address (segwit) |
| credit_card | Credit Card Number |
| mongodb | MongoDB ObjectID |
| cron | Cron |
| datetime | Datetime |
| e164 | e164 formatted phone number |
| email | E-mail String
| eth_addr | Ethereum Address |
| hexadecimal | Hexadecimal String |
| hexcolor | Hexcolor String |
| hsl | HSL String |
| hsla | HSLA String |
| html | HTML Tags |
| html_encoded | HTML Encoded |
| isbn | International Standard Book Number |
| isbn10 | International Standard Book Number 10 |
| 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 |
| jwt | JSON Web Token (JWT) |
| latitude | Latitude |
| longitude | Longitude |
| luhn_checksum | Luhn Algorithm Checksum (for strings and (u)int) |
| postcode_iso3166_alpha2 | Postcode |
| postcode_iso3166_alpha2_field | Postcode |
| rgb | RGB String |
| rgba | RGBA String |
| ssn | Social Security Number SSN |
| timezone | Timezone |
| uuid | Universally Unique Identifier UUID |
| uuid3 | Universally Unique Identifier UUID v3 |
| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 |
| uuid4 | Universally Unique Identifier UUID v4 |
| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 |
| uuid5 | Universally Unique Identifier UUID v5 |
| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
| md4 | MD4 hash |
| md5 | MD5 hash |
| sha256 | SHA256 hash |
| sha384 | SHA384 hash |
| sha512 | SHA512 hash |
| ripemd128 | RIPEMD-128 hash |
| ripemd128 | RIPEMD-160 hash |
| tiger128 | TIGER128 hash |
| tiger160 | TIGER160 hash |
| tiger192 | TIGER192 hash |
| semver | Semantic Versioning 2.0.0 |
| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
| cve | Common Vulnerabilities and Exposures Identifier (CVE id) |
### Comparisons:
| Tag | Description |
| - | - |
| eq | Equals |
| eq_ignore_case | Equals ignoring case |
| gt | Greater than|
| gte | Greater than or equal |
| lt | Less Than |
| lte | Less Than or Equal |
| ne | Not Equal |
| ne_ignore_case | Not Equal ignoring case |
### Other:
| Tag | Description |
| - | - |
| dir | Existing Directory |
| dirpath | Directory Path |
| file | Existing File |
| filepath | File Path |
| isdefault | Is Default |
| len | Length |
| max | Maximum |
| min | Minimum |
| oneof | One Of |
| required | Required |
| required_if | Required If |
| required_unless | Required Unless |
| required_with | Required With |
| required_with_all | Required With All |
| required_without | Required Without |
| required_without_all | Required Without All |
| excluded_if | Excluded If |
| excluded_unless | Excluded Unless |
| excluded_with | Excluded With |
| excluded_with_all | Excluded With All |
| excluded_without | Excluded Without |
| excluded_without_all | Excluded Without All |
| 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
@ -339,10 +149,5 @@ 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

@ -3,7 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// MyStruct .. // MyStruct ..

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// DbBackedUser User struct // DbBackedUser User struct

@ -3,7 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// Test ... // Test ...

@ -5,7 +5,7 @@ import (
"sync" "sync"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
type defaultValidator struct { type defaultValidator struct {
@ -22,7 +22,7 @@ func (v *defaultValidator) ValidateStruct(obj interface{}) error {
v.lazyinit() v.lazyinit()
if err := v.validate.Struct(obj); err != nil { if err := v.validate.Struct(obj); err != nil {
return err return error(err)
} }
} }

@ -1,87 +0,0 @@
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
}

@ -3,7 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// User contains user information // User contains user information
@ -68,8 +68,8 @@ func validateStruct() {
fmt.Println(err.Namespace()) fmt.Println(err.Namespace())
fmt.Println(err.Field()) fmt.Println(err.Field())
fmt.Println(err.StructNamespace()) fmt.Println(err.StructNamespace()) // can differ when a custom TagNameFunc is registered or
fmt.Println(err.StructField()) fmt.Println(err.StructField()) // by passing alt name to ReportError like below
fmt.Println(err.Tag()) fmt.Println(err.Tag())
fmt.Println(err.ActualTag()) fmt.Println(err.ActualTag())
fmt.Println(err.Kind()) fmt.Println(err.Kind())

@ -1,53 +1,19 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"reflect"
"strings"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
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"`
LastName string `json:"lname"` LastName string `json:"lname"`
Age uint8 `validate:"gte=0,lte=130"` Age uint8 `validate:"gte=0,lte=130"`
Email string `json:"e-mail" validate:"required,email"` Email string `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
@ -65,31 +31,11 @@ func main() {
validate = validator.New() validate = validator.New()
// register function to get tag name from json tags.
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
// 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
// internally dereferences during it's type checks. // interanlly 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",
@ -102,13 +48,13 @@ func main() {
FirstName: "", FirstName: "",
LastName: "", LastName: "",
Age: 45, Age: 45,
Email: "Badger.Smith@gmail", Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000", FavouriteColor: "#000",
Addresses: []*Address{address}, Addresses: []*Address{address},
} }
// 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
@ -120,27 +66,18 @@ func main() {
} }
for _, err := range err.(validator.ValidationErrors) { for _, err := range err.(validator.ValidationErrors) {
e := validationError{
Namespace: err.Namespace(), fmt.Println(err.Namespace())
Field: err.Field(), fmt.Println(err.Field())
StructNamespace: err.StructNamespace(), fmt.Println(err.StructNamespace()) // can differ when a custom TagNameFunc is registered or
StructField: err.StructField(), fmt.Println(err.StructField()) // by passing alt name to ReportError like below
Tag: err.Tag(), fmt.Println(err.Tag())
ActualTag: err.ActualTag(), fmt.Println(err.ActualTag())
Kind: fmt.Sprintf("%v", err.Kind()), fmt.Println(err.Kind())
Type: fmt.Sprintf("%v", err.Type()), fmt.Println(err.Type())
Value: fmt.Sprintf("%v", err.Value()), fmt.Println(err.Value())
Param: err.Param(), fmt.Println(err.Param())
Message: err.Error(), fmt.Println()
}
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
@ -164,8 +101,8 @@ func UserStructLevelValidation(sl validator.StructLevel) {
user := sl.Current().Interface().(User) user := sl.Current().Interface().(User)
if len(user.FirstName) == 0 && len(user.LastName) == 0 { if len(user.FirstName) == 0 && len(user.LastName) == 0 {
sl.ReportError(user.FirstName, "fname", "FirstName", "fnameorlname", "") sl.ReportError(user.FirstName, "FirstName", "fname", "fnameorlname", "")
sl.ReportError(user.LastName, "lname", "LastName", "fnameorlname", "") sl.ReportError(user.LastName, "LastName", "lname", "fnameorlname", "")
} }
// plus can do more, even with different tag than "fnameorlname" // plus can do more, even with different tag than "fnameorlname"

@ -1,92 +0,0 @@
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)
}

@ -5,8 +5,8 @@ import (
"github.com/go-playground/locales/en" "github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
en_translations "github.com/go-playground/validator/v10/translations/en" en_translations "gopkg.in/go-playground/validator.v9/translations/en"
) )
// User contains user information // User contains user information

File diff suppressed because it is too large Load Diff

@ -56,7 +56,6 @@ func BenchmarkFieldArrayDiveSuccess(b *testing.B) {
m := []string{"val1", "val2", "val3"} m := []string{"val1", "val2", "val3"}
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,required") _ = validate.Var(m, "required,dive,required")
} }
@ -101,7 +100,6 @@ func BenchmarkFieldMapDiveSuccess(b *testing.B) {
m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"} m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,required") _ = validate.Var(m, "required,dive,required")
} }
@ -146,7 +144,6 @@ func BenchmarkFieldMapDiveWithKeysSuccess(b *testing.B) {
m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"} m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,keys,required,endkeys,required") _ = validate.Var(m, "required,dive,keys,required,endkeys,required")
} }
@ -285,7 +282,6 @@ func BenchmarkFieldOrTagFailureParallel(b *testing.B) {
func BenchmarkStructLevelValidationSuccess(b *testing.B) { func BenchmarkStructLevelValidationSuccess(b *testing.B) {
validate := New() validate := New()
validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{})
tst := TestStruct{ tst := TestStruct{
String: "good value", String: "good value",
} }
@ -299,7 +295,6 @@ func BenchmarkStructLevelValidationSuccess(b *testing.B) {
func BenchmarkStructLevelValidationSuccessParallel(b *testing.B) { func BenchmarkStructLevelValidationSuccessParallel(b *testing.B) {
validate := New() validate := New()
validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{}) validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{})
tst := TestStruct{ tst := TestStruct{
String: "good value", String: "good value",
} }
@ -315,7 +310,6 @@ func BenchmarkStructLevelValidationSuccessParallel(b *testing.B) {
func BenchmarkStructLevelValidationFailure(b *testing.B) { func BenchmarkStructLevelValidationFailure(b *testing.B) {
validate := New() validate := New()
validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{})
tst := TestStruct{ tst := TestStruct{
String: "good value", String: "good value",
} }
@ -329,7 +323,6 @@ func BenchmarkStructLevelValidationFailure(b *testing.B) {
func BenchmarkStructLevelValidationFailureParallel(b *testing.B) { func BenchmarkStructLevelValidationFailureParallel(b *testing.B) {
validate := New() validate := New()
validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{}) validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{})
tst := TestStruct{ tst := TestStruct{
String: "good value", String: "good value",
} }
@ -366,6 +359,7 @@ func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) {
func BenchmarkStructSimpleCustomTypeSuccessParallel(b *testing.B) { func BenchmarkStructSimpleCustomTypeSuccessParallel(b *testing.B) {
validate := New() validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{ val := valuer{
Name: "1", Name: "1",
} }
@ -374,6 +368,7 @@ func BenchmarkStructSimpleCustomTypeSuccessParallel(b *testing.B) {
Valuer valuer `validate:"len=1"` Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
} }
validFoo := &Foo{Valuer: val, IntValue: 7} validFoo := &Foo{Valuer: val, IntValue: 7}
b.ResetTimer() b.ResetTimer()
@ -394,6 +389,7 @@ func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) {
Valuer valuer `validate:"len=1"` Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
} }
validFoo := &Foo{Valuer: val, IntValue: 3} validFoo := &Foo{Valuer: val, IntValue: 3}
b.ResetTimer() b.ResetTimer()
@ -412,6 +408,7 @@ func BenchmarkStructSimpleCustomTypeFailureParallel(b *testing.B) {
Valuer valuer `validate:"len=1"` Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
} }
validFoo := &Foo{Valuer: val, IntValue: 3} validFoo := &Foo{Valuer: val, IntValue: 3}
b.ResetTimer() b.ResetTimer()
@ -433,7 +430,9 @@ func BenchmarkStructFilteredSuccess(b *testing.B) {
test := &Test{ test := &Test{
Name: "Joey Bloggs", Name: "Joey Bloggs",
} }
byts := []byte("Name") byts := []byte("Name")
fn := func(ns []byte) bool { fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts) return !bytes.HasSuffix(ns, byts)
} }
@ -455,7 +454,9 @@ func BenchmarkStructFilteredSuccessParallel(b *testing.B) {
test := &Test{ test := &Test{
Name: "Joey Bloggs", Name: "Joey Bloggs",
} }
byts := []byte("Name") byts := []byte("Name")
fn := func(ns []byte) bool { fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts) return !bytes.HasSuffix(ns, byts)
} }
@ -503,7 +504,9 @@ func BenchmarkStructFilteredFailureParallel(b *testing.B) {
test := &Test{ test := &Test{
Name: "Joey Bloggs", Name: "Joey Bloggs",
} }
byts := []byte("NickName") byts := []byte("NickName")
fn := func(ns []byte) bool { fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts) return !bytes.HasSuffix(ns, byts)
} }
@ -678,6 +681,7 @@ func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) {
now := time.Now().UTC() now := time.Now().UTC()
then := now.Add(time.Hour * 5) then := now.Add(time.Hour * 5)
test := &Test{ test := &Test{
Start: now, Start: now,
End: then, End: then,
@ -699,6 +703,7 @@ func BenchmarkStructSimpleCrossFieldSuccessParallel(b *testing.B) {
now := time.Now().UTC() now := time.Now().UTC()
then := now.Add(time.Hour * 5) then := now.Add(time.Hour * 5)
test := &Test{ test := &Test{
Start: now, Start: now,
End: then, End: then,
@ -744,6 +749,7 @@ func BenchmarkStructSimpleCrossFieldFailureParallel(b *testing.B) {
now := time.Now().UTC() now := time.Now().UTC()
then := now.Add(time.Hour * -5) then := now.Add(time.Hour * -5)
test := &Test{ test := &Test{
Start: now, Start: now,
End: then, End: then,
@ -769,9 +775,11 @@ func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) {
} }
now := time.Now().UTC() now := time.Now().UTC()
inner := &Inner{ inner := &Inner{
Start: now, Start: now,
} }
outer := &Outer{ outer := &Outer{
Inner: inner, Inner: inner,
CreatedAt: now, CreatedAt: now,
@ -796,9 +804,11 @@ func BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel(b *testing.B) {
} }
now := time.Now().UTC() now := time.Now().UTC()
inner := &Inner{ inner := &Inner{
Start: now, Start: now,
} }
outer := &Outer{ outer := &Outer{
Inner: inner, Inner: inner,
CreatedAt: now, CreatedAt: now,
@ -814,6 +824,7 @@ func BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel(b *testing.B) {
func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) { func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) {
validate := New() validate := New()
type Inner struct { type Inner struct {
Start time.Time Start time.Time
} }
@ -875,6 +886,7 @@ func BenchmarkStructSimpleCrossStructCrossFieldFailureParallel(b *testing.B) {
func BenchmarkStructSimpleSuccess(b *testing.B) { func BenchmarkStructSimpleSuccess(b *testing.B) {
validate := New() validate := New()
type Foo struct { type Foo struct {
StringValue string `validate:"min=5,max=10"` StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
@ -890,10 +902,12 @@ func BenchmarkStructSimpleSuccess(b *testing.B) {
func BenchmarkStructSimpleSuccessParallel(b *testing.B) { func BenchmarkStructSimpleSuccessParallel(b *testing.B) {
validate := New() validate := New()
type Foo struct { type Foo struct {
StringValue string `validate:"min=5,max=10"` StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
} }
validFoo := &Foo{StringValue: "Foobar", IntValue: 7} validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
b.ResetTimer() b.ResetTimer()
@ -906,6 +920,7 @@ func BenchmarkStructSimpleSuccessParallel(b *testing.B) {
func BenchmarkStructSimpleFailure(b *testing.B) { func BenchmarkStructSimpleFailure(b *testing.B) {
validate := New() validate := New()
type Foo struct { type Foo struct {
StringValue string `validate:"min=5,max=10"` StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
@ -921,6 +936,7 @@ func BenchmarkStructSimpleFailure(b *testing.B) {
func BenchmarkStructSimpleFailureParallel(b *testing.B) { func BenchmarkStructSimpleFailureParallel(b *testing.B) {
validate := New() validate := New()
type Foo struct { type Foo struct {
StringValue string `validate:"min=5,max=10"` StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"` IntValue int `validate:"min=5,max=10"`
@ -938,6 +954,7 @@ func BenchmarkStructSimpleFailureParallel(b *testing.B) {
func BenchmarkStructComplexSuccess(b *testing.B) { func BenchmarkStructComplexSuccess(b *testing.B) {
validate := New() validate := New()
tSuccess := &TestString{ tSuccess := &TestString{
Required: "Required", Required: "Required",
Len: "length==10", Len: "length==10",
@ -973,6 +990,7 @@ func BenchmarkStructComplexSuccess(b *testing.B) {
func BenchmarkStructComplexSuccessParallel(b *testing.B) { func BenchmarkStructComplexSuccessParallel(b *testing.B) {
validate := New() validate := New()
tSuccess := &TestString{ tSuccess := &TestString{
Required: "Required", Required: "Required",
Len: "length==10", Len: "length==10",
@ -1010,6 +1028,7 @@ func BenchmarkStructComplexSuccessParallel(b *testing.B) {
func BenchmarkStructComplexFailure(b *testing.B) { func BenchmarkStructComplexFailure(b *testing.B) {
validate := New() validate := New()
tFail := &TestString{ tFail := &TestString{
Required: "", Required: "",
Len: "", Len: "",
@ -1042,6 +1061,7 @@ func BenchmarkStructComplexFailure(b *testing.B) {
func BenchmarkStructComplexFailureParallel(b *testing.B) { func BenchmarkStructComplexFailureParallel(b *testing.B) {
validate := New() validate := New()
tFail := &TestString{ tFail := &TestString{
Required: "", Required: "",
Len: "", Len: "",

@ -39,7 +39,9 @@ func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) {
} }
func (sc *structCache) Set(key reflect.Type, value *cStruct) { func (sc *structCache) Set(key reflect.Type, value *cStruct) {
m := sc.m.Load().(map[reflect.Type]*cStruct) m := sc.m.Load().(map[reflect.Type]*cStruct)
nm := make(map[reflect.Type]*cStruct, len(m)+1) nm := make(map[reflect.Type]*cStruct, len(m)+1)
for k, v := range m { for k, v := range m {
nm[k] = v nm[k] = v
@ -59,7 +61,9 @@ func (tc *tagCache) Get(key string) (c *cTag, found bool) {
} }
func (tc *tagCache) Set(key string, value *cTag) { func (tc *tagCache) Set(key string, value *cTag) {
m := tc.m.Load().(map[string]*cTag) m := tc.m.Load().(map[string]*cTag)
nm := make(map[string]*cTag, len(m)+1) nm := make(map[string]*cTag, len(m)+1)
for k, v := range m { for k, v := range m {
nm[k] = v nm[k] = v
@ -83,22 +87,22 @@ type cField struct {
} }
type cTag struct { type cTag struct {
tag string tag string
aliasTag string aliasTag string
actualAliasTag string actualAliasTag string
param string param string
keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation
next *cTag next *cTag
fn FuncCtx fn FuncCtx
typeof tagType typeof tagType
hasTag bool hasTag bool
hasAlias bool hasAlias bool
hasParam bool // true if parameter used eg. eq= where the equal sign has been set hasParam bool // true if parameter used eg. eq= where the equal sign has been set
isBlockEnd bool // indicates the current tag represents the last validation in the block isBlockEnd bool // indicates the current tag represents the last validation in the block
runValidationWhenNil bool
} }
func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct {
v.structCache.lock.Lock() v.structCache.lock.Lock()
defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise! defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise!
@ -114,7 +118,6 @@ 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
@ -122,23 +125,16 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
var customName string var customName string
for i := 0; i < numFields; i++ { for i := 0; i < numFields; i++ {
fld = typ.Field(i) fld = typ.Field(i)
if !fld.Anonymous && len(fld.PkgPath) > 0 { if !fld.Anonymous && len(fld.PkgPath) > 0 {
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
} }
customName = fld.Name customName = fld.Name
if v.hasTagNameFunc { if v.hasTagNameFunc {
@ -156,9 +152,8 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
} else { } else {
// even if field doesn't have validations need cTag for traversing to potential inner/nested // even if field doesn't have validations need cTag for traversing to potential inner/nested
// elements of the field. // elements of the field.
ctag = new(cTag) ctag = &cTag{typeof: typeDefault}
} }
cs.fields = append(cs.fields, &cField{ cs.fields = append(cs.fields, &cField{
idx: i, idx: i,
name: fld.Name, name: fld.Name,
@ -173,11 +168,14 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) { func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) {
var t string var t string
var ok bool
noAlias := len(alias) == 0 noAlias := len(alias) == 0
tags := strings.Split(tag, tagSeparator) tags := strings.Split(tag, tagSeparator)
for i := 0; i < len(tags); i++ { for i := 0; i < len(tags); i++ {
t = tags[i] t = tags[i]
if noAlias { if noAlias {
alias = t alias = t
} }
@ -191,13 +189,14 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
current.next, current = next, curr current.next, current = next, curr
} }
continue continue
} }
var prevTag tagType var prevTag tagType
if i == 0 { if i == 0 {
current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault} current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true}
firstCtag = current firstCtag = current
} else { } else {
prevTag = current.typeof prevTag = current.typeof
@ -261,14 +260,18 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
continue continue
default: default:
if t == isdefault { if t == isdefault {
current.typeof = typeIsDefault current.typeof = typeIsDefault
} }
// if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C" // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
orVals := strings.Split(t, orSeparator) orVals := strings.Split(t, orSeparator)
for j := 0; j < len(orVals); j++ { for j := 0; j < len(orVals); j++ {
vals := strings.SplitN(orVals[j], tagKeySeparator, 2) vals := strings.SplitN(orVals[j], tagKeySeparator, 2)
if noAlias { if noAlias {
alias = vals[0] alias = vals[0]
current.aliasTag = alias current.aliasTag = alias
@ -287,10 +290,7 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName))) panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName)))
} }
if wrapper, ok := v.validations[current.tag]; ok { if current.fn, ok = v.validations[current.tag]; !ok {
current.fn = wrapper.fn
current.runValidationWhenNil = wrapper.runValidatinOnNil
} else {
panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName))) panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName)))
} }

File diff suppressed because it is too large Load Diff

@ -1,79 +0,0 @@
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,
}

696
doc.go

File diff suppressed because it is too large Load Diff

@ -44,9 +44,12 @@ 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++ {
buff.WriteString(ve[i].Error()) fe = ve[i].(*fieldError)
buff.WriteString(fe.Error())
buff.WriteString("\n") buff.WriteString("\n")
} }
@ -79,7 +82,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 {
// Tag returns the validation tag that failed. if the // 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.
// //
@ -87,7 +90,7 @@ type FieldError interface {
// will return "iscolor" // will return "iscolor"
Tag() string Tag() string
// ActualTag returns the validation tag that failed, even if an // 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.
// //
@ -95,8 +98,8 @@ type FieldError interface {
// will return "hexcolor|rgb|rgba|hsl|hsla" // will return "hexcolor|rgb|rgba|hsl|hsla"
ActualTag() string ActualTag() string
// Namespace returns the namespace for the field error, with the tag // returns the namespace for the field error, with the tag
// name taking precedence over the field's actual name. // name taking precedence over the fields actual name.
// //
// eg. JSON name "User.fname" // eg. JSON name "User.fname"
// //
@ -106,33 +109,33 @@ 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
// StructNamespace returns the namespace for the field error, with the field's // returns the namespace for the field error, with the fields
// actual name. // actual name.
// //
// eq. "User.FirstName" see Namespace for comparison // eq. "User.FirstName" see Namespace for comparison
// //
// NOTE: this field can be blank when validating a single primitive field // NOTE: this field can be blank when validating a single primitive field
// using validate.Field(...) as there is no way to extract its name // using validate.Field(...) as there is no way to extract it's name
StructNamespace() string StructNamespace() string
// Field returns the fields name with the tag name taking precedence over the // returns the fields name with the tag name taking precedence over the
// field's actual name. // fields actual name.
// //
// eq. JSON name "fname" // eq. JSON name "fname"
// see StructField for comparison // see StructField for comparison
Field() string Field() string
// StructField returns the field's actual name from the struct, when able to determine. // returns the fields 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
// Value returns the actual field's value in case needed for creating the error // returns the actual fields value in case needed for creating the error
// message // message
Value() interface{} Value() interface{}
// Param returns the param value, in string form for comparison; this will also // 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
@ -143,18 +146,15 @@ 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
// Translate returns the FieldError's translated error // 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
// calling fe.Error() // calling fe.Error()
Translate(ut ut.Translator) string Translate(ut ut.Translator) string
// Error returns the FieldError's message
Error() string
} }
// compile time interface checks // compile time interface checks
@ -190,19 +190,19 @@ func (fe *fieldError) ActualTag() string {
} }
// Namespace 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 fields actual name.
func (fe *fieldError) Namespace() string { func (fe *fieldError) Namespace() string {
return fe.ns return fe.ns
} }
// StructNamespace returns the namespace for the field error, with the field's // StructNamespace returns the namespace for the field error, with the fields
// actual name. // actual name.
func (fe *fieldError) StructNamespace() string { func (fe *fieldError) StructNamespace() string {
return fe.structNs return fe.structNs
} }
// Field returns the field's 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. // fields actual name.
func (fe *fieldError) Field() string { func (fe *fieldError) Field() string {
return fe.ns[len(fe.ns)-int(fe.fieldLen):] return fe.ns[len(fe.ns)-int(fe.fieldLen):]
@ -218,13 +218,13 @@ func (fe *fieldError) Field() string {
// return fld // return fld
} }
// StructField returns the field's actual name from the struct, when able to determine. // returns the fields 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):]
} }
// Value returns the actual field's value in case needed for creating the error // Value returns the actual fields value in case needed for creating the error
// message // message
func (fe *fieldError) Value() interface{} { func (fe *fieldError) Value() interface{} {
return fe.value return fe.value
@ -254,8 +254,8 @@ func (fe *fieldError) Error() string {
// Translate 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 translation can be found, it returns the original // NOTE: is not registered translation can be found it returns the same
// untranslated error message. // as calling fe.Error()
func (fe *fieldError) Translate(ut ut.Translator) string { func (fe *fieldError) Translate(ut ut.Translator) string {
m, ok := fe.v.transTagFunc[ut] m, ok := fe.v.transTagFunc[ut]

@ -0,0 +1,83 @@
package validator_test
// import (
// "fmt"
// "gopkg.in/go-playground/validator.v8"
// )
// func ExampleValidate_new() {
// config := &validator.Config{TagName: "validate"}
// validator.New(config)
// }
// func ExampleValidate_field() {
// // This should be stored somewhere globally
// var validate *validator.Validate
// config := &validator.Config{TagName: "validate"}
// validate = validator.New(config)
// i := 0
// errs := validate.Field(i, "gt=1,lte=10")
// err := errs.(validator.ValidationErrors)[""]
// fmt.Println(err.Field)
// fmt.Println(err.Tag)
// fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time
// fmt.Println(err.Type)
// fmt.Println(err.Param)
// fmt.Println(err.Value)
// //Output:
// //
// //gt
// //int
// //int
// //1
// //0
// }
// func ExampleValidate_struct() {
// // This should be stored somewhere globally
// var validate *validator.Validate
// config := &validator.Config{TagName: "validate"}
// validate = validator.New(config)
// type ContactInformation struct {
// Phone string `validate:"required"`
// Street string `validate:"required"`
// City string `validate:"required"`
// }
// type User struct {
// Name string `validate:"required,excludesall=!@#$%^&*()_+-=:;?/0x2C"` // 0x2C = comma (,)
// Age int8 `validate:"required,gt=0,lt=150"`
// Email string `validate:"email"`
// ContactInformation []*ContactInformation
// }
// contactInfo := &ContactInformation{
// Street: "26 Here Blvd.",
// City: "Paradeso",
// }
// user := &User{
// Name: "Joey Bloggs",
// Age: 31,
// Email: "joeybloggs@gmail.com",
// ContactInformation: []*ContactInformation{contactInfo},
// }
// errs := validate.Struct(user)
// for _, v := range errs.(validator.ValidationErrors) {
// fmt.Println(v.Field) // Phone
// fmt.Println(v.Tag) // required
// //... and so forth
// //Output:
// //Phone
// //required
// }
// }

@ -6,61 +6,38 @@ import "reflect"
// to validate a field // to validate a field
type FieldLevel interface { type FieldLevel interface {
// Top returns the top level struct, if any // returns the top level struct, if any
Top() reflect.Value Top() reflect.Value
// Parent returns the current fields parent struct, if any or // 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
// Field returns current field for validation // returns current field for validation
Field() reflect.Value Field() reflect.Value
// FieldName returns the field's name with the tag // 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
// StructFieldName returns the struct field's name // returns the struct field's name
StructFieldName() string StructFieldName() string
// Param returns param for validation against current field // returns param for validation against current field
Param() string Param() string
// GetTag returns the current validations tag name
GetTag() string
// ExtractType gets the actual underlying type of field value. // ExtractType gets the actual underlying type of field value.
// It will dive into pointers, customTypes and return you the // It will dive into pointers, customTypes and return you the
// 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)
// GetStructFieldOK traverses the parent struct to retrieve a specific field denoted by the provided namespace // 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.
// //
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
// could not be retrieved because it didn't exist. // could not be retrieved because it didn't exist.
//
// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable.
GetStructFieldOK() (reflect.Value, reflect.Kind, bool) GetStructFieldOK() (reflect.Value, reflect.Kind, bool)
// GetStructFieldOKAdvanced 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.
//
// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool)
// GetStructFieldOK2 traverses the parent struct to retrieve a specific field denoted by the provided namespace
// in the param and returns the field, field kind, if it's a nullable type and whether is was successful in retrieving
// the field at all.
//
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
// could not be retrieved because it didn't exist.
GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool)
// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
// the field and namespace allowing more extensibility for validators.
GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool)
} }
var _ FieldLevel = new(validate) var _ FieldLevel = new(validate)
@ -71,16 +48,11 @@ func (v *validate) Field() reflect.Value {
} }
// FieldName 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 takeing precedence over the fields actual name.
func (v *validate) FieldName() string { func (v *validate) FieldName() string {
return v.cf.altName return v.cf.altName
} }
// GetTag returns the current validations tag name
func (v *validate) GetTag() string {
return v.ct.tag
}
// StructFieldName returns the struct field's name // StructFieldName returns the struct field's name
func (v *validate) StructFieldName() string { func (v *validate) StructFieldName() string {
return v.cf.name return v.cf.name
@ -92,29 +64,6 @@ func (v *validate) Param() string {
} }
// GetStructFieldOK returns Param returns param for validation against current field // GetStructFieldOK returns Param returns param for validation against current field
//
// Deprecated: Use GetStructFieldOK2() instead which also return if the value is nullable.
func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) {
current, kind, _, found := v.getStructFieldOKInternal(v.slflParent, v.ct.param)
return current, kind, found
}
// GetStructFieldOKAdvanced 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.
//
// Deprecated: Use GetStructFieldOKAdvanced2() instead which also return if the value is nullable.
func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) {
current, kind, _, found := v.GetStructFieldOKAdvanced2(val, namespace)
return current, kind, found
}
// GetStructFieldOK2 returns Param returns param for validation against current field
func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, bool, bool) {
return v.getStructFieldOKInternal(v.slflParent, v.ct.param) return v.getStructFieldOKInternal(v.slflParent, v.ct.param)
} }
// GetStructFieldOKAdvanced2 is the same as GetStructFieldOK except that it accepts the parent struct to start looking for
// the field and namespace allowing more extensibility for validators.
func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool, bool) {
return v.getStructFieldOKInternal(val, namespace)
}

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

@ -1,31 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
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/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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -4,7 +4,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// NotBlank is the validation function for validating if the current field // NotBlank is the validation function for validating if the current field
@ -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.Trim(strings.TrimSpace(field.String()), "\x1c\x1d\x1e\x1f")) > 0 return len(strings.TrimSpace(field.String())) > 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/assert/v2" "gopkg.in/go-playground/assert.v1"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
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: " \x1c\x1d\x1e\x1f\r\n", String: " ",
Array: []int{}, Array: []int{},
Pointer: x, Pointer: x,
Number: 0, Number: 0,

@ -1,173 +0,0 @@
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)
}
}

@ -9,17 +9,15 @@ const (
alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$" alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$"
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-9a-fA-F]+$"
hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$" hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$" 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*\\)$"
hslaRegexString = "^hsla\\(\\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*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$" hslaRegexString = "^hsla\\(\\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*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
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}$"
@ -30,44 +28,24 @@ 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]"
dataURIRegexString = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)` dataURIRegexString = "^data:.+\\/(.+);base64$"
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][a-zA-Z0-9\-\.]+[a-zA-Z0-9]$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(\.[a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.') btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$` // bitcoin address
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 = `^(?:[^%]|%[0-9A-Fa-f]{2})*$` uRLEncodedRegexString = `(%[A-Fa-f0-9]{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+`
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 (
@ -78,16 +56,14 @@ 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)
hslaRegex = regexp.MustCompile(hslaRegexString) hslaRegex = regexp.MustCompile(hslaRegexString)
e164Regex = regexp.MustCompile(e164RegexString)
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)
@ -98,17 +74,6 @@ 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)
@ -118,20 +83,13 @@ var (
sSNRegex = regexp.MustCompile(sSNRegexString) sSNRegex = regexp.MustCompile(sSNRegexString)
hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952) hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952)
hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123) hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123)
fqdnRegexRFC1123 = regexp.MustCompile(fqdnRegexStringRFC1123)
btcAddressRegex = regexp.MustCompile(btcAddressRegexString) btcAddressRegex = regexp.MustCompile(btcAddressRegexString)
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)
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 {
// Validator returns the main validation object, in case one wants to call validations internally. // 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
// Top returns the top level struct, if any // returns the top level struct, if any
Top() reflect.Value Top() reflect.Value
// Parent returns the current fields parent struct, if any // returns the current fields parent struct, if any
Parent() reflect.Value Parent() reflect.Value
// Current returns the current struct. // 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)
// ReportError reports an error just by passing the field and tag information // 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)
// ReportValidationErrors reports an error just by passing ValidationErrors // reports an error just by passing ValidationErrors
// //
// NOTES: // NOTES:
// //

File diff suppressed because it is too large Load Diff

@ -1,695 +0,0 @@
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))
}
}

@ -10,12 +10,13 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// 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
@ -28,14 +29,10 @@ 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
} }
@ -64,8 +61,10 @@ 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
@ -124,6 +123,7 @@ 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,8 +152,10 @@ 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
@ -212,6 +214,7 @@ 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
} }
@ -240,8 +243,10 @@ 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
@ -302,6 +307,7 @@ 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)
@ -316,6 +322,7 @@ 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)
@ -328,6 +335,7 @@ 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
} }
@ -361,8 +369,10 @@ 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
@ -370,6 +380,7 @@ 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:]))
} }
@ -445,6 +456,7 @@ 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
} }
@ -480,6 +492,7 @@ 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
@ -487,6 +500,7 @@ 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:]))
} }
@ -562,6 +576,7 @@ 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
} }
@ -597,6 +612,7 @@ 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
@ -604,6 +620,7 @@ 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:]))
} }
@ -679,6 +696,7 @@ 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
} }
@ -714,6 +732,7 @@ 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
@ -721,6 +740,7 @@ 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:]))
} }
@ -798,6 +818,7 @@ 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)
@ -812,6 +833,7 @@ 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)
@ -826,6 +848,7 @@ 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)
@ -840,6 +863,7 @@ 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)
@ -854,6 +878,7 @@ 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)
@ -868,6 +893,7 @@ 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)
@ -882,6 +908,7 @@ 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)
@ -896,6 +923,7 @@ 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)
@ -910,6 +938,7 @@ 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)
@ -924,6 +953,7 @@ 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)
@ -938,6 +968,7 @@ 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)
@ -952,6 +983,7 @@ 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)
@ -1011,11 +1043,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
translation: "{0} must be a valid HSLA color", translation: "{0} must be a valid HSLA color",
override: false, override: false,
}, },
{
tag: "e164",
translation: "{0} must be a valid E.164 formatted phone number",
override: false,
},
{ {
tag: "email", tag: "email",
translation: "{0} must be a valid email address", translation: "{0} must be a valid email address",
@ -1041,6 +1068,7 @@ 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)
@ -1055,6 +1083,7 @@ 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)
@ -1069,6 +1098,7 @@ 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)
@ -1083,6 +1113,7 @@ 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)
@ -1097,6 +1128,7 @@ 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)
@ -1141,11 +1173,6 @@ 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",
@ -1266,11 +1293,6 @@ 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",
@ -1281,11 +1303,6 @@ 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}]",
@ -1299,88 +1316,22 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return s return s
}, },
}, },
{
tag: "json",
translation: "{0} must be a valid json string",
override: false,
},
{
tag: "jwt",
translation: "{0} must be a valid jwt string",
override: false,
},
{
tag: "lowercase",
translation: "{0} must be a lowercase string",
override: false,
},
{
tag: "uppercase",
translation: "{0} must be an uppercase string",
override: false,
},
{
tag: "datetime",
translation: "{0} does not match the {1} format",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{
tag: "postcode_iso3166_alpha2",
translation: "{0} does not match postcode format of {1} country",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe)
return fe.(error).Error()
}
return t
},
},
{
tag: "postcode_iso3166_alpha2_field",
translation: "{0} does not match postcode format of country in {1} field",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("warning: error translating FieldError: %#v", fe)
return fe.(error).Error()
}
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)
} }
@ -1394,16 +1345,21 @@ 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)

@ -4,13 +4,14 @@ 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/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
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")
@ -27,7 +28,6 @@ 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,7 +35,6 @@ 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"`
@ -105,7 +104,6 @@ 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"`
@ -130,7 +128,6 @@ 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"`
@ -144,16 +141,6 @@ func TestTranslations(t *testing.T) {
UniqueSlice []string `validate:"unique"` UniqueSlice []string `validate:"unique"`
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"`
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"`
CveString string `validate:"cve"`
} }
var test Test var test Test
@ -196,20 +183,12 @@ 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.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.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)
@ -229,10 +208,6 @@ 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",
@ -337,10 +312,6 @@ 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",
@ -605,10 +576,6 @@ 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",
@ -665,42 +632,6 @@ func TestTranslations(t *testing.T) {
ns: "Test.UniqueMap", ns: "Test.UniqueMap",
expected: "UniqueMap must contain unique values", expected: "UniqueMap must contain unique values",
}, },
{
ns: "Test.JSONString",
expected: "JSONString must be a valid json string",
},
{
ns: "Test.JWTString",
expected: "JWTString must be a valid jwt string",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseString must be a lowercase string",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseString must be an uppercase string",
},
{
ns: "Test.Datetime",
expected: "Datetime does not match the 2006-01-02 format",
},
{
ns: "Test.PostCode",
expected: "PostCode does not match postcode format of SG country",
},
{
ns: "Test.PostCodeByField",
expected: "PostCodeByField does not match postcode format of country in PostCodeCountry field",
},
{
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 {
@ -717,4 +648,5 @@ 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))
} }
} }

File diff suppressed because it is too large Load Diff

@ -1,658 +0,0 @@
package es
import (
"testing"
"time"
. "github.com/go-playground/assert/v2"
spanish "github.com/go-playground/locales/es"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
spa := spanish.New()
uni := ut.New(spa, spa)
trans, _ := uni.GetTranslator("es")
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"`
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"`
}
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"
s := "toolong"
test.StrPtrMaxLen = &s
test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
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 debe ser un color válido",
},
{
ns: "Test.MAC",
expected: "MAC debe contener una dirección MAC válida",
},
{
ns: "Test.IPAddr",
expected: "IPAddr debe ser una dirección IP resoluble",
},
{
ns: "Test.IPAddrv4",
expected: "IPAddrv4 debe ser una dirección IPv4 resoluble",
},
{
ns: "Test.IPAddrv6",
expected: "IPAddrv6 debe ser una dirección IPv6 resoluble",
},
{
ns: "Test.UDPAddr",
expected: "UDPAddr debe ser una dirección UDP válida",
},
{
ns: "Test.UDPAddrv4",
expected: "UDPAddrv4 debe ser una dirección IPv4 UDP válida",
},
{
ns: "Test.UDPAddrv6",
expected: "UDPAddrv6 debe ser una dirección IPv6 UDP válida",
},
{
ns: "Test.TCPAddr",
expected: "TCPAddr debe ser una dirección TCP válida",
},
{
ns: "Test.TCPAddrv4",
expected: "TCPAddrv4 debe ser una dirección IPv4 TCP válida",
},
{
ns: "Test.TCPAddrv6",
expected: "TCPAddrv6 debe ser una dirección IPv6 TCP válida",
},
{
ns: "Test.CIDR",
expected: "CIDR debe contener una anotación válida del CIDR",
},
{
ns: "Test.CIDRv4",
expected: "CIDRv4 debe contener una notación CIDR válida para una dirección IPv4",
},
{
ns: "Test.CIDRv6",
expected: "CIDRv6 debe contener una notación CIDR válida para una dirección IPv6",
},
{
ns: "Test.SSN",
expected: "SSN debe ser un número válido de SSN",
},
{
ns: "Test.IP",
expected: "IP debe ser una dirección IP válida",
},
{
ns: "Test.IPv4",
expected: "IPv4 debe ser una dirección IPv4 válida",
},
{
ns: "Test.IPv6",
expected: "IPv6 debe ser una dirección IPv6 válida",
},
{
ns: "Test.DataURI",
expected: "DataURI debe contener un URI de datos válido",
},
{
ns: "Test.Latitude",
expected: "Latitude debe contener coordenadas de latitud válidas",
},
{
ns: "Test.Longitude",
expected: "Longitude debe contener unas coordenadas de longitud válidas",
},
{
ns: "Test.MultiByte",
expected: "MultiByte debe contener caracteres multibyte",
},
{
ns: "Test.ASCII",
expected: "ASCII debe contener sólo caracteres ascii",
},
{
ns: "Test.PrintableASCII",
expected: "PrintableASCII debe contener sólo caracteres ASCII imprimibles",
},
{
ns: "Test.UUID",
expected: "UUID debe ser un UUID válido",
},
{
ns: "Test.UUID3",
expected: "UUID3 debe ser una versión válida 3 UUID",
},
{
ns: "Test.UUID4",
expected: "UUID4 debe ser una versión válida 4 UUID",
},
{
ns: "Test.UUID5",
expected: "UUID5 debe ser una versión válida 5 UUID",
},
{
ns: "Test.ULID",
expected: "ULID debe ser un ULID válido",
},
{
ns: "Test.ISBN",
expected: "ISBN debe ser un número ISBN válido",
},
{
ns: "Test.ISBN10",
expected: "ISBN10 debe ser un número ISBN-10 válido",
},
{
ns: "Test.ISBN13",
expected: "ISBN13 debe ser un número ISBN-13 válido",
},
{
ns: "Test.Excludes",
expected: "Excludes no puede contener el texto 'text'",
},
{
ns: "Test.ExcludesAll",
expected: "ExcludesAll no puede contener ninguno de los siguientes caracteres '!@#$'",
},
{
ns: "Test.ExcludesRune",
expected: "ExcludesRune no puede contener lo siguiente '☻'",
},
{
ns: "Test.ContainsAny",
expected: "ContainsAny debe contener al menos uno de los siguientes caracteres '!@#$'",
},
{
ns: "Test.Contains",
expected: "Contains debe contener el texto 'purpose'",
},
{
ns: "Test.Base64",
expected: "Base64 debe ser una cadena de Base64 válida",
},
{
ns: "Test.Email",
expected: "Email debe ser una dirección de correo electrónico válida",
},
{
ns: "Test.URL",
expected: "URL debe ser un URL válido",
},
{
ns: "Test.URI",
expected: "URI debe ser una URI válida",
},
{
ns: "Test.RGBColorString",
expected: "RGBColorString debe ser un color RGB válido",
},
{
ns: "Test.RGBAColorString",
expected: "RGBAColorString debe ser un color RGBA válido",
},
{
ns: "Test.HSLColorString",
expected: "HSLColorString debe ser un color HSL válido",
},
{
ns: "Test.HSLAColorString",
expected: "HSLAColorString debe ser un color HSL válido",
},
{
ns: "Test.HexadecimalString",
expected: "HexadecimalString debe ser un hexadecimal válido",
},
{
ns: "Test.HexColorString",
expected: "HexColorString debe ser un color HEX válido",
},
{
ns: "Test.NumberString",
expected: "NumberString debe ser un número válido",
},
{
ns: "Test.NumericString",
expected: "NumericString debe ser un valor numérico válido",
},
{
ns: "Test.AlphanumString",
expected: "AlphanumString sólo puede contener caracteres alfanuméricos",
},
{
ns: "Test.AlphaString",
expected: "AlphaString sólo puede contener caracteres alfabéticos",
},
{
ns: "Test.LtFieldString",
expected: "LtFieldString debe ser menor que MaxString",
},
{
ns: "Test.LteFieldString",
expected: "LteFieldString debe ser menor o igual a MaxString",
},
{
ns: "Test.GtFieldString",
expected: "GtFieldString debe ser mayor que MaxString",
},
{
ns: "Test.GteFieldString",
expected: "GteFieldString debe ser mayor o igual a MaxString",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString no puede ser igual a EqFieldString",
},
{
ns: "Test.LtCSFieldString",
expected: "LtCSFieldString debe ser menor que Inner.LtCSFieldString",
},
{
ns: "Test.LteCSFieldString",
expected: "LteCSFieldString debe ser menor o igual a Inner.LteCSFieldString",
},
{
ns: "Test.GtCSFieldString",
expected: "GtCSFieldString debe ser mayor que Inner.GtCSFieldString",
},
{
ns: "Test.GteCSFieldString",
expected: "GteCSFieldString debe ser mayor o igual a Inner.GteCSFieldString",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString no puede ser igual a Inner.NeCSFieldString",
},
{
ns: "Test.EqCSFieldString",
expected: "EqCSFieldString debe ser igual a Inner.EqCSFieldString",
},
{
ns: "Test.EqFieldString",
expected: "EqFieldString debe ser igual a MaxString",
},
{
ns: "Test.GteString",
expected: "GteString debe tener al menos 3 caracteres de longitud",
},
{
ns: "Test.GteNumber",
expected: "GteNumber debe ser 5,56 o mayor",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple debe contener al menos 2 elementos",
},
{
ns: "Test.GteTime",
expected: "GteTime debe ser después o durante la fecha y hora actuales",
},
{
ns: "Test.GtString",
expected: "GtString debe ser mayor que 3 caracteres en longitud",
},
{
ns: "Test.GtNumber",
expected: "GtNumber debe ser mayor que 5,56",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple debe contener más de 2 elementos",
},
{
ns: "Test.GtTime",
expected: "GtTime debe ser después de la fecha y hora actual",
},
{
ns: "Test.LteString",
expected: "LteString debe tener un máximo de 3 caracteres de longitud",
},
{
ns: "Test.LteNumber",
expected: "LteNumber debe ser 5,56 o menos",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple debe contener como máximo 2 elementos",
},
{
ns: "Test.LteTime",
expected: "LteTime debe ser antes o durante la fecha y hora actual",
},
{
ns: "Test.LtString",
expected: "LtString debe tener menos de 3 caracteres de longitud",
},
{
ns: "Test.LtNumber",
expected: "LtNumber debe ser menos de 5,56",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple debe contener menos de 2 elementos",
},
{
ns: "Test.LtTime",
expected: "LtTime debe ser antes de la fecha y hora actual",
},
{
ns: "Test.NeString",
expected: "NeString no debería ser igual a ",
},
{
ns: "Test.NeNumber",
expected: "NeNumber no debería ser igual a 0.00",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple no debería ser igual a 0",
},
{
ns: "Test.EqString",
expected: "EqString no es igual a 3",
},
{
ns: "Test.EqNumber",
expected: "EqNumber no es igual a 2.33",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple no es igual a 7",
},
{
ns: "Test.MaxString",
expected: "MaxString debe tener un máximo de 3 caracteres de longitud",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber debe ser 1.113,00 o menos",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple debe contener como máximo 7 elementos",
},
{
ns: "Test.MinString",
expected: "MinString debe tener al menos 1 carácter de longitud",
},
{
ns: "Test.MinNumber",
expected: "MinNumber debe ser 1.113,00 o más",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple debe contener al menos 7 elementos",
},
{
ns: "Test.LenString",
expected: "LenString debe tener 1 carácter de longitud",
},
{
ns: "Test.LenNumber",
expected: "LenNumber debe ser igual a 1.113,00",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple debe contener 7 elementos",
},
{
ns: "Test.RequiredString",
expected: "RequiredString es un campo requerido",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber es un campo requerido",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple es un campo requerido",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen debe tener al menos 10 caracteres de longitud",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen debe tener un máximo de 1 carácter de longitud",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen debe tener 2 caracteres de longitud",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt debe tener menos de 1 carácter de longitud",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte debe tener un máximo de 1 carácter de longitud",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt debe ser mayor que 10 caracteres en longitud",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte debe tener al menos 10 caracteres de longitud",
},
{
ns: "Test.OneOfString",
expected: "OneOfString debe ser uno de [red green]",
},
{
ns: "Test.OneOfInt",
expected: "OneOfInt debe ser uno de [5 63]",
},
{
ns: "Test.UniqueSlice",
expected: "UniqueSlice debe contener valores únicos",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArray debe contener valores únicos",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMap debe contener valores únicos",
},
}
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))
}
}

File diff suppressed because it is too large Load Diff

@ -1,690 +0,0 @@
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))
}
}

@ -10,7 +10,7 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
@ -1173,11 +1173,6 @@ 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,10 +4,10 @@ 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/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
@ -104,7 +104,6 @@ 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"`
@ -307,10 +306,6 @@ 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",
@ -541,7 +536,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MaxNumber", ns: "Test.MaxNumber",
expected: "MaxNumber doit être égal à 1113,00 ou moins", expected: "MaxNumber doit être égal à 1 113,00 ou moins",
}, },
{ {
ns: "Test.MaxMultiple", ns: "Test.MaxMultiple",
@ -553,7 +548,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.MinNumber", ns: "Test.MinNumber",
expected: "MinNumber doit être égal à 1113,00 ou plus", expected: "MinNumber doit être égal à 1 113,00 ou plus",
}, },
{ {
ns: "Test.MinMultiple", ns: "Test.MinMultiple",
@ -565,7 +560,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.LenNumber", ns: "Test.LenNumber",
expected: "LenNumber doit être égal à 1113,00", expected: "LenNumber doit être égal à 1 113,00",
}, },
{ {
ns: "Test.LenMultiple", ns: "Test.LenMultiple",

@ -10,7 +10,7 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
@ -1173,11 +1173,6 @@ 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,10 +4,10 @@ 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/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
@ -104,7 +104,6 @@ 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"`
@ -307,10 +306,6 @@ 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

@ -1,725 +0,0 @@
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))
}
}

@ -10,12 +10,13 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// 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
@ -28,14 +29,10 @@ 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
} }
@ -67,6 +64,7 @@ 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
@ -125,6 +123,7 @@ 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
} }
@ -137,7 +136,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
} }
@ -156,6 +155,7 @@ 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,6 +214,7 @@ 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
} }
@ -226,7 +227,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
} }
@ -306,6 +307,7 @@ 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)
@ -372,6 +374,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
if err != nil { if err != nil {
goto END goto END
} }
t, err = ut.T("ne-items", fe.Field(), c) t, err = ut.T("ne-items", fe.Field(), c)
default: default:
t, err = ut.T("ne", fe.Field(), fe.Param()) t, err = ut.T("ne", fe.Field(), fe.Param())
@ -389,6 +392,7 @@ 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
} }
@ -509,6 +513,7 @@ 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
} }
@ -521,7 +526,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
} }
@ -628,6 +633,7 @@ 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
} }
@ -747,6 +753,7 @@ 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
} }
@ -759,7 +766,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
} }
@ -868,6 +875,7 @@ 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)
@ -882,6 +890,7 @@ 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)
@ -896,6 +905,7 @@ 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)
@ -910,6 +920,7 @@ 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)
@ -924,6 +935,7 @@ 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)
@ -938,6 +950,7 @@ 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)
@ -952,6 +965,7 @@ 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)
@ -966,6 +980,7 @@ 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)
@ -980,6 +995,7 @@ 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,6 +1010,7 @@ 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)
@ -1008,6 +1025,7 @@ 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)
@ -1022,6 +1040,7 @@ 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)
@ -1106,6 +1125,7 @@ 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)
@ -1120,6 +1140,7 @@ 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)
@ -1134,6 +1155,7 @@ 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)
@ -1148,6 +1170,7 @@ 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)
@ -1162,6 +1185,7 @@ 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)
@ -1203,12 +1227,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
}, },
{ {
tag: "uuid5", tag: "uuid5",
translation: "{0}はバージョンが5の正しいUUIDでなければなりません", translation: "{0}はバージョンが4の正しいUUIDでなければなりません",
override: false,
},
{
tag: "ulid",
translation: "{0}は正しいULIDでなければなりません",
override: false, override: false,
}, },
{ {
@ -1331,11 +1350,6 @@ 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}は正しい色でなければなりません",
@ -1354,83 +1368,22 @@ 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)
} }
@ -1444,7 +1397,9 @@ 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
} }
@ -1456,6 +1411,7 @@ 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,13 +4,14 @@ 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/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
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")
@ -27,131 +28,116 @@ 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"`
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"` 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"`
NumericString string `validate:"numeric"` NumberString string `validate:"number"`
NumberString string `validate:"number"` HexadecimalString string `validate:"hexadecimal"`
HexadecimalString string `validate:"hexadecimal"` HexColorString string `validate:"hexcolor"`
HexColorString string `validate:"hexcolor"` RGBColorString string `validate:"rgb"`
RGBColorString string `validate:"rgb"` RGBAColorString string `validate:"rgba"`
RGBAColorString string `validate:"rgba"` HSLColorString string `validate:"hsl"`
HSLColorString string `validate:"hsl"` HSLAColorString string `validate:"hsla"`
HSLAColorString string `validate:"hsla"` Email string `validate:"email"`
Email string `validate:"email"` URL string `validate:"url"`
URL string `validate:"url"` URI string `validate:"uri"`
URI string `validate:"uri"` Base64 string `validate:"base64"`
Base64 string `validate:"base64"` Contains string `validate:"contains=purpose"`
Contains string `validate:"contains=purpose"` ContainsAny string `validate:"containsany=!@#$"`
ContainsAny string `validate:"containsany=!@#$"` Excludes string `validate:"excludes=text"`
Excludes string `validate:"excludes=text"` ExcludesAll string `validate:"excludesall=!@#$"`
ExcludesAll string `validate:"excludesall=!@#$"` ExcludesRune string `validate:"excludesrune=☻"`
ExcludesRune string `validate:"excludesrune=☻"` ISBN string `validate:"isbn"`
ISBN string `validate:"isbn"` ISBN10 string `validate:"isbn10"`
ISBN10 string `validate:"isbn10"` ISBN13 string `validate:"isbn13"`
ISBN13 string `validate:"isbn13"` UUID string `validate:"uuid"`
UUID string `validate:"uuid"` UUID3 string `validate:"uuid3"`
UUID3 string `validate:"uuid3"` UUID4 string `validate:"uuid4"`
UUID4 string `validate:"uuid4"` UUID5 string `validate:"uuid5"`
UUID5 string `validate:"uuid5"` ASCII string `validate:"ascii"`
ULID string `validate:"ulid"` PrintableASCII string `validate:"printascii"`
ASCII string `validate:"ascii"` MultiByte string `validate:"multibyte"`
PrintableASCII string `validate:"printascii"` DataURI string `validate:"datauri"`
MultiByte string `validate:"multibyte"` Latitude string `validate:"latitude"`
DataURI string `validate:"datauri"` Longitude string `validate:"longitude"`
Latitude string `validate:"latitude"` SSN string `validate:"ssn"`
Longitude string `validate:"longitude"` IP string `validate:"ip"`
SSN string `validate:"ssn"` IPv4 string `validate:"ipv4"`
IP string `validate:"ip"` IPv6 string `validate:"ipv6"`
IPv4 string `validate:"ipv4"` CIDR string `validate:"cidr"`
IPv6 string `validate:"ipv6"` CIDRv4 string `validate:"cidrv4"`
CIDR string `validate:"cidr"` CIDRv6 string `validate:"cidrv6"`
CIDRv4 string `validate:"cidrv4"` TCPAddr string `validate:"tcp_addr"`
CIDRv6 string `validate:"cidrv6"` TCPAddrv4 string `validate:"tcp4_addr"`
TCPAddr string `validate:"tcp_addr"` TCPAddrv6 string `validate:"tcp6_addr"`
TCPAddrv4 string `validate:"tcp4_addr"` UDPAddr string `validate:"udp_addr"`
TCPAddrv6 string `validate:"tcp6_addr"` UDPAddrv4 string `validate:"udp4_addr"`
UDPAddr string `validate:"udp_addr"` UDPAddrv6 string `validate:"udp6_addr"`
UDPAddrv4 string `validate:"udp4_addr"` IPAddr string `validate:"ip_addr"`
UDPAddrv6 string `validate:"udp6_addr"` IPAddrv4 string `validate:"ip4_addr"`
IPAddr string `validate:"ip_addr"` IPAddrv6 string `validate:"ip6_addr"`
IPAddrv4 string `validate:"ip4_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
IPAddrv6 string `validate:"ip6_addr"` MAC string `validate:"mac"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future IsColor string `validate:"iscolor"`
MAC string `validate:"mac"` StrPtrMinLen *string `validate:"min=10"`
IsColor string `validate:"iscolor"` StrPtrMaxLen *string `validate:"max=1"`
StrPtrMinLen *string `validate:"min=10"` StrPtrLen *string `validate:"len=2"`
StrPtrMaxLen *string `validate:"max=1"` StrPtrLt *string `validate:"lt=1"`
StrPtrLen *string `validate:"len=2"` StrPtrLte *string `validate:"lte=1"`
StrPtrLt *string `validate:"lt=1"` StrPtrGt *string `validate:"gt=10"`
StrPtrLte *string `validate:"lte=1"` StrPtrGte *string `validate:"gte=10"`
StrPtrGt *string `validate:"gt=10"` OneOfString string `validate:"oneof=red green"`
StrPtrGte *string `validate:"gte=10"` OneOfInt int `validate:"oneof=5 63"`
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
@ -194,20 +180,10 @@ 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)
@ -328,11 +304,7 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.UUID5", ns: "Test.UUID5",
expected: "UUID5はバージョンが5の正しいUUIDでなければなりません", expected: "UUID5はバージョンが4の正しいUUIDでなければなりません",
},
{
ns: "Test.ULID",
expected: "ULIDは正しいULIDでなければなりません",
}, },
{ {
ns: "Test.ISBN", ns: "Test.ISBN",
@ -476,7 +448,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",
@ -508,7 +480,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",
@ -564,7 +536,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",
@ -576,7 +548,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",
@ -598,10 +570,6 @@ 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は必須フィールドです",
@ -646,50 +614,6 @@ 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

@ -1,709 +0,0 @@
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))
}
}

@ -10,7 +10,7 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
@ -1173,11 +1173,6 @@ 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,10 +4,10 @@ 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/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
@ -104,7 +104,6 @@ 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"`
@ -307,10 +306,6 @@ 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",

File diff suppressed because it is too large Load Diff

@ -1,682 +0,0 @@
package pt
import (
"testing"
"time"
. "github.com/go-playground/assert/v2"
"github.com/go-playground/locales/pt"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
pt := pt.New()
uni := ut.New(pt, pt)
trans, _ := uni.GetTranslator("pt")
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"`
}
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 deve ser uma cor válida",
},
{
ns: "Test.MAC",
expected: "MAC deve conter um endereço MAC válido",
},
{
ns: "Test.IPAddr",
expected: "IPAddr deve ser um endereço IP resolvível",
},
{
ns: "Test.IPAddrv4",
expected: "IPAddrv4 deve ser um endereço IPv4 resolvível",
},
{
ns: "Test.IPAddrv6",
expected: "IPAddrv6 deve ser um endereço IPv6 resolvível",
},
{
ns: "Test.UDPAddr",
expected: "UDPAddr deve ser um endereço UDP válido",
},
{
ns: "Test.UDPAddrv4",
expected: "UDPAddrv4 deve ser um endereço UDP IPv4 válido",
},
{
ns: "Test.UDPAddrv6",
expected: "UDPAddrv6 deve ser um endereço UDP IPv6 válido",
},
{
ns: "Test.TCPAddr",
expected: "TCPAddr deve ser um endereço TCP válido",
},
{
ns: "Test.TCPAddrv4",
expected: "TCPAddrv4 deve ser um endereço TCP IPv4 válido",
},
{
ns: "Test.TCPAddrv6",
expected: "TCPAddrv6 deve ser um endereço TCP IPv6 válido",
},
{
ns: "Test.CIDR",
expected: "CIDR não respeita a notação CIDR",
},
{
ns: "Test.CIDRv4",
expected: "CIDRv4 não respeita a notação CIDR para um endereço IPv4",
},
{
ns: "Test.CIDRv6",
expected: "CIDRv6 não respeita a notação CIDR para um endereço IPv6",
},
{
ns: "Test.SSN",
expected: "SSN deve ser um número SSN válido",
},
{
ns: "Test.IP",
expected: "IP deve ser um endereço IP válido",
},
{
ns: "Test.IPv4",
expected: "IPv4 deve ser um endereço IPv4 válido",
},
{
ns: "Test.IPv6",
expected: "IPv6 deve ser um endereço IPv6 válido",
},
{
ns: "Test.DataURI",
expected: "DataURI deve conter um Data URI válido",
},
{
ns: "Test.Latitude",
expected: "Latitude deve conter uma coordenada de latitude válida",
},
{
ns: "Test.Longitude",
expected: "Longitude deve conter uma coordenada de longitude válida",
},
{
ns: "Test.MultiByte",
expected: "MultiByte deve conter caracteres multibyte",
},
{
ns: "Test.ASCII",
expected: "ASCII deve conter apenas caracteres ascii",
},
{
ns: "Test.PrintableASCII",
expected: "PrintableASCII deve conter apenas caracteres ascii imprimíveis",
},
{
ns: "Test.UUID",
expected: "UUID deve ser um UUID válido",
},
{
ns: "Test.UUID3",
expected: "UUID3 deve ser um UUID versão 3 válido",
},
{
ns: "Test.UUID4",
expected: "UUID4 deve ser um UUID versão 4 válido",
},
{
ns: "Test.UUID5",
expected: "UUID5 deve ser um UUID versão 5 válido",
},
{
ns: "Test.ULID",
expected: "ULID deve ser um ULID válido",
},
{
ns: "Test.ISBN",
expected: "ISBN deve ser um número de ISBN válido",
},
{
ns: "Test.ISBN10",
expected: "ISBN10 deve ser um número ISBN-10 válido",
},
{
ns: "Test.ISBN13",
expected: "ISBN13 deve ser um número ISBN-13 válido",
},
{
ns: "Test.Excludes",
expected: "Excludes não deve conter o texto 'text'",
},
{
ns: "Test.ExcludesAll",
expected: "ExcludesAll não deve conter os seguintes caracteres '!@#$'",
},
{
ns: "Test.ExcludesRune",
expected: "ExcludesRune não pode conter o seguinte '☻'",
},
{
ns: "Test.ContainsAny",
expected: "ContainsAny deve conter pelo menos um dos seguintes caracteres '!@#$'",
},
{
ns: "Test.Contains",
expected: "Contains deve conter o texto 'purpose'",
},
{
ns: "Test.Base64",
expected: "Base64 deve ser uma string Base64 válida",
},
{
ns: "Test.Email",
expected: "Email deve ser um endereço de e-mail válido",
},
{
ns: "Test.URL",
expected: "URL deve ser um URL válido",
},
{
ns: "Test.URI",
expected: "URI deve ser um URI válido",
},
{
ns: "Test.RGBColorString",
expected: "RGBColorString deve ser uma cor RGB válida",
},
{
ns: "Test.RGBAColorString",
expected: "RGBAColorString deve ser uma cor RGBA válida",
},
{
ns: "Test.HSLColorString",
expected: "HSLColorString deve ser uma cor HSL válida",
},
{
ns: "Test.HSLAColorString",
expected: "HSLAColorString deve ser uma cor HSLA válida",
},
{
ns: "Test.HexadecimalString",
expected: "HexadecimalString deve ser um hexadecimal válido",
},
{
ns: "Test.HexColorString",
expected: "HexColorString deve ser uma cor HEX válida",
},
{
ns: "Test.NumberString",
expected: "NumberString deve ser um número válido",
},
{
ns: "Test.NumericString",
expected: "NumericString deve ser um valor numérico válido",
},
{
ns: "Test.AlphanumString",
expected: "AlphanumString deve conter apenas caracteres alfanuméricos",
},
{
ns: "Test.AlphaString",
expected: "AlphaString deve conter apenas caracteres alfabéticos",
},
{
ns: "Test.LtFieldString",
expected: "LtFieldString deve ser menor que MaxString",
},
{
ns: "Test.LteFieldString",
expected: "LteFieldString deve ser menor ou igual que MaxString",
},
{
ns: "Test.GtFieldString",
expected: "GtFieldString deve ser maior que MaxString",
},
{
ns: "Test.GteFieldString",
expected: "GteFieldString deve ser maior ou igual que MaxString",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString não deve ser igual a EqFieldString",
},
{
ns: "Test.LtCSFieldString",
expected: "LtCSFieldString deve ser menor que Inner.LtCSFieldString",
},
{
ns: "Test.LteCSFieldString",
expected: "LteCSFieldString deve ser menor ou igual que Inner.LteCSFieldString",
},
{
ns: "Test.GtCSFieldString",
expected: "GtCSFieldString deve ser maior que Inner.GtCSFieldString",
},
{
ns: "Test.GteCSFieldString",
expected: "GteCSFieldString deve ser maior ou igual que Inner.GteCSFieldString",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString não deve ser igual a Inner.NeCSFieldString",
},
{
ns: "Test.EqCSFieldString",
expected: "EqCSFieldString deve ser igual a Inner.EqCSFieldString",
},
{
ns: "Test.EqFieldString",
expected: "EqFieldString deve ser igual a MaxString",
},
{
ns: "Test.GteString",
expected: "GteString deve ter pelo menos 3 caracteres",
},
{
ns: "Test.GteNumber",
expected: "GteNumber deve ser maior ou igual a 5,56",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple deve conter pelo menos 2 items",
},
{
ns: "Test.GteTime",
expected: "GteTime deve ser posterior ou igual à data/hora atual",
},
{
ns: "Test.GtString",
expected: "GtString deve conter mais de 3 caracteres",
},
{
ns: "Test.GtNumber",
expected: "GtNumber deve ser maior que 5,56",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple deve conter mais de 2 items",
},
{
ns: "Test.GtTime",
expected: "GtTime deve ser posterior à data/hora atual",
},
{
ns: "Test.LteString",
expected: "LteString deve ter no máximo 3 caracteres",
},
{
ns: "Test.LteNumber",
expected: "LteNumber deve ser menor ou igual a 5,56",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple deve conter no máximo 2 items",
},
{
ns: "Test.LteTime",
expected: "LteTime deve ser anterior ou igual à data/hora atual",
},
{
ns: "Test.LtString",
expected: "LtString deve ter menos de 3 caracteres",
},
{
ns: "Test.LtNumber",
expected: "LtNumber deve ser menor que 5,56",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple deve conter menos de 2 items",
},
{
ns: "Test.LtTime",
expected: "LtTime deve ser anterior à data / hora atual",
},
{
ns: "Test.NeString",
expected: "NeString não deve ser igual a ",
},
{
ns: "Test.NeNumber",
expected: "NeNumber não deve ser igual a 0.00",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple não deve ser igual a 0",
},
{
ns: "Test.EqString",
expected: "EqString não é igual a 3",
},
{
ns: "Test.EqNumber",
expected: "EqNumber não é igual a 2.33",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple não é igual a 7",
},
{
ns: "Test.MaxString",
expected: "MaxString deve ter no máximo 3 caracteres",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber deve ser 1.113,00 ou menos",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple deve conter no máximo 7 items",
},
{
ns: "Test.MinString",
expected: "MinString deve ter pelo menos 1 caractere",
},
{
ns: "Test.MinNumber",
expected: "MinNumber deve ser 1.113,00 ou superior",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple deve conter pelo menos 7 items",
},
{
ns: "Test.LenString",
expected: "LenString deve ter 1 caractere",
},
{
ns: "Test.LenNumber",
expected: "LenNumber deve ser igual a 1.113,00",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple deve conter 7 items",
},
{
ns: "Test.RequiredString",
expected: "RequiredString é obrigatório",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber é obrigatório",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple é obrigatório",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen deve ter pelo menos 10 caracteres",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen deve ter no máximo 1 caractere",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen deve ter 2 caracteres",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt deve ter menos de 1 caractere",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte deve ter no máximo 1 caractere",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt deve conter mais de 10 caracteres",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte deve ter pelo menos 10 caracteres",
},
{
ns: "Test.OneOfString",
expected: "OneOfString deve ser um de [red green]",
},
{
ns: "Test.OneOfInt",
expected: "OneOfInt deve ser um de [5 63]",
},
{
ns: "Test.UniqueSlice",
expected: "UniqueSlice deve conter valores únicos",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArray deve conter valores únicos",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMap deve conter valores únicos",
},
{
ns: "Test.JSONString",
expected: "JSONString deve ser uma string json válida",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseString deve estar em minuscúlas",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseString deve estar em maiúsculas",
},
{
ns: "Test.Datetime",
expected: "Datetime não está no formato 2006-01-02",
},
}
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))
}
}

@ -10,7 +10,7 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
@ -26,7 +26,7 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
}{ }{
{ {
tag: "required", tag: "required",
translation: "{0} é um campo obrigatório", translation: "{0} é um campo requerido",
override: false, override: false,
}, },
{ {
@ -1173,11 +1173,6 @@ 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",
@ -1316,16 +1311,6 @@ 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" "gopkg.in/go-playground/validator.v9"
. "gopkg.in/go-playground/assert.v1"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
@ -104,7 +104,6 @@ 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"`
@ -139,8 +138,6 @@ 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
@ -173,8 +170,6 @@ 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!"
@ -311,10 +306,6 @@ 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",
@ -577,15 +568,15 @@ func TestTranslations(t *testing.T) {
}, },
{ {
ns: "Test.RequiredString", ns: "Test.RequiredString",
expected: "RequiredString é um campo obrigatório", expected: "RequiredString é um campo requerido",
}, },
{ {
ns: "Test.RequiredNumber", ns: "Test.RequiredNumber",
expected: "RequiredNumber é um campo obrigatório", expected: "RequiredNumber é um campo requerido",
}, },
{ {
ns: "Test.RequiredMultiple", ns: "Test.RequiredMultiple",
expected: "RequiredMultiple é um campo obrigatório", expected: "RequiredMultiple é um campo requerido",
}, },
{ {
ns: "Test.StrPtrMinLen", ns: "Test.StrPtrMinLen",
@ -623,14 +614,6 @@ 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 {

File diff suppressed because it is too large Load Diff

@ -1,767 +0,0 @@
package ru
import (
"log"
//"github.com/rustery/validator"
"testing"
"time"
. "github.com/go-playground/assert/v2"
russian "github.com/go-playground/locales/ru"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
ru := russian.New()
uni := ut.New(ru, ru)
trans, _ := uni.GetTranslator("ru")
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"`
LenMultipleSecond []string `validate:"len=2"`
MinString string `validate:"min=1"`
MinStringMultiple string `validate:"min=2"`
MinStringMultipleSecond string `validate:"min=7"`
MinNumber float64 `validate:"min=1113.00"`
MinMultiple []string `validate:"min=7"`
MinMultipleSecond []string `validate:"min=2"`
MaxString string `validate:"max=3"`
MaxStringSecond string `validate:"max=7"`
MaxNumber float64 `validate:"max=1113.00"`
MaxMultiple []string `validate:"max=7"`
MaxMultipleSecond []string `validate:"max=2"`
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"`
LtStringSecond string `validate:"lt=7"`
LtNumber float64 `validate:"lt=5.56"`
LtMultiple []string `validate:"lt=2"`
LtMultipleSecond []string `validate:"lt=7"`
LtTime time.Time `validate:"lt"`
LteString string `validate:"lte=3"`
LteStringSecond string `validate:"lte=7"`
LteNumber float64 `validate:"lte=5.56"`
LteMultiple []string `validate:"lte=2"`
LteMultipleSecond []string `validate:"lte=7"`
LteTime time.Time `validate:"lte"`
GtString string `validate:"gt=3"`
GtStringSecond string `validate:"gt=7"`
GtNumber float64 `validate:"gt=5.56"`
GtMultiple []string `validate:"gt=2"`
GtMultipleSecond []string `validate:"gt=7"`
GtTime time.Time `validate:"gt"`
GteString string `validate:"gte=3"`
GteStringSecond string `validate:"gte=7"`
GteNumber float64 `validate:"gte=5.56"`
GteMultiple []string `validate:"gte=2"`
GteMultipleSecond []string `validate:"gte=7"`
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"`
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
test.Inner.EqCSFieldString = "1234"
test.Inner.GtCSFieldString = "1234"
test.Inner.GteCSFieldString = "1234"
test.MaxString = "1234"
test.MaxStringSecond = "12345678"
test.MaxNumber = 2000
test.MaxMultiple = make([]string, 9)
test.MaxMultipleSecond = make([]string, 3)
test.LtString = "1234"
test.LtStringSecond = "12345678"
test.LtNumber = 6
test.LtMultiple = make([]string, 3)
test.LtMultipleSecond = make([]string, 8)
test.LtTime = time.Now().Add(time.Hour * 24)
test.LteString = "1234"
test.LteStringSecond = "12345678"
test.LteNumber = 6
test.LteMultiple = make([]string, 3)
test.LteMultipleSecond = make([]string, 8)
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"
s := "toolong"
test.StrPtrMaxLen = &s
test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
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 должен быть распознаваемым IPv4 адресом",
},
{
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 должен содержать Data 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 должен быть email адресом",
},
{
ns: "Test.URL",
expected: "URL должен быть 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.GteStringSecond",
expected: "GteStringSecond должен содержать минимум 7 символов",
},
{
ns: "Test.GteNumber",
expected: "GteNumber должен быть больше или равно 5,56",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple должен содержать минимум 2 элемента",
},
{
ns: "Test.GteMultipleSecond",
expected: "GteMultipleSecond должен содержать минимум 7 элементов",
},
{
ns: "Test.GteTime",
expected: "GteTime должна быть позже или равна текущему моменту",
},
{
ns: "Test.GtString",
expected: "GtString должен быть длиннее 3 символов",
},
{
ns: "Test.GtStringSecond",
expected: "GtStringSecond должен быть длиннее 7 символов",
},
{
ns: "Test.GtNumber",
expected: "GtNumber должен быть больше 5,56",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple должен содержать более 2 элементов",
},
{
ns: "Test.GtMultipleSecond",
expected: "GtMultipleSecond должен содержать более 7 элементов",
},
{
ns: "Test.GtTime",
expected: "GtTime должна быть позже текущего момента",
},
{
ns: "Test.LteString",
expected: "LteString должен содержать максимум 3 символа",
},
{
ns: "Test.LteStringSecond",
expected: "LteStringSecond должен содержать максимум 7 символов",
},
{
ns: "Test.LteNumber",
expected: "LteNumber должен быть менее или равен 5,56",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple должен содержать максимум 2 элемента",
},
{
ns: "Test.LteMultipleSecond",
expected: "LteMultipleSecond должен содержать максимум 7 элементов",
},
{
ns: "Test.LteTime",
expected: "LteTime must be less than or equal to the current Date & Time",
},
{
ns: "Test.LtString",
expected: "LtString должен иметь менее 3 символов",
},
{
ns: "Test.LtStringSecond",
expected: "LtStringSecond должен иметь менее 7 символов",
},
{
ns: "Test.LtNumber",
expected: "LtNumber должен быть менее 5,56",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple должен содержать менее 2 элементов",
},
{
ns: "Test.LtMultipleSecond",
expected: "LtMultipleSecond должен содержать менее 7 элементов",
},
{
ns: "Test.LtTime",
expected: "LtTime must be less than the current Date & Time",
},
{
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.MaxStringSecond",
expected: "MaxStringSecond должен содержать максимум 7 символов",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber должен быть меньше или равно 1 113,00",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple должен содержать максимум 7 элементов",
},
{
ns: "Test.MaxMultipleSecond",
expected: "MaxMultipleSecond должен содержать максимум 2 элемента",
},
{
ns: "Test.MinString",
expected: "MinString должен содержать минимум 1 символ",
},
{
ns: "Test.MinStringMultiple",
expected: "MinStringMultiple должен содержать минимум 2 символа",
},
{
ns: "Test.MinStringMultipleSecond",
expected: "MinStringMultipleSecond должен содержать минимум 7 символов",
},
{
ns: "Test.MinNumber",
expected: "MinNumber должен быть больше или равно 1 113,00",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple должен содержать минимум 7 элементов",
},
{
ns: "Test.MinMultipleSecond",
expected: "MinMultipleSecond должен содержать минимум 2 элемента",
},
{
ns: "Test.LenString",
expected: "LenString должен быть длиной в 1 символ",
},
{
ns: "Test.LenNumber",
expected: "LenNumber должен быть равен 1 113,00",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple должен содержать 7 элементов",
},
{
ns: "Test.LenMultipleSecond",
expected: "LenMultipleSecond должен содержать 2 элемента",
},
{
ns: "Test.RequiredString",
expected: "RequiredString обязательное поле",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber обязательное поле",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple обязательное поле",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen должен содержать минимум 10 символов",
},
{
ns: "Test.StrPtrMinLenSecond",
expected: "StrPtrMinLenSecond должен содержать минимум 2 символа",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen должен содержать максимум 1 символ",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen должен быть длиной в 2 символа",
},
{
ns: "Test.StrPtrLenSecond",
expected: "StrPtrLenSecond должен быть длиной в 7 символов",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt должен иметь менее 1 символ",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte должен содержать максимум 1 символ",
},
{
ns: "Test.StrPtrLteMultiple",
expected: "StrPtrLteMultiple должен содержать максимум 2 символа",
},
{
ns: "Test.StrPtrLteMultipleSecond",
expected: "StrPtrLteMultipleSecond должен содержать максимум 7 символов",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt должен быть длиннее 10 символов",
},
{
ns: "Test.StrPtrGtSecond",
expected: "StrPtrGtSecond должен быть длиннее 2 символов",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte должен содержать минимум 10 символов",
},
{
ns: "Test.StrPtrGteSecond",
expected: "StrPtrGteSecond должен содержать минимум 2 символа",
},
{
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 должен содержать уникальные значения",
},
}
for _, tt := range tests {
var fe validator.FieldError
for _, e := range errs {
if tt.ns == e.Namespace() {
fe = e
break
}
}
log.Println(fe)
NotEqual(t, fe, nil)
Equal(t, tt.expected, fe.Translate(trans))
}
}

File diff suppressed because it is too large Load Diff

@ -1,657 +0,0 @@
package tr
import (
"testing"
"time"
. "github.com/go-playground/assert/v2"
turkish "github.com/go-playground/locales/tr"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
)
func TestTranslations(t *testing.T) {
tr := turkish.New()
uni := ut.New(tr, tr)
trans, _ := uni.GetTranslator("tr")
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"`
}
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"
s := "toolong"
test.StrPtrMaxLen = &s
test.StrPtrLen = &s
test.UniqueSlice = []string{"1234", "1234"}
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
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 geçerli bir renk olmalıdır",
},
{
ns: "Test.MAC",
expected: "MAC geçerli bir MAC adresi içermelidir",
},
{
ns: "Test.IPAddr",
expected: "IPAddr çözülebilir bir IP adresi olmalıdır",
},
{
ns: "Test.IPAddrv4",
expected: "IPAddrv4 çözülebilir bir IPv4 adresi olmalıdır",
},
{
ns: "Test.IPAddrv6",
expected: "IPAddrv6 çözülebilir bir IPv6 adresi olmalıdır",
},
{
ns: "Test.UDPAddr",
expected: "UDPAddr geçerli bir UDP adresi olmalıdır",
},
{
ns: "Test.UDPAddrv4",
expected: "UDPAddrv4 geçerli bir IPv4 UDP adresi olmalıdır",
},
{
ns: "Test.UDPAddrv6",
expected: "UDPAddrv6 geçerli bir IPv6 UDP adresi olmalıdır",
},
{
ns: "Test.TCPAddr",
expected: "TCPAddr geçerli bir TCP adresi olmalıdır",
},
{
ns: "Test.TCPAddrv4",
expected: "TCPAddrv4 geçerli bir IPv4 TCP adresi olmalıdır",
},
{
ns: "Test.TCPAddrv6",
expected: "TCPAddrv6 geçerli bir IPv6 TCP adresi olmalıdır",
},
{
ns: "Test.CIDR",
expected: "CIDR geçerli bir CIDR gösterimi içermelidir",
},
{
ns: "Test.CIDRv4",
expected: "CIDRv4 bir IPv4 adresi için geçerli bir CIDR gösterimi içermelidir",
},
{
ns: "Test.CIDRv6",
expected: "CIDRv6 bir IPv6 adresi için geçerli bir CIDR gösterimi içermelidir",
},
{
ns: "Test.SSN",
expected: "SSN geçerli bir SSN numarası olmalıdır",
},
{
ns: "Test.IP",
expected: "IP geçerli bir IP adresi olmalıdır",
},
{
ns: "Test.IPv4",
expected: "IPv4 geçerli bir IPv4 adresi olmalıdır",
},
{
ns: "Test.IPv6",
expected: "IPv6 geçerli bir IPv6 adresi olmalıdır",
},
{
ns: "Test.DataURI",
expected: "DataURI geçerli bir Veri URI içermelidir",
},
{
ns: "Test.Latitude",
expected: "Latitude geçerli bir enlem koordinatı içermelidir",
},
{
ns: "Test.Longitude",
expected: "Longitude geçerli bir boylam koordinatı içermelidir",
},
{
ns: "Test.MultiByte",
expected: "MultiByte çok baytlı karakterler içermelidir",
},
{
ns: "Test.ASCII",
expected: "ASCII yalnızca ascii karakterler içermelidir",
},
{
ns: "Test.PrintableASCII",
expected: "PrintableASCII yalnızca yazdırılabilir ascii karakterleri içermelidir",
},
{
ns: "Test.UUID",
expected: "UUID geçerli bir UUID olmalıdır",
},
{
ns: "Test.UUID3",
expected: "UUID3 geçerli bir sürüm 3 UUID olmalıdır",
},
{
ns: "Test.UUID4",
expected: "UUID4 geçerli bir sürüm 4 UUID olmalıdır",
},
{
ns: "Test.UUID5",
expected: "UUID5 geçerli bir sürüm 5 UUID olmalıdır",
},
{
ns: "Test.ULID",
expected: "ULID geçerli bir ULID olmalıdır",
},
{
ns: "Test.ISBN",
expected: "ISBN geçerli bir ISBN numarası olmalıdır",
},
{
ns: "Test.ISBN10",
expected: "ISBN10 geçerli bir ISBN-10 numarası olmalıdır",
},
{
ns: "Test.ISBN13",
expected: "ISBN13 geçerli bir ISBN-13 numarası olmalıdır",
},
{
ns: "Test.Excludes",
expected: "Excludes, 'text' metnini içeremez",
},
{
ns: "Test.ExcludesAll",
expected: "ExcludesAll, '!@#$' karakterlerinden hiçbirini içeremez",
},
{
ns: "Test.ExcludesRune",
expected: "ExcludesRune, '☻' ifadesini içeremez",
},
{
ns: "Test.ContainsAny",
expected: "ContainsAny, '!@#$' karakterlerinden en az birini içermelidir",
},
{
ns: "Test.Contains",
expected: "Contains, 'purpose' metnini içermelidir",
},
{
ns: "Test.Base64",
expected: "Base64 geçerli bir Base64 karakter dizesi olmalıdır",
},
{
ns: "Test.Email",
expected: "Email geçerli bir e-posta adresi olmalıdır",
},
{
ns: "Test.URL",
expected: "URL geçerli bir URL olmalıdır",
},
{
ns: "Test.URI",
expected: "URI geçerli bir URI olmalıdır",
},
{
ns: "Test.RGBColorString",
expected: "RGBColorString geçerli bir RGB rengi olmalıdır",
},
{
ns: "Test.RGBAColorString",
expected: "RGBAColorString geçerli bir RGBA rengi olmalıdır",
},
{
ns: "Test.HSLColorString",
expected: "HSLColorString geçerli bir HSL rengi olmalıdır",
},
{
ns: "Test.HSLAColorString",
expected: "HSLAColorString geçerli bir HSLA rengi olmalıdır",
},
{
ns: "Test.HexadecimalString",
expected: "HexadecimalString geçerli bir onaltılık olmalıdır",
},
{
ns: "Test.HexColorString",
expected: "HexColorString geçerli bir HEX rengi olmalıdır",
},
{
ns: "Test.NumberString",
expected: "NumberString geçerli bir sayı olmalıdır",
},
{
ns: "Test.NumericString",
expected: "NumericString geçerli bir sayısal değer olmalıdır",
},
{
ns: "Test.AlphanumString",
expected: "AlphanumString yalnızca alfanümerik karakterler içerebilir",
},
{
ns: "Test.AlphaString",
expected: "AlphaString yalnızca alfabetik karakterler içerebilir",
},
{
ns: "Test.LtFieldString",
expected: "LtFieldString, MaxString değerinden küçük olmalıdır",
},
{
ns: "Test.LteFieldString",
expected: "LteFieldString, MaxString değerinden küçük veya ona eşit olmalıdır",
},
{
ns: "Test.GtFieldString",
expected: "GtFieldString, MaxString değerinden büyük olmalıdır",
},
{
ns: "Test.GteFieldString",
expected: "GteFieldString, MaxString değerinden büyük veya ona eşit olmalıdır",
},
{
ns: "Test.NeFieldString",
expected: "NeFieldString, EqFieldString değerine eşit olmamalıdır",
},
{
ns: "Test.LtCSFieldString",
expected: "LtCSFieldString, Inner.LtCSFieldString değerinden küçük olmalıdır",
},
{
ns: "Test.LteCSFieldString",
expected: "LteCSFieldString, Inner.LteCSFieldString değerinden küçük veya ona eşit olmalıdır",
},
{
ns: "Test.GtCSFieldString",
expected: "GtCSFieldString, Inner.GtCSFieldString değerinden büyük olmalıdır",
},
{
ns: "Test.GteCSFieldString",
expected: "GteCSFieldString, Inner.GteCSFieldString değerinden küçük veya ona eşit olmalıdır",
},
{
ns: "Test.NeCSFieldString",
expected: "NeCSFieldString, Inner.NeCSFieldString değerine eşit olmamalıdır",
},
{
ns: "Test.EqCSFieldString",
expected: "EqCSFieldString, Inner.EqCSFieldString değerine eşit olmalıdır",
},
{
ns: "Test.EqFieldString",
expected: "EqFieldString, MaxString değerine eşit olmalıdır",
},
{
ns: "Test.GteString",
expected: "GteString en az 3 karakter uzunluğunda olmalıdır",
},
{
ns: "Test.GteNumber",
expected: "GteNumber, 5,56 veya daha büyük olmalıdır",
},
{
ns: "Test.GteMultiple",
expected: "GteMultiple en az 2 öğe içermelidir",
},
{
ns: "Test.GteTime",
expected: "GteTime geçerli Tarih ve Saatten büyük veya ona eşit olmalıdır",
},
{
ns: "Test.GtString",
expected: "GtString, 3 karakter uzunluğundan fazla olmalıdır",
},
{
ns: "Test.GtNumber",
expected: "GtNumber, 5,56 değerinden büyük olmalıdır",
},
{
ns: "Test.GtMultiple",
expected: "GtMultiple, 2 öğeden daha fazla içermelidir",
},
{
ns: "Test.GtTime",
expected: "GtTime geçerli Tarih ve Saatten büyük olmalıdır",
},
{
ns: "Test.LteString",
expected: "LteString en fazla 3 karakter uzunluğunda olmalıdır",
},
{
ns: "Test.LteNumber",
expected: "LteNumber, 5,56 veya daha az olmalıdır",
},
{
ns: "Test.LteMultiple",
expected: "LteMultiple, maksimum 2 öğe içermelidir",
},
{
ns: "Test.LteTime",
expected: "LteTime geçerli Tarih ve Saate eşit veya daha küçük olmalıdır",
},
{
ns: "Test.LtString",
expected: "LtString, 3 karakter uzunluğundan daha az olmalıdır",
},
{
ns: "Test.LtNumber",
expected: "LtNumber, 5,56 değerinden küçük olmalıdır",
},
{
ns: "Test.LtMultiple",
expected: "LtMultiple, 2 öğeden daha az içermelidir",
},
{
ns: "Test.LtTime",
expected: "LtTime geçerli Tarih ve Saatten daha az olmalıdır",
},
{
ns: "Test.NeString",
expected: "NeString, değerine eşit olmamalıdır",
},
{
ns: "Test.NeNumber",
expected: "NeNumber, 0.00 değerine eşit olmamalıdır",
},
{
ns: "Test.NeMultiple",
expected: "NeMultiple, 0 değerine eşit olmamalıdır",
},
{
ns: "Test.EqString",
expected: "EqString, 3 değerine eşit değil",
},
{
ns: "Test.EqNumber",
expected: "EqNumber, 2.33 değerine eşit değil",
},
{
ns: "Test.EqMultiple",
expected: "EqMultiple, 7 değerine eşit değil",
},
{
ns: "Test.MaxString",
expected: "MaxString uzunluğu en fazla 3 karakter olmalıdır",
},
{
ns: "Test.MaxNumber",
expected: "MaxNumber, 1.113,00 veya daha az olmalıdır",
},
{
ns: "Test.MaxMultiple",
expected: "MaxMultiple maksimum 7 öğe içermelidir",
},
{
ns: "Test.MinString",
expected: "MinString en az 1 karakter uzunluğunda olmalıdır",
},
{
ns: "Test.MinNumber",
expected: "MinNumber, 1.113,00 veya daha büyük olmalıdır",
},
{
ns: "Test.MinMultiple",
expected: "MinMultiple en az 7 öğe içermelidir",
},
{
ns: "Test.LenString",
expected: "LenString uzunluğu 1 karakter olmalıdır",
},
{
ns: "Test.LenNumber",
expected: "LenNumber, 1.113,00 değerine eşit olmalıdır",
},
{
ns: "Test.LenMultiple",
expected: "LenMultiple, 7 öğe içermelidir",
},
{
ns: "Test.RequiredString",
expected: "RequiredString zorunlu bir alandır",
},
{
ns: "Test.RequiredNumber",
expected: "RequiredNumber zorunlu bir alandır",
},
{
ns: "Test.RequiredMultiple",
expected: "RequiredMultiple zorunlu bir alandır",
},
{
ns: "Test.StrPtrMinLen",
expected: "StrPtrMinLen en az 10 karakter uzunluğunda olmalıdır",
},
{
ns: "Test.StrPtrMaxLen",
expected: "StrPtrMaxLen uzunluğu en fazla 1 karakter olmalıdır",
},
{
ns: "Test.StrPtrLen",
expected: "StrPtrLen uzunluğu 2 karakter olmalıdır",
},
{
ns: "Test.StrPtrLt",
expected: "StrPtrLt, 1 karakter uzunluğundan daha az olmalıdır",
},
{
ns: "Test.StrPtrLte",
expected: "StrPtrLte en fazla 1 karakter uzunluğunda olmalıdır",
},
{
ns: "Test.StrPtrGt",
expected: "StrPtrGt, 10 karakter uzunluğundan fazla olmalıdır",
},
{
ns: "Test.StrPtrGte",
expected: "StrPtrGte en az 10 karakter uzunluğunda olmalıdır",
},
{
ns: "Test.OneOfString",
expected: "OneOfString, [red green]'dan biri olmalıdır",
},
{
ns: "Test.OneOfInt",
expected: "OneOfInt, [5 63]'dan biri olmalıdır",
},
{
ns: "Test.UniqueSlice",
expected: "UniqueSlice benzersiz değerler içermelidir",
},
{
ns: "Test.UniqueArray",
expected: "UniqueArray benzersiz değerler içermelidir",
},
{
ns: "Test.UniqueMap",
expected: "UniqueMap benzersiz değerler içermelidir",
},
}
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))
}
}

File diff suppressed because it is too large Load Diff

@ -1,690 +0,0 @@
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))
}
}

@ -10,7 +10,7 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
@ -29,36 +29,6 @@ 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) {
@ -460,10 +430,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("lt-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("lt-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -579,10 +552,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("lte-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("lte-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -698,11 +674,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag())
} else { if err != nil {
goto END
t, err = ut.T("gt-datetime", fe.Field()) }
} }
t, err = ut.T("gt-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -818,10 +796,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用于struct类型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("gte-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("gte-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -1030,16 +1011,6 @@ 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}必须是一个有效的数值",
@ -1130,21 +1101,6 @@ 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}'",
@ -1190,36 +1146,6 @@ 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编号",
@ -1255,11 +1181,6 @@ 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字符",
@ -1398,36 +1319,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return s return s
}, },
}, },
{
tag: "json",
translation: "{0}必须是一个JSON字符串",
override: false,
},
{
tag: "lowercase",
translation: "{0}必须是小写字母",
override: false,
},
{
tag: "uppercase",
translation: "{0}必须是大写字母",
override: false,
},
{
tag: "datetime",
translation: "{0}的格式必须是{1}",
override: false,
customTransFunc: func(ut ut.Translator, fe validator.FieldError) string {
t, err := ut.T(fe.Tag(), fe.Field(), fe.Param())
if err != nil {
log.Printf("警告: 翻译字段错误: %#v", fe)
return fe.(error).Error()
}
return t
},
},
} }
for _, t := range translations { for _, t := range translations {

@ -4,17 +4,18 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
zhongwen "github.com/go-playground/locales/zh" zhongwen "github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
zh := zhongwen.New() zh := zhongwen.New()
uni := ut.New(zh, zh) uni := ut.New(zh, zh)
trans, _ := uni.GetTranslator("zh") trans, ok := uni.GetTranslator("zh")
Equal(t, ok, true)
validate := validator.New() validate := validator.New()
@ -31,123 +32,113 @@ 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"`
AlphanumUnicodeString string `validate:"alphanumunicode"` NumericString string `validate:"numeric"`
AlphaUnicodeString string `validate:"alphaunicode"` 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=!@#$"`
ContainsRune string `validate:"containsrune=☻"` ExcludesRune string `validate:"excludesrune=☻"`
Excludes string `validate:"excludes=text"` ISBN string `validate:"isbn"`
ExcludesAll string `validate:"excludesall=!@#$"` ISBN10 string `validate:"isbn10"`
ExcludesRune string `validate:"excludesrune=☻"` ISBN13 string `validate:"isbn13"`
EndsWith string `validate:"endswith=end"` UUID string `validate:"uuid"`
StartsWith string `validate:"startswith=start"` UUID3 string `validate:"uuid3"`
ISBN string `validate:"isbn"` UUID4 string `validate:"uuid4"`
ISBN10 string `validate:"isbn10"` UUID5 string `validate:"uuid5"`
ISBN13 string `validate:"isbn13"` ASCII string `validate:"ascii"`
UUID string `validate:"uuid"` PrintableASCII string `validate:"printascii"`
UUID3 string `validate:"uuid3"` MultiByte string `validate:"multibyte"`
UUID4 string `validate:"uuid4"` DataURI string `validate:"datauri"`
UUID5 string `validate:"uuid5"` Latitude string `validate:"latitude"`
ULID string `validate:"ulid"` Longitude string `validate:"longitude"`
ASCII string `validate:"ascii"` SSN string `validate:"ssn"`
PrintableASCII string `validate:"printascii"` IP string `validate:"ip"`
MultiByte string `validate:"multibyte"` IPv4 string `validate:"ipv4"`
DataURI string `validate:"datauri"` IPv6 string `validate:"ipv6"`
Latitude string `validate:"latitude"` CIDR string `validate:"cidr"`
Longitude string `validate:"longitude"` CIDRv4 string `validate:"cidrv4"`
SSN string `validate:"ssn"` CIDRv6 string `validate:"cidrv6"`
IP string `validate:"ip"` TCPAddr string `validate:"tcp_addr"`
IPv4 string `validate:"ipv4"` TCPAddrv4 string `validate:"tcp4_addr"`
IPv6 string `validate:"ipv6"` TCPAddrv6 string `validate:"tcp6_addr"`
CIDR string `validate:"cidr"` UDPAddr string `validate:"udp_addr"`
CIDRv4 string `validate:"cidrv4"` UDPAddrv4 string `validate:"udp4_addr"`
CIDRv6 string `validate:"cidrv6"` UDPAddrv6 string `validate:"udp6_addr"`
TCPAddr string `validate:"tcp_addr"` IPAddr string `validate:"ip_addr"`
TCPAddrv4 string `validate:"tcp4_addr"` IPAddrv4 string `validate:"ip4_addr"`
TCPAddrv6 string `validate:"tcp6_addr"` IPAddrv6 string `validate:"ip6_addr"`
UDPAddr string `validate:"udp_addr"` UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future
UDPAddrv4 string `validate:"udp4_addr"` MAC string `validate:"mac"`
UDPAddrv6 string `validate:"udp6_addr"` IsColor string `validate:"iscolor"`
IPAddr string `validate:"ip_addr"` StrPtrMinLen *string `validate:"min=10"`
IPAddrv4 string `validate:"ip4_addr"` StrPtrMaxLen *string `validate:"max=1"`
IPAddrv6 string `validate:"ip6_addr"` StrPtrLen *string `validate:"len=2"`
UinxAddr string `validate:"unix_addr"` // can't fail from within Go's net package currently, but maybe in the future StrPtrLt *string `validate:"lt=1"`
MAC string `validate:"mac"` StrPtrLte *string `validate:"lte=1"`
IsColor string `validate:"iscolor"` StrPtrGt *string `validate:"gt=10"`
StrPtrMinLen *string `validate:"min=10"` StrPtrGte *string `validate:"gte=10"`
StrPtrMaxLen *string `validate:"max=1"` OneOfString string `validate:"oneof=red green"`
StrPtrLen *string `validate:"len=2"` OneOfInt int `validate:"oneof=5 63"`
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"`
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
@ -178,8 +169,6 @@ 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"
@ -187,9 +176,6 @@ 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 = "カタカナ"
@ -199,13 +185,6 @@ func TestTranslations(t *testing.T) {
test.StrPtrMaxLen = &s test.StrPtrMaxLen = &s
test.StrPtrLen = &s test.StrPtrLen = &s
test.JsonString = "{\"foo\":\"bar\",}"
test.LowercaseString = "ABCDEFG"
test.UppercaseString = "abcdefg"
test.Datetime = "20060102"
err = validate.Struct(test) err = validate.Struct(test)
NotEqual(t, err, nil) NotEqual(t, err, nil)
@ -328,10 +307,6 @@ 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编号",
@ -344,14 +319,6 @@ 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'",
@ -364,10 +331,6 @@ 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必须包含至少一个以下字符'!@#$'",
@ -424,14 +387,6 @@ 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只能包含字母和数字",
@ -660,22 +615,6 @@ func TestTranslations(t *testing.T) {
ns: "Test.OneOfInt", ns: "Test.OneOfInt",
expected: "OneOfInt必须是[5 63]中的一个", expected: "OneOfInt必须是[5 63]中的一个",
}, },
{
ns: "Test.JsonString",
expected: "JsonString必须是一个JSON字符串",
},
{
ns: "Test.LowercaseString",
expected: "LowercaseString必须是小写字母",
},
{
ns: "Test.UppercaseString",
expected: "UppercaseString必须是大写字母",
},
{
ns: "Test.Datetime",
expected: "Datetime的格式必须是2006-01-02",
},
} }
for _, tt := range tests { for _, tt := range tests {

@ -10,7 +10,7 @@ import (
"github.com/go-playground/locales" "github.com/go-playground/locales"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" "gopkg.in/go-playground/validator.v9"
) )
// RegisterDefaultTranslations registers a set of default translations // RegisterDefaultTranslations registers a set of default translations
@ -430,10 +430,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("lt-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("lt-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -549,10 +552,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("lte-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("lte-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -618,10 +624,13 @@ 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:]))
} }
f64, err = strconv.ParseFloat(fe.Param(), 64) f64, err = strconv.ParseFloat(fe.Param(), 64)
return return
} }
@ -665,10 +674,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("gt-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("gt-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -784,10 +796,13 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
case reflect.Struct: case reflect.Struct:
if fe.Type() != reflect.TypeOf(time.Time{}) { if fe.Type() != reflect.TypeOf(time.Time{}) {
err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag()) err = fmt.Errorf("tag '%s'不能用於struct類型.", fe.Tag())
} else { if err != nil {
t, err = ut.T("gte-datetime", fe.Field()) goto END
}
} }
t, err = ut.T("gte-datetime", fe.Field())
default: default:
err = fn() err = fn()
if err != nil { if err != nil {
@ -1166,11 +1181,6 @@ 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字元",
@ -1309,21 +1319,6 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
return s return s
}, },
}, },
{
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("警告: 翻譯欄位錯誤: %#v", fe)
return fe.(error).Error()
}
return t
},
},
} }
for _, t := range translations { for _, t := range translations {

@ -4,17 +4,17 @@ import (
"testing" "testing"
"time" "time"
. "github.com/go-playground/assert/v2"
zhongwen "github.com/go-playground/locales/zh_Hant_TW" zhongwen "github.com/go-playground/locales/zh_Hant_TW"
ut "github.com/go-playground/universal-translator" ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10" . "gopkg.in/go-playground/assert.v1"
"gopkg.in/go-playground/validator.v9"
) )
func TestTranslations(t *testing.T) { func TestTranslations(t *testing.T) {
zh := zhongwen.New() zh := zhongwen.New()
uni := ut.New(zh, zh) uni := ut.New(zh, zh)
trans, _ := uni.GetTranslator("zh") trans, ok := uni.GetTranslator("zh_Hant_TW")
Equal(t, ok, true)
validate := validator.New() validate := validator.New()
@ -104,7 +104,6 @@ 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"`
@ -139,7 +138,6 @@ 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"`
Datetime string `validate:"datetime=2006-01-02"`
} }
var test Test var test Test
@ -186,8 +184,6 @@ func TestTranslations(t *testing.T) {
test.StrPtrMaxLen = &s test.StrPtrMaxLen = &s
test.StrPtrLen = &s test.StrPtrLen = &s
test.Datetime = "2008-Feb-01"
err = validate.Struct(test) err = validate.Struct(test)
NotEqual(t, err, nil) NotEqual(t, err, nil)
@ -310,10 +306,6 @@ 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編號",
@ -622,10 +614,6 @@ func TestTranslations(t *testing.T) {
ns: "Test.OneOfInt", ns: "Test.OneOfInt",
expected: "OneOfInt必須是[5 63]中的一個", expected: "OneOfInt必須是[5 63]中的一個",
}, },
{
ns: "Test.Datetime",
expected: "Datetime與2006-01-02格式不匹配",
},
} }
for _, tt := range tests { for _, tt := range tests {

@ -4,7 +4,6 @@ import (
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"time"
) )
// extractTypeInternal gets the actual underlying type of field value. // extractTypeInternal gets the actual underlying type of field value.
@ -58,10 +57,11 @@ BEGIN:
// //
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
// could not be retrieved because it didn't exist. // could not be retrieved because it didn't exist.
func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) { func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, found bool) {
BEGIN: BEGIN:
current, kind, nullable = v.ExtractType(val) current, kind, _ = v.ExtractType(val)
if kind == reflect.Invalid { if kind == reflect.Invalid {
return return
} }
@ -82,7 +82,7 @@ BEGIN:
fld := namespace fld := namespace
var ns string var ns string
if !typ.ConvertibleTo(timeType) { if typ != timeType {
idx := strings.Index(namespace, namespaceSeparator) idx := strings.Index(namespace, namespaceSeparator)
@ -112,7 +112,7 @@ BEGIN:
arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2]) arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
if arrIdx >= current.Len() { if arrIdx >= current.Len() {
return return current, kind, false
} }
startIdx := idx2 + 1 startIdx := idx2 + 1
@ -223,34 +223,13 @@ BEGIN:
// asInt returns the parameter as a int64 // asInt returns the parameter as a int64
// or panics if it can't convert // or panics if it can't convert
func asInt(param string) int64 { func asInt(param string) int64 {
i, err := strconv.ParseInt(param, 0, 64) i, err := strconv.ParseInt(param, 0, 64)
panicIf(err) panicIf(err)
return i return i
} }
// asIntFromTimeDuration parses param as time.Duration and returns it as int64
// or panics on error.
func asIntFromTimeDuration(param string) int64 {
d, err := time.ParseDuration(param)
if err != nil {
// attempt parsing as an an integer assuming nanosecond precision
return asInt(param)
}
return int64(d)
}
// asIntFromType calls the proper function to parse param as int64,
// given a field's Type t.
func asIntFromType(t reflect.Type, param string) int64 {
switch t {
case timeDurationType:
return asIntFromTimeDuration(param)
default:
return asInt(param)
}
}
// asUint returns the parameter as a uint64 // asUint returns the parameter as a uint64
// or panics if it can't convert // or panics if it can't convert
func asUint(param string) uint64 { func asUint(param string) uint64 {
@ -271,16 +250,6 @@ func asFloat(param string) float64 {
return i return i
} }
// asBool returns the parameter as a bool
// or panics if it can't convert
func asBool(param string) bool {
i, err := strconv.ParseBool(param)
panicIf(err)
return i
}
func panicIf(err error) { func panicIf(err error) {
if err != nil { if err != nil {
panic(err.Error()) panic(err.Error())

@ -7,7 +7,7 @@ import (
"strconv" "strconv"
) )
// per validate construct // per validate contruct
type validate struct { type validate struct {
v *Validate v *Validate
top reflect.Value top reflect.Value
@ -74,7 +74,7 @@ func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, cur
} }
} }
v.traverseField(ctx, current, current.Field(f.idx), ns, structNs, f, f.cTags) v.traverseField(ctx, parent, current.Field(f.idx), ns, structNs, f, f.cTags)
} }
} }
@ -94,6 +94,7 @@ func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, cur
// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { func (v *validate) traverseField(ctx context.Context, parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) {
var typ reflect.Type var typ reflect.Type
var kind reflect.Kind var kind reflect.Kind
@ -111,36 +112,16 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
} }
if ct.hasTag { if ct.hasTag {
if kind == reflect.Invalid {
v.str1 = string(append(ns, cf.altName...))
if v.v.hasTagNameFunc {
v.str2 = string(append(structNs, cf.name...))
} else {
v.str2 = v.str1
}
v.errs = append(v.errs,
&fieldError{
v: v.v,
tag: ct.aliasTag,
actualTag: ct.tag,
ns: v.str1,
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
param: ct.param,
kind: kind,
},
)
return
}
v.str1 = string(append(ns, cf.altName...)) v.str1 = string(append(ns, cf.altName...))
if v.v.hasTagNameFunc { if v.v.hasTagNameFunc {
v.str2 = string(append(structNs, cf.name...)) v.str2 = string(append(structNs, cf.name...))
} else { } else {
v.str2 = v.str1 v.str2 = v.str1
} }
if !ct.runValidationWhenNil {
if kind == reflect.Invalid {
v.errs = append(v.errs, v.errs = append(v.errs,
&fieldError{ &fieldError{
v: v.v, v: v.v,
@ -150,21 +131,38 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
structNs: v.str2, structNs: v.str2,
fieldLen: uint8(len(cf.altName)), fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)), structfieldLen: uint8(len(cf.name)),
value: current.Interface(),
param: ct.param, param: ct.param,
kind: kind, kind: kind,
typ: current.Type(),
}, },
) )
return return
} }
v.errs = append(v.errs,
&fieldError{
v: v.v,
tag: ct.aliasTag,
actualTag: ct.tag,
ns: v.str1,
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: current.Type(),
},
)
return
} }
case reflect.Struct: case reflect.Struct:
typ = current.Type() typ = current.Type()
if !typ.ConvertibleTo(timeType) { if typ != timeType {
if ct != nil { if ct != nil {
@ -222,12 +220,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, parent, current, typ, ns, structNs, ct) v.validateStruct(ctx, current, current, typ, ns, structNs, ct)
return return
} }
} }
if ct == nil || !ct.hasTag { if !ct.hasTag {
return return
} }
@ -249,7 +247,7 @@ OUTER:
v.cf = cf v.cf = cf
v.ct = ct v.ct = ct
if !hasValue(v) { if !v.fldIsPointer && !hasValue(v) {
return return
} }
@ -355,10 +353,6 @@ 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 {
@ -372,11 +366,6 @@ OUTER:
if ct.typeof != typeOr { if ct.typeof != typeOr {
continue OUTER continue OUTER
} }
if ct.isBlockEnd {
ct = ct.next
continue OUTER
}
} }
} }
@ -452,6 +441,7 @@ 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 {

@ -13,45 +13,31 @@ import (
) )
const ( const (
defaultTagName = "validate" defaultTagName = "validate"
utf8HexComma = "0x2C" utf8HexComma = "0x2C"
utf8Pipe = "0x7C" utf8Pipe = "0x7C"
tagSeparator = "," tagSeparator = ","
orSeparator = "|" orSeparator = "|"
tagKeySeparator = "=" tagKeySeparator = "="
structOnlyTag = "structonly" structOnlyTag = "structonly"
noStructLevelTag = "nostructlevel" noStructLevelTag = "nostructlevel"
omitempty = "omitempty" omitempty = "omitempty"
isdefault = "isdefault" isdefault = "isdefault"
requiredWithoutAllTag = "required_without_all" skipValidationTag = "-"
requiredWithoutTag = "required_without" diveTag = "dive"
requiredWithTag = "required_with" keysTag = "keys"
requiredWithAllTag = "required_with_all" endKeysTag = "endkeys"
requiredIfTag = "required_if" requiredTag = "required"
requiredUnlessTag = "required_unless" namespaceSeparator = "."
excludedWithoutAllTag = "excluded_without_all" leftBracket = "["
excludedWithoutTag = "excluded_without" rightBracket = "]"
excludedWithTag = "excluded_with" restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
excludedWithAllTag = "excluded_with_all" restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
excludedIfTag = "excluded_if" restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
excludedUnlessTag = "excluded_unless"
skipValidationTag = "-"
diveTag = "dive"
keysTag = "keys"
endKeysTag = "endkeys"
requiredTag = "required"
namespaceSeparator = "."
leftBracket = "["
rightBracket = "]"
restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
) )
var ( var (
timeDurationType = reflect.TypeOf(time.Duration(0)) timeType = reflect.TypeOf(time.Time{})
timeType = reflect.TypeOf(time.Time{})
defaultCField = &cField{namesEqual: true} defaultCField = &cField{namesEqual: true}
) )
@ -69,11 +55,6 @@ type CustomTypeFunc func(field reflect.Value) interface{}
// TagNameFunc allows for adding of a custom tag name parser // TagNameFunc allows for adding of a custom tag name parser
type TagNameFunc func(field reflect.StructField) string type TagNameFunc func(field reflect.StructField) string
type internalValidationFuncWrapper struct {
fn FuncCtx
runValidatinOnNil bool
}
// Validate contains the validator settings and cache // Validate contains the validator settings and cache
type Validate struct { type Validate struct {
tagName string tagName string
@ -84,18 +65,13 @@ type Validate struct {
structLevelFuncs map[reflect.Type]StructLevelFuncCtx structLevelFuncs map[reflect.Type]StructLevelFuncCtx
customFuncs map[reflect.Type]CustomTypeFunc customFuncs map[reflect.Type]CustomTypeFunc
aliases map[string]string aliases map[string]string
validations map[string]internalValidationFuncWrapper validations map[string]FuncCtx
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)
@ -107,7 +83,7 @@ func New() *Validate {
v := &Validate{ v := &Validate{
tagName: defaultTagName, tagName: defaultTagName,
aliases: make(map[string]string, len(bakedInAliases)), aliases: make(map[string]string, len(bakedInAliases)),
validations: make(map[string]internalValidationFuncWrapper, len(bakedInValidators)), validations: make(map[string]FuncCtx, len(bakedInValidators)),
tagCache: tc, tagCache: tc,
structCache: sc, structCache: sc,
} }
@ -120,15 +96,8 @@ func New() *Validate {
// must copy validators for separate validations to be used in each instance // must copy validators for separate validations to be used in each instance
for k, val := range bakedInValidators { for k, val := range bakedInValidators {
switch k { // no need to error check here, baked in will always be valid
// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour _ = v.registerValidation(k, wrapFunc(val), true)
case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
excludedIfTag, excludedUnlessTag, excludedWithTag, excludedWithAllTag, excludedWithoutTag, excludedWithoutAllTag:
_ = v.registerValidation(k, wrapFunc(val), true, true)
default:
// no need to error check here, baked in will always be valid
_ = v.registerValidation(k, wrapFunc(val), true, false)
}
} }
v.pool = &sync.Pool{ v.pool = &sync.Pool{
@ -150,54 +119,17 @@ 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]
// // skip if tag key says it should be ignored // if name == "-" {
// if name == "-" { // return ""
// 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
@ -208,34 +140,34 @@ func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
// NOTES: // NOTES:
// - if the key already exists, the previous validation function will be replaced. // - if the key already exists, the previous validation function will be replaced.
// - this method is not thread-safe it is intended that these all be registered prior to any validation // - this method is not thread-safe it is intended that these all be registered prior to any validation
func (v *Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull ...bool) error { func (v *Validate) RegisterValidation(tag string, fn Func) error {
return v.RegisterValidationCtx(tag, wrapFunc(fn), callValidationEvenIfNull...) return v.RegisterValidationCtx(tag, wrapFunc(fn))
} }
// RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation // RegisterValidationCtx does the same as RegisterValidation on accepts a FuncCtx validation
// allowing context.Context validation support. // allowing context.Context validation support.
func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull ...bool) error { func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx) error {
var nilCheckable bool return v.registerValidation(tag, fn, false)
if len(callValidationEvenIfNull) > 0 {
nilCheckable = callValidationEvenIfNull[0]
}
return v.registerValidation(tag, fn, false, nilCheckable)
} }
func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn 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]
if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) { if !bakedIn && (ok || strings.ContainsAny(tag, restrictedTagChars)) {
panic(fmt.Sprintf(restrictedTagErr, tag)) panic(fmt.Sprintf(restrictedTagErr, tag))
} }
v.validations[tag] = internalValidationFuncWrapper{fn: fn, runValidatinOnNil: nilCheckable}
v.validations[tag] = fn
return nil return nil
} }
@ -284,34 +216,6 @@ 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
@ -372,7 +276,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().ConvertibleTo(timeType) { if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -417,7 +321,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().ConvertibleTo(timeType) { if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -465,7 +369,7 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields .
val = val.Elem() val = val.Elem()
} }
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -486,10 +390,7 @@ 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...)
// Don't append empty name for unnamed structs vd.misc = append(vd.misc, '.')
if len(vd.misc) != 0 {
vd.misc = append(vd.misc, '.')
}
for _, s := range flds { for _, s := range flds {
@ -555,7 +456,7 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields ..
val = val.Elem() val = val.Elem()
} }
if val.Kind() != reflect.Struct || val.Type().ConvertibleTo(timeType) { if val.Kind() != reflect.Struct || val.Type() == timeType {
return &InvalidValidationError{Type: reflect.TypeOf(s)} return &InvalidValidationError{Type: reflect.TypeOf(s)}
} }
@ -613,7 +514,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 information via context.Context. // validation 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")
@ -632,7 +533,6 @@ 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