-
first install it
npm i class-validator-translator-middleware
-
Now create a directory wherever you want and name it what ever you like but I use class-validator-errors:
mkdir src/class-validator-errors
-
Then you should create
error-codes.json
in that directory:touch src/class-validator-errors/error-codes.json
-
Now in it you have to define your error codes like this.
{ "title_should_be_sample": "title_should_be_sample" }
-
Now you must define your error locale messages in separated files on that directory. E.X. you should
touch src/class-validator-errors/en.json
and in that file you have:{ "title_should_be_sample": "sample is good" }
And Also
touch src/class-validator-errors/fa.json
:{ "title_should_be_sample": "تست خوبه" }
Important note: You cannot define an error code in
error-codes.json
but it had no defined error message in your error locale messages. If you do this intentionally or accidentally you will get an error while creating a new instance ofClassValidatorTranslatorMiddleware
, The thrown error is instance of this error custom error class:IncompatibleErrorCodeAndErrorMessage
.Since I am reading the error messages using require, they will be cached in the memory and this will prevent unnecessary reads from file system. for more info please read
ClassValidatorTranslatorMiddleware
codes 🤩Note if you are using tsc: because we will never ever use fa.json and other json files you have to include this unused json files in your
tsconfig.json
/tsconfig.build.json
file like this (If you do not include your fa.json, en.json, ... files will not be in the compiled version. unless you import them implicitly):{ "include": ["src", "src/**/*.json"] // ... }
I client side sends an locale that you do not defined its error-message file in the
class-validator-errors
directory you will get An error in the next error handler middleware. In this case you will get an error that it is instance ofSpecifiedErrorMessageFileNotFound
. -
Your frontend have to specify the
accept-language
header in their requests and it should be within theLocale
enum. -
Final examples:
-
Here is one example in ExpressJS:
// app.ts import { join } from 'path'; import { Equals, IsOptional } from 'class-validator'; import { ClassValidatorTranslatorMiddleware, IncompatibleErrorCodeAndErrorMessage } from 'class-validator-translator-middleware'; process.on('uncaughtException', (error) => { if (error instanceof IncompatibleErrorCodeAndErrorMessage) { // do what ever you like, like sending email/notification to your devops guy process.exit(1); } }) const messagesPath = join(__dirname, 'class-validator-errors'); const classValidatorTranslatorMiddleware = new ClassValidatorTranslatorMiddleware(messagesPath); const classValidatorTranslatorMiddleware = new ClassValidatorTranslatorMiddleware(messagesPath); app.use(classValidatorTranslatorMiddleware.middleware); // this can be your class validator class TestClassValidator { @IsOptional() @Equals('sample', { message: 'title_should_be_sample' }) title: string = 'bad_value'; } app.use((error, req, res, next) => { for (const error of errors) { console.log(error.constraints); // تست خوبه } }); ```
-
Here is one example in routing controller
// messages.ts import { ClassValidatorTranslatorMiddleware } from 'class-validator-translator-middleware'; // city-filter.ts import { IsBoolean, IsAlpha, IsOptional, } from 'class-validator'; export class CityFilterQuery { @IsOptional() @IsAlpha('en', { message: 'serviced_should_be_boolean_not_empty', }) @IsBoolean({ message: 'serviced_should_be_boolean' }) serviced?: boolean; } // class-validator-error-translator.middleware.ts import { join } from 'path'; import { ValidationError } from 'class-validator'; import { Middleware, ExpressErrorMiddlewareInterface, HttpError, } from 'routing-controllers'; import { NextFunction, Request, Response } from 'express'; import { ClassValidatorTranslatorMiddleware } from 'class-validator-translator-middleware'; const messagesPath = join( __dirname, 'class-validator-errors', ); const classValidatorTranslatorMiddleware = new ClassValidatorTranslatorMiddleware(messagesPath); class CustomValidationError { errors: ValidationError[]; status?: number; statusCode?: number; } @Middleware({ type: 'after' }) export class ClassValidatorErrorTranslator implements ExpressErrorMiddlewareInterface { error( error: HttpError | CustomValidationError, request: Request, response: Response, next: NextFunction, ): void { classValidatorTranslatorMiddleware.middleware( error, request, response, next, ); } } // another middleware import { ValidationError } from 'class-validator'; import { Middleware, ExpressErrorMiddlewareInterface, HttpError, } from 'routing-controllers'; import { NextFunction, Request, Response } from 'express'; import { SpecifiedErrorMessageFileNotFound } from 'class-validator-translator-middleware'; @Middleware({ type: 'after' }) export class ClassValidatorErrorTranslator implements ExpressErrorMiddlewareInterface { error( error: HttpError | CustomValidationError, request: Request, response: Response, next: NextFunction, ): void { if ( error instanceof SpecifiedErrorMessageFileNotFound ) { // do whatever you want. response.status(400).json({ message: 'un-supported-language', }); } next(error); } } // app.ts import { ClassValidatorErrorTranslator } from './middlewares/class-validator-error-translator.middleware'; import express from 'express'; const app = express(); const routingControllersOptions: RoutingControllersOptions = { controllers: [ /* controllers */ ], middlewares: [ClassValidatorErrorTranslator], /* other configs */ validation: { whitelist: true, }, }; useExpressServer(app, routingControllersOptions);
-
Language | Code |
---|---|
Abkhazian | AB |
Afar | AA |
Afrikaans | AF |
Albanian | SQ |
Amharic | AM |
Arabic | AR |
Armenian | HY |
Assamese | AS |
Aymara | AY |
Azerbaijani | AZ |
Bashkir | BA |
Basque | EU |
Bengali, Bangla | BN |
Bhutani | DZ |
Bihari | BH |
Bislama | BI |
Breton | BR |
Bulgarian | BG |
Burmese | MY |
Byelorussian | BE |
Cambodian | KM |
Catalan | CA |
Chinese | ZH |
Corsican | CO |
Croatian | HR |
Czech | CS |
Danish | DA |
Dutch | NL |
English, American | EN |
Esperanto | EO |
Estonian | ET |
Faeroese | FO |
Fiji | FJ |
Finnish | FI |
French | FR |
Frisian | FY |
Gaelic (Scots Gaelic) | GD |
Galician | GL |
Georgian | KA |
German | DE |
Greek | EL |
Greenlandic | KL |
Guarani | GN |
Gujarati | GU |
Hausa | HA |
Hebrew | IW |
Hindi | HI |
Hungarian | HU |
Icelandic | IS |
Indonesian | IN |
Interlingua | IA |
Interlingue | IE |
Inupiak | IK |
Irish | GA |
Italian | IT |
Japanese | JA |
Javanese | JW |
Kannada | KN |
Kashmiri | KS |
Kazakh | KK |
Kinyarwanda | RW |
Kirghiz | KY |
Kirundi | RN |
Korean | KO |
Kurdish | KU |
Laothian | LO |
Latin | LA |
Latvian, Lettish | LV |
Lingala | LN |
Lithuanian | LT |
Macedonian | MK |
Malagasy | MG |
Malay | MS |
Malayalam | ML |
Maltese | MT |
Maori | MI |
Marathi | MR |
Moldavian | MO |
Mongolian | MN |
Nauru | NA |
Nepali | NE |
Norwegian | NO |
Occitan | OC |
Oriya | OR |
Oromo, Afan | OM |
Pashto, Pushto | PS |
Persian | FA |
Polish | PL |
Portuguese | PT |
Punjabi | PA |
Quechua | QU |
Rhaeto-Romance | RM |
Romanian | RO |
Russian | RU |
Samoan | SM |
Sangro | SG |
Sanskrit | SA |
Serbian | SR |
Serbo-Croatian | SH |
Sesotho | ST |
Setswana | TN |
Shona | SN |
Sindhi | SD |
Singhalese | SI |
Siswati | SS |
Slovak | SK |
Slovenian | SL |
Somali | SO |
Spanish | ES |
Sudanese | SU |
Swahili | SW |
Swedish | SV |
Tagalog | TL |
Tajik | TG |
Tamil | TA |
Tatar | TT |
Tegulu | TE |
Thai | TH |
Tibetan | BO |
Tigrinya | TI |
Tonga | TO |
Tsonga | TS |
Turkish | TR |
Turkmen | TK |
Twi | TW |
Ukrainian | UK |
Urdu | UR |
Uzbek | UZ |
Vietnamese | VI |
Volapuk | VO |
Welsh | CY |
Wolof | WO |
Xhosa | XH |
Yiddish | JI |
Yoruba | YO |
Zulu | ZU |
- I had no time to add all the languages in the Locale
- Please use it with Typescript to prevent any unexpected behaviours
- Feel free to create issue or pull request
- Clone repository
npm i; npm i prepeare
- Create a new branch from
develop
branch (git checkout -b develop-your-name
) - Write you code
- Write its tests in tests directory
- run
npm test
and make sure it works perfectly