UNPKG

54.1 kBMarkdownView Raw
1# Fork of [class-validator](https://github.com/typestack/class-validator)
2
3This project is a fork of another with minor changes, created for personal use.
4
5Long term support is not guaranteed, use of this copy is at your own risk.
6
7## Installation
8
9```
10npm install class-validator-multi-lang --save
11```
12
13## Differences from the original project:
14
15🤘 This feature added support to replace any validation errors
16
17:fire: Integrations with https://crowdin.com/ for manual simplified update translates :cn: :de: :ru: :us:
18
19:earth_americas: Translations created with the machine :robot:, if you found the mistake :bug: please add a new version of translate and write a comment in the right panel in https://crowdin.com/project/class-validator :sunglasses:
20
21:exclamation: The translations are inside the [package](https://www.npmjs.com/package/class-validator-multi-lang), so the package size is very large, you can use the [lite version](https://www.npmjs.com/package/class-validator-multi-lang-lite) without translations and add the necessary translates ones [manually](https://github.com/EndyKaufman/class-validator-multi-lang/tree/i18n/i18n)
22
23## Examples of usages
24
25:godmode: Basic set custom messages
26
27```typescript
28import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
29
30class MyClass {
31 @IsOptional()
32 @Equals('test')
33 title: string = 'bad_value';
34}
35
36const RU_I18N_MESSAGES = {
37 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
38};
39
40const model = new MyClass();
41
42validator.validate(model, messages: RU_I18N_MESSAGES).then(errors => {
43 console.log(errors[0].constraints);
44 // out: title должно быть равно test
45});
46```
47
48:rage3: Load from file
49
50```typescript
51import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
52import { readFileSync } from 'fs';
53import { resolve } from 'path';
54
55class MyClass {
56 @IsOptional()
57 @Equals('test')
58 title: string = 'bad_value';
59}
60
61const RU_I18N_MESSAGES = JSON.parse(readFileSync(resolve(__dirname, './node_modules/class-validator-multi-lang/i18n/ru.json')).toString());
62
63const model = new MyClass();
64
65validator.validate(model, messages: RU_I18N_MESSAGES).then(errors => {
66 console.log(errors[0].constraints);
67 // out: title должен быть равен test
68});
69```
70
71:goberserk: Load from 2 file :bomb: :boom:
72
73```typescript
74import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
75import { readFileSync } from 'fs';
76import { resolve } from 'path';
77
78class MyClass {
79 @IsOptional()
80 @Equals('test')
81 title: string = 'bad_value';
82}
83
84const RU_I18N_MESSAGES = JSON.parse(
85 readFileSync(resolve(__dirname, './node_modules/class-validator-multi-lang/i18n/ru.json')).toString()
86);
87
88const FR_I18N_MESSAGES = JSON.parse(
89 readFileSync(resolve(__dirname, './node_modules/class-validator-multi-lang/i18n/fr.json')).toString()
90);
91
92const model = new MyClass();
93
94validator.validate(model, { messages: RU_I18N_MESSAGES }).then(errors => {
95 console.log(errors[0].constraints);
96 // out: title должен быть равен test
97
98 validator.validate(model, { messages: FR_I18N_MESSAGES }).then(errors => {
99 console.log(errors[0].constraints);
100 // out: title doit être égal à test
101 });
102});
103```
104
105:feelsgood: With override
106
107```typescript
108import { IsOptional, Equals, validator, setClassValidatorMessages } from 'class-validator-multi-lang';
109
110class MyClass {
111 @IsOptional()
112 @Equals('test')
113 title: string = 'bad_value';
114}
115
116setClassValidatorMessages({
117 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
118});
119
120const model = new MyClass();
121
122validator.validate(model).then(errors => {
123 console.log(errors[0].constraints);
124 // out: title должно быть равно test
125});
126```
127
128🔢 With change property name
129
130```typescript
131import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator-multi-lang';
132
133class MyClass {
134 @IsOptional()
135 @Equals('test')
136 @ClassPropertyTitle('property "title"')
137 title: string = 'bad_value';
138}
139
140const RU_I18N_MESSAGES = {
141 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
142};
143const RU_I18N_TITLES = {
144 'property "title"': 'поле "заголовок"',
145};
146
147const model = new MyClass();
148
149validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
150 console.log(errors[0].constraints);
151 // out: поле "заголовок" должно быть равно test
152});
153```
154
155🔢 With change target name
156
157```typescript
158import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator-multi-lang';
159
160@ClassTitle('object "MyClass"')
161class MyClass {
162 @IsOptional()
163 @Equals('test')
164 title: string = 'bad_value';
165}
166
167const RU_I18N_MESSAGES = {
168 '$property must be equal to $constraint1': '$property в $target должно быть равно $constraint1',
169};
170const RU_I18N_TITLES = {
171 'object "MyClass"': 'объекте "МойКласс"',
172};
173
174const model = new MyClass();
175
176validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
177 console.log(errors[0].constraints);
178 // out: title в объекте "МойКласс" должно быть равно test
179});
180```
181
182🔢 With change arguments for validation decorator
183
184```typescript
185import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
186
187class MyClass {
188 @IsOptional()
189 @Equals('test')
190 title: string = 'bad_value';
191}
192
193const RU_I18N_MESSAGES = {
194 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
195};
196const RU_I18N_TITLES = {
197 test: '"тест"',
198};
199
200const model = new MyClass();
201
202validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
203 console.log(errors[0].constraints);
204 // out: title должно быть равно "тест"
205});
206```
207
208🔢 With change value
209
210```typescript
211import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
212
213class MyClass {
214 @IsOptional()
215 @Equals('test')
216 title: string = 'bad_value';
217}
218
219const RU_I18N_MESSAGES = {
220 '$property must be equal to $constraint1': '$property равно $value, а должно быть равно $constraint1',
221};
222const RU_I18N_TITLES = {
223 bad_value: '"плохое_значение"',
224};
225
226const model = new MyClass();
227
228validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
229 console.log(errors[0].constraints);
230 // out: title равно "плохое_значение", а должно быть равно test
231});
232```
233
234---
235
236# class-validator
237
238![Build Status](https://github.com/EndyKaufman/class-validator-multi-lang/workflows/CI/badge.svg)
239[![codecov](https://codecov.io/gh/endykaufman/class-validator-multi-lang/branch/i18n/graph/badge.svg)](https://codecov.io/gh/endykaufman/class-validator-multi-lang)
240[![npm version](https://badge.fury.io/js/class-validator-multi-lang.svg)](https://badge.fury.io/js/class-validator-multi-lang)
241[![install size](https://packagephobia.now.sh/badge?p=class-validator-multi-lang)](https://packagephobia.now.sh/result?p=class-validator-multi-lang)
242[![Crowdin](https://badges.crowdin.net/class-validator/localized.svg)](https://crowdin.com/project/class-validator)
243
244Allows use of decorator and non-decorator based validation.
245Internally uses [validator.js][1] to perform validation.
246Class-validator works on both browser and node.js platforms.
247
248## Table of Contents
249
250- [class-validator](#class-validator)
251 - [Table of Contents](#table-of-contents)
252 - [Installation](#installation)
253 - [Usage](#usage)
254 - [Passing options](#passing-options)
255 - [Validation errors](#validation-errors)
256 - [Validation messages](#validation-messages)
257 - [Validating arrays](#validating-arrays)
258 - [Validating sets](#validating-sets)
259 - [Validating maps](#validating-maps)
260 - [Validating nested objects](#validating-nested-objects)
261 - [Validating promises](#validating-promises)
262 - [Inheriting Validation decorators](#inheriting-validation-decorators)
263 - [Conditional validation](#conditional-validation)
264 - [Whitelisting](#whitelisting)
265 - [Passing context to decorators](#passing-context-to-decorators)
266 - [Skipping missing properties](#skipping-missing-properties)
267 - [Validation groups](#validation-groups)
268 - [Custom validation classes](#custom-validation-classes)
269 - [Custom validation decorators](#custom-validation-decorators)
270 - [Using service container](#using-service-container)
271 - [Synchronous validation](#synchronous-validation)
272 - [Manual validation](#manual-validation)
273 - [Validation decorators](#validation-decorators)
274 - [Defining validation schema without decorators](#defining-validation-schema-without-decorators)
275 - [Validating plain objects](#validating-plain-objects)
276 - [Basic support i18n](#basic-support-i18n)
277 - [Samples](#samples)
278 - [Extensions](#extensions)
279 - [Release notes](#release-notes)
280
281## Installation
282
283```
284npm install class-validator --save
285```
286
287> Note: Please use at least npm@6 when using class-validator. From npm@6 the dependency tree is flattened, which is required by `class-validator` to function properly.
288
289## Usage
290
291Create your class and put some validation decorators on the properties you want to validate:
292
293```typescript
294import {
295 validate,
296 validateOrReject,
297 Contains,
298 IsInt,
299 Length,
300 IsEmail,
301 IsFQDN,
302 IsDate,
303 Min,
304 Max,
305} from 'class-validator-multi-lang';
306
307export class Post {
308 @Length(10, 20)
309 title: string;
310
311 @Contains('hello')
312 text: string;
313
314 @IsInt()
315 @Min(0)
316 @Max(10)
317 rating: number;
318
319 @IsEmail()
320 email: string;
321
322 @IsFQDN()
323 site: string;
324
325 @IsDate()
326 createDate: Date;
327}
328
329let post = new Post();
330post.title = 'Hello'; // should not pass
331post.text = 'this is a great post about hell world'; // should not pass
332post.rating = 11; // should not pass
333post.email = 'google.com'; // should not pass
334post.site = 'googlecom'; // should not pass
335
336validate(post).then(errors => {
337 // errors is an array of validation errors
338 if (errors.length > 0) {
339 console.log('validation failed. errors: ', errors);
340 } else {
341 console.log('validation succeed');
342 }
343});
344
345validateOrReject(post).catch(errors => {
346 console.log('Promise rejected (validation failed). Errors: ', errors);
347});
348// or
349async function validateOrRejectExample(input) {
350 try {
351 await validateOrReject(input);
352 } catch (errors) {
353 console.log('Caught promise rejection (validation failed). Errors: ', errors);
354 }
355}
356```
357
358### Passing options
359
360The `validate` function optionally expects a `ValidatorOptions` object as a second parameter:
361
362```ts
363export interface ValidatorOptions {
364 skipMissingProperties?: boolean;
365 whitelist?: boolean;
366 forbidNonWhitelisted?: boolean;
367 groups?: string[];
368 dismissDefaultMessages?: boolean;
369 validationError?: {
370 target?: boolean;
371 value?: boolean;
372 };
373
374 forbidUnknownValues?: boolean;
375 stopAtFirstError?: boolean;
376}
377```
378
379> It's highly advised to set `forbidUnknownValues: true` as it will prevent unknown objects from passing validation.
380
381## Validation errors
382
383The `validate` method returns an array of `ValidationError` objects. Each `ValidationError` is:
384
385```typescript
386{
387 target: Object; // Object that was validated.
388 property: string; // Object's property that haven't pass validation.
389 value: any; // Value that haven't pass a validation.
390 constraints?: { // Constraints that failed validation with error messages.
391 [type: string]: string;
392 };
393 children?: ValidationError[]; // Contains all nested validation errors of the property
394}
395```
396
397In our case, when we validated a Post object, we have such an array of `ValidationError` objects:
398
399```typescript
400[{
401 target: /* post object */,
402 property: "title",
403 value: "Hello",
404 constraints: {
405 length: "$property must be longer than or equal to 10 characters"
406 }
407}, {
408 target: /* post object */,
409 property: "text",
410 value: "this is a great post about hell world",
411 constraints: {
412 contains: "text must contain a hello string"
413 }
414},
415// and other errors
416]
417```
418
419If you don't want a `target` to be exposed in validation errors, there is a special option when you use validator:
420
421```typescript
422validator.validate(post, { validationError: { target: false } });
423```
424
425This is especially useful when you send errors back over http, and you most probably don't want to expose
426the whole target object.
427
428## Validation messages
429
430You can specify validation message in the decorator options and that message will be returned in the `ValidationError`
431returned by the `validate` method (in the case that validation for this field fails).
432
433```typescript
434import { MinLength, MaxLength } from 'class-validator-multi-lang';
435
436export class Post {
437 @MinLength(10, {
438 message: 'Title is too short',
439 })
440 @MaxLength(50, {
441 message: 'Title is too long',
442 })
443 title: string;
444}
445```
446
447There are few special tokens you can use in your messages:
448
449- `$value` - the value that is being validated
450- `$property` - name of the object's property being validated
451- `$target` - name of the object's class being validated
452- `$constraint1`, `$constraint2`, ... `$constraintN` - constraints defined by specific validation type
453
454Example of usage:
455
456```typescript
457import { MinLength, MaxLength } from 'class-validator-multi-lang';
458
459export class Post {
460 @MinLength(10, {
461 // here, $constraint1 will be replaced with "10", and $value with actual supplied value
462 message: 'Title is too short. Minimal length is $constraint1 characters, but actual is $value',
463 })
464 @MaxLength(50, {
465 // here, $constraint1 will be replaced with "50", and $value with actual supplied value
466 message: 'Title is too long. Maximal length is $constraint1 characters, but actual is $value',
467 })
468 title: string;
469}
470```
471
472Also you can provide a function, that returns a message. This allows you to create more granular messages:
473
474```typescript
475import { MinLength, MaxLength, ValidationArguments } from 'class-validator-multi-lang';
476
477export class Post {
478 @MinLength(10, {
479 message: (args: ValidationArguments) => {
480 if (args.value.length === 1) {
481 return 'Too short, minimum length is 1 character';
482 } else {
483 return 'Too short, minimum length is ' + args.constraints[0] + ' characters';
484 }
485 },
486 })
487 title: string;
488}
489```
490
491Message function accepts `ValidationArguments` which contains the following information:
492
493- `value` - the value that is being validated
494- `constraints` - array of constraints defined by specific validation type
495- `targetName` - name of the object's class being validated
496- `object` - object that is being validated
497- `property` - name of the object's property being validated
498
499## Validating arrays
500
501If your field is an array and you want to perform validation of each item in the array you must specify a
502special `each: true` decorator option:
503
504```typescript
505import { MinLength, MaxLength } from 'class-validator-multi-lang';
506
507export class Post {
508 @MaxLength(20, {
509 each: true,
510 })
511 tags: string[];
512}
513```
514
515This will validate each item in `post.tags` array.
516
517## Validating sets
518
519If your field is a set and you want to perform validation of each item in the set you must specify a
520special `each: true` decorator option:
521
522```typescript
523import { MinLength, MaxLength } from 'class-validator-multi-lang';
524
525export class Post {
526 @MaxLength(20, {
527 each: true,
528 })
529 tags: Set<string>;
530}
531```
532
533This will validate each item in `post.tags` set.
534
535## Validating maps
536
537If your field is a map and you want to perform validation of each item in the map you must specify a
538special `each: true` decorator option:
539
540```typescript
541import { MinLength, MaxLength } from 'class-validator-multi-lang';
542
543export class Post {
544 @MaxLength(20, {
545 each: true,
546 })
547 tags: Map<string, string>;
548}
549```
550
551This will validate each item in `post.tags` map.
552
553## Validating nested objects
554
555If your object contains nested objects and you want the validator to perform their validation too, then you need to
556use the `@ValidateNested()` decorator:
557
558```typescript
559import { ValidateNested } from 'class-validator-multi-lang';
560
561export class Post {
562 @ValidateNested()
563 user: User;
564}
565```
566
567Please note that nested object _must_ be an instance of a class, otherwise `@ValidateNested` won't know what class is target of validation. Check also [Validating plain objects](#validating-plain-objects).
568
569It also works with multi-dimensional array, like :
570
571```typescript
572import { ValidateNested } from 'class-validator-multi-lang';
573
574export class Plan2D {
575 @ValidateNested()
576 matrix: Point[][];
577}
578```
579
580## Validating promises
581
582If your object contains property with `Promise`-returned value that should be validated, then you need to use the `@ValidatePromise()` decorator:
583
584```typescript
585import { ValidatePromise, Min } from 'class-validator-multi-lang';
586
587export class Post {
588 @Min(0)
589 @ValidatePromise()
590 userId: Promise<number>;
591}
592```
593
594It also works great with `@ValidateNested` decorator:
595
596```typescript
597import { ValidateNested, ValidatePromise } from 'class-validator-multi-lang';
598
599export class Post {
600 @ValidateNested()
601 @ValidatePromise()
602 user: Promise<User>;
603}
604```
605
606## Inheriting Validation decorators
607
608When you define a subclass which extends from another one, the subclass will automatically inherit the parent's decorators. If a property is redefined in the descendant class decorators will be applied on it both from that and the base class.
609
610```typescript
611import { validate } from 'class-validator-multi-lang';
612
613class BaseContent {
614 @IsEmail()
615 email: string;
616
617 @IsString()
618 password: string;
619}
620
621class User extends BaseContent {
622 @MinLength(10)
623 @MaxLength(20)
624 name: string;
625
626 @Contains('hello')
627 welcome: string;
628
629 @MinLength(20)
630 password: string;
631}
632
633let user = new User();
634
635user.email = 'invalid email'; // inherited property
636user.password = 'too short'; // password wil be validated not only against IsString, but against MinLength as well
637user.name = 'not valid';
638user.welcome = 'helo';
639
640validate(user).then(errors => {
641 // ...
642}); // it will return errors for email, title and text properties
643```
644
645## Conditional validation
646
647The conditional validation decorator (`@ValidateIf`) can be used to ignore the validators on a property when the provided condition function returns false. The condition function takes the object being validated and must return a `boolean`.
648
649```typescript
650import { ValidateIf, IsNotEmpty } from 'class-validator-multi-lang';
651
652export class Post {
653 otherProperty: string;
654
655 @ValidateIf(o => o.otherProperty === 'value')
656 @IsNotEmpty()
657 example: string;
658}
659```
660
661In the example above, the validation rules applied to `example` won't be run unless the object's `otherProperty` is `"value"`.
662
663Note that when the condition is false all validation decorators are ignored, including `isDefined`.
664
665## Whitelisting
666
667Even if your object is an instance of a validation class it can contain additional properties that are not defined.
668If you do not want to have such properties on your object, pass special flag to `validate` method:
669
670```typescript
671import { validate } from 'class-validator-multi-lang';
672// ...
673validate(post, { whitelist: true });
674```
675
676This will strip all properties that don't have any decorators. If no other decorator is suitable for your property,
677you can use @Allow decorator:
678
679```typescript
680import {validate, Allow, Min} from "class-validator-multi-lang";
681
682export class Post {
683
684 @Allow()
685 title: string;
686
687 @Min(0)
688 views: number;
689
690 nonWhitelistedProperty: number;
691}
692
693let post = new Post();
694post.title = 'Hello world!';
695post.views = 420;
696
697post.nonWhitelistedProperty = 69;
698(post as any).anotherNonWhitelistedProperty = "something";
699
700validate(post).then(errors => {
701 // post.nonWhitelistedProperty is not defined
702 // (post as any).anotherNonWhitelistedProperty is not defined
703 ...
704});
705```
706
707If you would rather to have an error thrown when any non-whitelisted properties are present, pass another flag to
708`validate` method:
709
710```typescript
711import { validate } from 'class-validator-multi-lang';
712// ...
713validate(post, { whitelist: true, forbidNonWhitelisted: true });
714```
715
716## Passing context to decorators
717
718It's possible to pass a custom object to decorators which will be accessible on the `ValidationError` instance of the property if validation failed.
719
720```ts
721import { validate } from 'class-validator-multi-lang';
722
723class MyClass {
724 @MinLength(32, {
725 message: 'EIC code must be at least 32 characters',
726 context: {
727 errorCode: 1003,
728 developerNote: 'The validated string must contain 32 or more characters.',
729 },
730 })
731 eicCode: string;
732}
733
734const model = new MyClass();
735
736validate(model).then(errors => {
737 //errors[0].contexts['minLength'].errorCode === 1003
738});
739```
740
741## Skipping missing properties
742
743Sometimes you may want to skip validation of the properties that do not exist in the validating object. This is
744usually desirable when you want to update some parts of the object, and want to validate only updated parts,
745but skip everything else, e.g. skip missing properties.
746In such situations you will need to pass a special flag to `validate` method:
747
748```typescript
749import { validate } from 'class-validator-multi-lang';
750// ...
751validate(post, { skipMissingProperties: true });
752```
753
754When skipping missing properties, sometimes you want not to skip all missing properties, some of them maybe required
755for you, even if skipMissingProperties is set to true. For such cases you should use `@IsDefined()` decorator.
756`@IsDefined()` is the only decorator that ignores `skipMissingProperties` option.
757
758## Validation groups
759
760In different situations you may want to use different validation schemas of the same object.
761In such cases you can use validation groups.
762
763```typescript
764import { validate, Min, Length } from 'class-validator-multi-lang';
765
766export class User {
767 @Min(12, {
768 groups: ['registration'],
769 })
770 age: number;
771
772 @Length(2, 20, {
773 groups: ['registration', 'admin'],
774 })
775 name: string;
776}
777
778let user = new User();
779user.age = 10;
780user.name = 'Alex';
781
782validate(user, {
783 groups: ['registration'],
784}); // this will not pass validation
785
786validate(user, {
787 groups: ['admin'],
788}); // this will pass validation
789
790validate(user, {
791 groups: ['registration', 'admin'],
792}); // this will not pass validation
793
794validate(user, {
795 groups: undefined, // the default
796}); // this will not pass validation since all properties get validated regardless of their groups
797
798validate(user, {
799 groups: [],
800}); // this will not pass validation, (equivalent to 'groups: undefined', see above)
801```
802
803There is also a special flag `always: true` in validation options that you can use. This flag says that this validation
804must be applied always no matter which group is used.
805
806## Custom validation classes
807
808If you have custom validation logic you can create a _Constraint class_:
809
8101. First create a file, lets say `CustomTextLength.ts`, and define a new class:
811
812 ```typescript
813 import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator-multi-lang';
814
815 @ValidatorConstraint({ name: 'customText', async: false })
816 export class CustomTextLength implements ValidatorConstraintInterface {
817 validate(text: string, args: ValidationArguments) {
818 return text.length > 1 && text.length < 10; // for async validations you must return a Promise<boolean> here
819 }
820
821 defaultMessage(args: ValidationArguments) {
822 // here you can provide default error message if validation failed
823 return 'Text ($value) is too short or too long!';
824 }
825 }
826 ```
827
828 We marked our class with `@ValidatorConstraint` decorator.
829 You can also supply a validation constraint name - this name will be used as "error type" in ValidationError.
830 If you will not supply a constraint name - it will be auto-generated.
831
832 Our class must implement `ValidatorConstraintInterface` interface and its `validate` method,
833 which defines validation logic. If validation succeeds, method returns true, otherwise false.
834 Custom validator can be asynchronous, if you want to perform validation after some asynchronous
835 operations, simply return a promise with boolean inside in `validate` method.
836
837 Also we defined optional method `defaultMessage` which defines a default error message,
838 in the case that the decorator's implementation doesn't set an error message.
839
8402) Then you can use your new validation constraint in your class:
841
842 ```typescript
843 import { Validate } from 'class-validator-multi-lang';
844 import { CustomTextLength } from './CustomTextLength';
845
846 export class Post {
847 @Validate(CustomTextLength, {
848 message: 'Title is too short or long!',
849 })
850 title: string;
851 }
852 ```
853
854 Here we set our newly created `CustomTextLength` validation constraint for `Post.title`.
855
8563) And use validator as usual:
857
858 ```typescript
859 import { validate } from 'class-validator-multi-lang';
860
861 validate(post).then(errors => {
862 // ...
863 });
864 ```
865
866You can also pass constraints to your validator, like this:
867
868```typescript
869import { Validate } from 'class-validator-multi-lang';
870import { CustomTextLength } from './CustomTextLength';
871
872export class Post {
873 @Validate(CustomTextLength, [3, 20], {
874 message: 'Wrong post title',
875 })
876 title: string;
877}
878```
879
880And use them from `validationArguments` object:
881
882```typescript
883import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator-multi-lang';
884
885@ValidatorConstraint()
886export class CustomTextLength implements ValidatorConstraintInterface {
887 validate(text: string, validationArguments: ValidationArguments) {
888 return text.length > validationArguments.constraints[0] && text.length < validationArguments.constraints[1];
889 }
890}
891```
892
893## Custom validation decorators
894
895You can also create a custom decorators. Its the most elegant way of using a custom validations.
896Lets create a decorator called `@IsLongerThan`:
897
8981. Create a decorator itself:
899
900 ```typescript
901 import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator-multi-lang';
902
903 export function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
904 return function (object: Object, propertyName: string) {
905 registerDecorator({
906 name: 'isLongerThan',
907 target: object.constructor,
908 propertyName: propertyName,
909 constraints: [property],
910 options: validationOptions,
911 validator: {
912 validate(value: any, args: ValidationArguments) {
913 const [relatedPropertyName] = args.constraints;
914 const relatedValue = (args.object as any)[relatedPropertyName];
915 return typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length; // you can return a Promise<boolean> here as well, if you want to make async validation
916 },
917 },
918 });
919 };
920 }
921 ```
922
9232. Put it to use:
924
925 ```typescript
926 import { IsLongerThan } from './IsLongerThan';
927
928 export class Post {
929 title: string;
930
931 @IsLongerThan('title', {
932 /* you can also use additional validation options, like "groups" in your custom validation decorators. "each" is not supported */
933 message: 'Text must be longer than the title',
934 })
935 text: string;
936 }
937 ```
938
939In your custom decorators you can also use `ValidationConstraint`.
940Lets create another custom validation decorator called `IsUserAlreadyExist`:
941
9421. Create a ValidationConstraint and decorator:
943
944 ```typescript
945 import {
946 registerDecorator,
947 ValidationOptions,
948 ValidatorConstraint,
949 ValidatorConstraintInterface,
950 ValidationArguments,
951 } from 'class-validator-multi-lang';
952
953 @ValidatorConstraint({ async: true })
954 export class IsUserAlreadyExistConstraint implements ValidatorConstraintInterface {
955 validate(userName: any, args: ValidationArguments) {
956 return UserRepository.findOneByName(userName).then(user => {
957 if (user) return false;
958 return true;
959 });
960 }
961 }
962
963 export function IsUserAlreadyExist(validationOptions?: ValidationOptions) {
964 return function (object: Object, propertyName: string) {
965 registerDecorator({
966 target: object.constructor,
967 propertyName: propertyName,
968 options: validationOptions,
969 constraints: [],
970 validator: IsUserAlreadyExistConstraint,
971 });
972 };
973 }
974 ```
975
976 note that we marked our constraint that it will by async by adding `{ async: true }` in validation options.
977
9782. And put it to use:
979
980 ```typescript
981 import { IsUserAlreadyExist } from './IsUserAlreadyExist';
982
983 export class User {
984 @IsUserAlreadyExist({
985 message: 'User $value already exists. Choose another name.',
986 })
987 name: string;
988 }
989 ```
990
991## Using service container
992
993Validator supports service container in the case if want to inject dependencies into your custom validator constraint
994classes. Here is example how to integrate it with [typedi][2]:
995
996```typescript
997import { Container } from 'typedi';
998import { useContainer, Validator } from 'class-validator-multi-lang';
999
1000// do this somewhere in the global application level:
1001useContainer(Container);
1002let validator = Container.get(Validator);
1003
1004// now everywhere you can inject Validator class which will go from the container
1005// also you can inject classes using constructor injection into your custom ValidatorConstraint-s
1006```
1007
1008## Synchronous validation
1009
1010If you want to perform a simple non async validation you can use `validateSync` method instead of regular `validate`
1011method. It has the same arguments as `validate` method. But note, this method **ignores** all async validations
1012you have.
1013
1014## Manual validation
1015
1016There are several method exist in the Validator that allows to perform non-decorator based validation:
1017
1018```typescript
1019import { isEmpty, isBoolean } from 'class-validator-multi-lang';
1020
1021isEmpty(value);
1022isBoolean(value);
1023```
1024
1025## Validation decorators
1026
1027<!-- Disable table formatting because Prettier messing it up. -->
1028<!-- prettier-ignore -->
1029| Decorator | Description |
1030| ------------------------------------------------| ----------- |
1031| **Common validation decorators** | |
1032| `@IsDefined(value: any)` | Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option. |
1033| `@IsOptional()` | Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property. |
1034| `@Equals(comparison: any)` | Checks if value equals ("===") comparison. |
1035| `@NotEquals(comparison: any)` | Checks if value not equal ("!==") comparison. |
1036| `@IsEmpty()` | Checks if given value is empty (=== '', === null, === undefined). |
1037| `@IsNotEmpty()` | Checks if given value is not empty (!== '', !== null, !== undefined). |
1038| `@IsIn(values: any[])` | Checks if value is in a array of allowed values. |
1039| `@IsNotIn(values: any[])` | Checks if value is not in a array of disallowed values. |
1040| **Type validation decorators** | |
1041| `@IsBoolean()` | Checks if a value is a boolean. |
1042| `@IsDate()` | Checks if the value is a date. |
1043| `@IsString()` | Checks if the string is a string. |
1044| `@IsNumber(options: IsNumberOptions)` | Checks if the value is a number. |
1045| `@IsInt()` | Checks if the value is an integer number. |
1046| `@IsArray()` | Checks if the value is an array |
1047| `@IsEnum(entity: object)` | Checks if the value is an valid enum |
1048| **Number validation decorators** |
1049| `@IsDivisibleBy(num: number)` | Checks if the value is a number that's divisible by another. |
1050| `@IsPositive()` | Checks if the value is a positive number greater than zero. |
1051| `@IsNegative()` | Checks if the value is a negative number smaller than zero. |
1052| `@Min(min: number)` | Checks if the given number is greater than or equal to given number. |
1053| `@Max(max: number)` | Checks if the given number is less than or equal to given number. |
1054| **Date validation decorators** |
1055| `@MinDate(date: Date)` | Checks if the value is a date that's after the specified date. |
1056| `@MaxDate(date: Date)` | Checks if the value is a date that's before the specified date. |
1057| **String-type validation decorators** | |
1058| `@IsBooleanString()` | Checks if a string is a boolean (e.g. is "true" or "false"). |
1059| `@IsDateString()` | Alias for `@IsISO8601()`. |
1060| `@IsNumberString(options?: IsNumericOptions)` | Checks if a string is a number. |
1061| **String validation decorators** | |
1062| `@Contains(seed: string)` | Checks if the string contains the seed. |
1063| `@NotContains(seed: string)` | Checks if the string not contains the seed. |
1064| `@IsAlpha()` | Checks if the string contains only letters (a-zA-Z). |
1065| `@IsAlphanumeric()` | Checks if the string contains only letters and numbers. |
1066| `@IsDecimal(options?: IsDecimalOptions)` | Checks if the string is a valid decimal value. Default IsDecimalOptions are `force_decimal=False`, `decimal_digits: '1,'`, `locale: 'en-US'` |
1067| `@IsAscii()` | Checks if the string contains ASCII chars only. |
1068| `@IsBase32()` | Checks if a string is base32 encoded. |
1069| `@IsBase64()` | Checks if a string is base64 encoded. |
1070| `@IsIBAN()` | Checks if a string is a IBAN (International Bank Account Number). |
1071| `@IsBIC()` | Checks if a string is a BIC (Bank Identification Code) or SWIFT code. |
1072| `@IsByteLength(min: number, max?: number)` | Checks if the string's length (in bytes) falls in a range. |
1073| `@IsCreditCard()` | Checks if the string is a credit card. |
1074| `@IsCurrency(options?: IsCurrencyOptions)` | Checks if the string is a valid currency amount. |
1075| `@IsEthereumAddress()` | Checks if the string is an Ethereum address using basic regex. Does not validate address checksums. |
1076| `@IsBtcAddress()` | Checks if the string is a valid BTC address. |
1077| `@IsDataURI()` | Checks if the string is a data uri format. |
1078| `@IsEmail(options?: IsEmailOptions)` | Checks if the string is an email.|
1079| `@IsFQDN(options?: IsFQDNOptions)` | Checks if the string is a fully qualified domain name (e.g. domain.com). |
1080| `@IsFullWidth()` | Checks if the string contains any full-width chars. |
1081| `@IsHalfWidth()` | Checks if the string contains any half-width chars. |
1082| `@IsVariableWidth()` | Checks if the string contains a mixture of full and half-width chars. |
1083| `@IsHexColor()` | Checks if the string is a hexadecimal color. |
1084| `@IsHSLColor()` | Checks if the string is an HSL color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value). |
1085| `@IsRgbColor(options?: IsRgbOptions)` | Checks if the string is a rgb or rgba color. |
1086| `@IsIdentityCard(locale?: string)` | Checks if the string is a valid identity card code. |
1087| `@IsPassportNumber(countryCode?: string)` | Checks if the string is a valid passport number relative to a specific country code. |
1088| `@IsPostalCode(locale?: string)` | Checks if the string is a postal code. |
1089| `@IsHexadecimal()` | Checks if the string is a hexadecimal number. |
1090| `@IsOctal()` | Checks if the string is a octal number. |
1091| `@IsMACAddress(options?: IsMACAddressOptions)` | Checks if the string is a MAC Address. |
1092| `@IsIP(version?: "4"\|"6")` | Checks if the string is an IP (version 4 or 6). |
1093| `@IsPort()` | Checks if the string is a valid port number. |
1094| `@IsISBN(version?: "10"\|"13")` | Checks if the string is an ISBN (version 10 or 13). |
1095| `@IsEAN()` | Checks if the string is an if the string is an EAN (European Article Number). |
1096| `@IsISIN()` | Checks if the string is an ISIN (stock/security identifier). |
1097| `@IsISO8601(options?: IsISO8601Options)` | Checks if the string is a valid ISO 8601 date format. Use the option strict = true for additional checks for a valid date. |
1098| `@IsJSON()` | Checks if the string is valid JSON. |
1099| `@IsJWT()` | Checks if the string is valid JWT. |
1100| `@IsObject()` | Checks if the object is valid Object (null, functions, arrays will return false). |
1101| `@IsNotEmptyObject()` | Checks if the object is not empty. |
1102| `@IsLowercase()` | Checks if the string is lowercase. |
1103| `@IsLatLong()` | Checks if the string is a valid latitude-longitude coordinate in the format lat, long. |
1104| `@IsLatitude()` | Checks if the string or number is a valid latitude coordinate. |
1105| `@IsLongitude()` | Checks if the string or number is a valid longitude coordinate. |
1106| `@IsMobilePhone(locale: string)` | Checks if the string is a mobile phone number. |
1107| `@IsISO31661Alpha2()` | Checks if the string is a valid ISO 3166-1 alpha-2 officially assigned country code. |
1108| `@IsISO31661Alpha3()` | Checks if the string is a valid ISO 3166-1 alpha-3 officially assigned country code. |
1109| `@IsLocale()` | Checks if the string is a locale. |
1110| `@IsPhoneNumber(region: string)` | Checks if the string is a valid phone numberusing libphonenumber-js. |
1111| `@IsMongoId()` | Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. |
1112| `@IsMultibyte()` | Checks if the string contains one or more multibyte chars. |
1113| `@IsNumberString(options?: IsNumericOptions)` | Checks if the string is numeric. |
1114| `@IsSurrogatePair()` | Checks if the string contains any surrogate pairs chars. |
1115| `@IsUrl(options?: IsURLOptions)` | Checks if the string is an url. |
1116| `@IsMagnetURI()` | Checks if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme). |
1117| `@IsUUID(version?: "3"\|"4"\|"5"\|"all")` | Checks if the string is a UUID (version 3, 4, 5 or all ). |
1118| `@IsFirebasePushId()` | Checks if the string is a [Firebase Push ID](https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html) |
1119| `@IsUppercase()` | Checks if the string is uppercase. |
1120| `@Length(min: number, max?: number)` | Checks if the string's length falls in a range. |
1121| `@MinLength(min: number)` | Checks if the string's length is not less than given number. |
1122| `@MaxLength(max: number)` | Checks if the string's length is not more than given number. |
1123| `@Matches(pattern: RegExp, modifiers?: string)` | Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). |
1124| `@IsMilitaryTime()` | Checks if the string is a valid representation of military time in the format HH:MM. |
1125| `@IsHash(algorithm: string)` | Checks if the string is a hash The following types are supported:`md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `ripemd128`, `ripemd160`, `tiger128`, `tiger160`, `tiger192`, `crc32`, `crc32b`. |
1126| `@IsMimeType()` | Checks if the string matches to a valid [MIME type](https://en.wikipedia.org/wiki/Media_type) format |
1127| `@IsSemVer()` | Checks if the string is a Semantic Versioning Specification (SemVer). |
1128| `@IsISSN(options?: IsISSNOptions)` | Checks if the string is a ISSN. |
1129| `@IsISRC()` | Checks if the string is a [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code). |
1130| `@IsRFC3339()` | Checks if the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date. |
1131| **Array validation decorators** | |
1132| `@ArrayContains(values: any[])` | Checks if array contains all values from the given array of values. |
1133| `@ArrayNotContains(values: any[])` | Checks if array does not contain any of the given values. |
1134| `@ArrayNotEmpty()` | Checks if given array is not empty. |
1135| `@ArrayMinSize(min: number)` | Checks if the array's length is greater than or equal to the specified number. |
1136| `@ArrayMaxSize(max: number)` | Checks if the array's length is less or equal to the specified number. |
1137| `@ArrayUnique(identifier?: (o) => any)` | Checks if all array's values are unique. Comparison for objects is reference-based. Optional function can be speciefied which return value will be used for the comparsion. |
1138| **Object validation decorators** |
1139| `@IsInstance(value: any)` | Checks if the property is an instance of the passed value. |
1140| **Other decorators** | |
1141| `@Allow()` | Prevent stripping off the property when no other constraint is specified for it. |
1142
1143## Defining validation schema without decorators
1144
1145You can define your validation schemas without decorators:
1146
1147- you can define it in the separate object
1148- you can define it in the `.json` file
1149
1150This feature maybe useful in the cases if:
1151
1152- are using es5/es6 and don't have decorators available
1153- you don't have a classes, and instead using interfaces
1154- you don't want to use model at all
1155- you want to have a validation schema separate of your model
1156- you want beautiful json-schema based validation models
1157- you simply hate decorators
1158
1159Here is an example of using it:
1160
11611. Create a schema object:
1162
1163 ```typescript
1164 import { ValidationSchema } from 'class-validator-multi-lang';
1165 export let UserValidationSchema: ValidationSchema = {
1166 // using interface here is not required, its just for type-safety
1167 name: 'myUserSchema', // this is required, and must be unique
1168 properties: {
1169 firstName: [
1170 {
1171 type: 'minLength', // validation type. All validation types are listed in ValidationTypes class.
1172 constraints: [2],
1173 },
1174 {
1175 type: 'maxLength',
1176 constraints: [20],
1177 },
1178 ],
1179 lastName: [
1180 {
1181 type: 'minLength',
1182 constraints: [2],
1183 },
1184 {
1185 type: 'maxLength',
1186 constraints: [20],
1187 },
1188 ],
1189 email: [
1190 {
1191 type: 'isEmail',
1192 },
1193 ],
1194 },
1195 };
1196 ```
1197
1198 Same schema can be provided in `.json` file, depend on your wish.
1199
12002. Register your schema:
1201
1202 ```typescript
1203 import { registerSchema } from 'class-validator-multi-lang';
1204 import { UserValidationSchema } from './UserValidationSchema';
1205 registerSchema(UserValidationSchema); // if schema is in .json file, then you can simply do registerSchema(require("path-to-schema.json"));
1206 ```
1207
1208 Better to put this code in a global place, maybe when you bootstrap your application, for example in `app.ts`.
1209
12103. Validate your object using validation schema:
1211
1212 ```typescript
1213 import { validate } from 'class-validator-multi-lang';
1214 const user = { firstName: 'Johny', secondName: 'Cage', email: 'johny@cage.com' };
1215 validate('myUserSchema', user).then(errors => {
1216 if (errors.length > 0) {
1217 console.log('Validation failed: ', errors);
1218 } else {
1219 console.log('Validation succeed.');
1220 }
1221 });
1222 ```
1223
1224 That's it. Here `"myUserSchema"` is the name of our validation schema.
1225 `validate` method will perform validation based on this schema
1226
1227## Validating plain objects
1228
1229Due to nature of the decorators, the validated object has to be instantiated using `new Class()` syntax. If you have your class defined using class-validator decorators and you want to validate plain JS object (literal object or returned by JSON.parse), you need to transform it to the class instance via using [class-transformer](https://github.com/pleerock/class-transformer)).
1230
1231## Basic support i18n
1232
1233Translations created with the machine, if you found the mistake please add a new version of translate and write a comment in the right panel in https://crowdin.com/
1234
1235Basic set custom messages
1236
1237```typescript
1238import { IsOptional, Equals, Validator } from 'class-validator-multi-lang';
1239
1240class MyClass {
1241 @IsOptional()
1242 @Equals('test')
1243 title: string = 'bad_value';
1244}
1245
1246const RU_I18N_MESSAGES = {
1247 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
1248};
1249
1250const model = new MyClass();
1251
1252validator.validate(model, messages: RU_I18N_MESSAGES).then(errors => {
1253 console.log(errors[0].constraints);
1254 // out: title должно быть равно test
1255});
1256```
1257
1258Load from file
1259
1260```typescript
1261import { IsOptional, Equals, Validator } from 'class-validator-multi-lang';
1262import { readFileSync } from 'fs';
1263import { resolve } from 'path';
1264
1265class MyClass {
1266 @IsOptional()
1267 @Equals('test')
1268 title: string = 'bad_value';
1269}
1270
1271const RU_I18N_MESSAGES = JSON.parse(readFileSync(resolve(__dirname, './node_modules/class-validator-multi-lang/i18n/ru.json')).toString());
1272
1273const model = new MyClass();
1274
1275validator.validate(model, messages: RU_I18N_MESSAGES).then(errors => {
1276 console.log(errors[0].constraints);
1277 // out: title должен быть равен test
1278});
1279```
1280
1281With override
1282
1283```typescript
1284import { IsOptional, Equals, Validator, setClassValidatorMessages } from 'class-validator-multi-lang';
1285
1286class MyClass {
1287 @IsOptional()
1288 @Equals('test')
1289 title: string = 'bad_value';
1290}
1291
1292setClassValidatorMessages({
1293 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
1294});
1295
1296const model = new MyClass();
1297
1298validator.validate(model).then(errors => {
1299 console.log(errors[0].constraints);
1300 // out: title должно быть равно test
1301});
1302```
1303
1304With change property name
1305
1306```typescript
1307import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator-multi-lang';
1308
1309class MyClass {
1310 @IsOptional()
1311 @Equals('test')
1312 @ClassPropertyTitle('property "title"')
1313 title: string = 'bad_value';
1314}
1315
1316const RU_I18N_MESSAGES = {
1317 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
1318};
1319const RU_I18N_TITLES = {
1320 'property "title"': 'поле "заголовок"',
1321};
1322
1323const model = new MyClass();
1324
1325validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1326 console.log(errors[0].constraints);
1327 // out: поле "заголовок" должно быть равно test
1328});
1329```
1330
1331With change target name
1332
1333```typescript
1334import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator-multi-lang';
1335
1336@ClassTitle('object "MyClass"')
1337class MyClass {
1338 @IsOptional()
1339 @Equals('test')
1340 title: string = 'bad_value';
1341}
1342
1343const RU_I18N_MESSAGES = {
1344 '$property must be equal to $constraint1': '$property в $target должно быть равно $constraint1',
1345};
1346const RU_I18N_TITLES = {
1347 'object "MyClass"': 'объекте "МойКласс"',
1348};
1349
1350const model = new MyClass();
1351
1352validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1353 console.log(errors[0].constraints);
1354 // out: title в объекте "МойКласс" должно быть равно test
1355});
1356```
1357
1358With change arguments for validation decorator
1359
1360```typescript
1361import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
1362
1363class MyClass {
1364 @IsOptional()
1365 @Equals('test')
1366 title: string = 'bad_value';
1367}
1368
1369const RU_I18N_MESSAGES = {
1370 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
1371};
1372const RU_I18N_TITLES = {
1373 test: '"тест"',
1374};
1375
1376const model = new MyClass();
1377
1378validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1379 console.log(errors[0].constraints);
1380 // out: title должно быть равно "тест"
1381});
1382```
1383
1384With change value
1385
1386```typescript
1387import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
1388
1389class MyClass {
1390 @IsOptional()
1391 @Equals('test')
1392 title: string = 'bad_value';
1393}
1394
1395const RU_I18N_MESSAGES = {
1396 '$property must be equal to $constraint1': '$property равно $value, а должно быть равно $constraint1',
1397};
1398const RU_I18N_TITLES = {
1399 bad_value: '"плохое_значение"',
1400};
1401
1402const model = new MyClass();
1403
1404validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1405 console.log(errors[0].constraints);
1406 // out: title равно "плохое_значение", а должно быть равно test
1407});
1408```
1409
1410🔢 With change property name
1411
1412```typescript
1413import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator-multi-lang';
1414
1415class MyClass {
1416 @IsOptional()
1417 @Equals('test')
1418 @ClassPropertyTitle('property "title"')
1419 title: string = 'bad_value';
1420}
1421
1422const RU_I18N_MESSAGES = {
1423 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
1424};
1425const RU_I18N_TITLES = {
1426 'property "title"': 'поле "заголовок"',
1427};
1428
1429const model = new MyClass();
1430
1431validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1432 console.log(errors[0].constraints);
1433 // out: поле "заголовок" должно быть равно test
1434});
1435```
1436
1437🔢 With change target name
1438
1439```typescript
1440import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator-multi-lang';
1441
1442@ClassTitle('object "MyClass"')
1443class MyClass {
1444 @IsOptional()
1445 @Equals('test')
1446 title: string = 'bad_value';
1447}
1448
1449const RU_I18N_MESSAGES = {
1450 '$property must be equal to $constraint1': '$property в $target должно быть равно $constraint1',
1451};
1452const RU_I18N_TITLES = {
1453 'object "MyClass"': 'объекте "МойКласс"',
1454};
1455
1456const model = new MyClass();
1457
1458validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1459 console.log(errors[0].constraints);
1460 // out: title в объекте "МойКласс" должно быть равно test
1461});
1462```
1463
1464🔢 With change arguments for validation decorator
1465
1466```typescript
1467import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
1468
1469class MyClass {
1470 @IsOptional()
1471 @Equals('test')
1472 title: string = 'bad_value';
1473}
1474
1475const RU_I18N_MESSAGES = {
1476 '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
1477};
1478const RU_I18N_TITLES = {
1479 test: '"тест"',
1480};
1481
1482const model = new MyClass();
1483
1484validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1485 console.log(errors[0].constraints);
1486 // out: title должно быть равно "тест"
1487});
1488```
1489
1490🔢 With change value
1491
1492```typescript
1493import { IsOptional, Equals, validator } from 'class-validator-multi-lang';
1494
1495class MyClass {
1496 @IsOptional()
1497 @Equals('test')
1498 title: string = 'bad_value';
1499}
1500
1501const RU_I18N_MESSAGES = {
1502 '$property must be equal to $constraint1': '$property равно $value, а должно быть равно $constraint1',
1503};
1504const RU_I18N_TITLES = {
1505 bad_value: '"плохое_значение"',
1506};
1507
1508const model = new MyClass();
1509
1510validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
1511 console.log(errors[0].constraints);
1512 // out: title равно "плохое_значение", а должно быть равно test
1513});
1514```
1515
1516## Samples
1517
1518Take a look on samples in [./sample](https://github.com/pleerock/class-validator/tree/master/sample) for more examples of
1519usages.
1520
1521## Extensions
1522
1523There are several extensions that simplify class-validator integration with other modules:
1524
1525- [class-validator integration](https://github.com/19majkel94/class-transformer-validator) with [class-transformer](https://github.com/pleerock/class-transformer)
1526- [class-validator-rule](https://github.com/yantrab/class-validator-rule)
1527- [ngx-dynamic-form-builder](https://github.com/EndyKaufman/ngx-dynamic-form-builder)
1528- [abarghoud/ngx-reactive-form-class-validator](https://github.com/abarghoud/ngx-reactive-form-class-validator)
1529
1530## Release notes
1531
1532See information about breaking changes and release notes [here][3].
1533
1534[1]: https://github.com/chriso/validator.js
1535[2]: https://github.com/pleerock/typedi
1536[3]: CHANGELOG.md