Skip to content

feat: add support mega feature for multi-lang #743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from

Conversation

EndyKaufman
Copy link

@EndyKaufman EndyKaufman commented Sep 3, 2020

Description

It is a very cool library, but we waited many years of support multi-language 😢
This PR has added this feature 🔥 🔥 🔥

:godmode: Basic set custom messages

import { IsOptional, Equals, validator} from 'class-validator';

class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = {
  '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
};

const model = new MyClass();

validator.validate(model, messages: RU_I18N_MESSAGES).then(errors => {
  console.log(errors[0].constraints);
  // out: title должно быть равно test
});

:rage3: Load from file

import { IsOptional, Equals, validator} from 'class-validator';
import { readFileSync } from 'fs';
import { resolve } from 'path';

class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = JSON.parse(readFileSync(resolve(__dirname, './node_modules/class-validator/i18n/ru.json')).toString());

const model = new MyClass();

validator.validate(model, messages: RU_I18N_MESSAGES).then(errors => {
  console.log(errors[0].constraints);
  // out: title должен быть равен test
});

:goberserk: Load from 2 file 💣 💥

import { IsOptional, Equals, validator} from 'class-validator';
import { readFileSync } from 'fs';
import { resolve } from 'path';

class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = JSON.parse(readFileSync(resolve(__dirname, './node_modules/class-validator/i18n/ru.json')).toString());

const FR_I18N_MESSAGES = JSON.parse(readFileSync(resolve(__dirname, './node_modules/class-validator/i18n/fr.json')).toString());

const model = new MyClass();

validator.validate(model, { messages: RU_I18N_MESSAGES }).then(errors => {
  console.log(errors[0].constraints);
  // out: title должно быть равно test

  validator.validate(model, { messages: FR_I18N_MESSAGES }).then(errors => {
    console.log(errors[0].constraints);
    // out: title doit être égal à test
  });
});

:feelsgood: With override

import { IsOptional, Equals, validator, setClassValidatorMessages} from 'class-validator';

class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

setClassValidatorMessages({
  '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
});

const model = new MyClass();

validator.validate(model).then(errors => {
  console.log(errors[0].constraints);
  // out: title должно быть равно test
});

🔥 This feature added support integrations with https://crowdin.com/ for manual simplified update translates 🇨🇳 🇩🇪 🇷🇺 🇺🇸
🌎 Translations 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/project/class-validator 😎

Checklist

  • the pull request title describes what this PR does (not a vague title like Update index.md)
  • the pull request targets the default branch of the repository (develop)
  • the code follows the established code style of the repository
    • npm run prettier:check passes
    • npm run lint:check passes
  • tests are added for the changes I made (if any source code was modified)
  • documentation added or updated
  • I have run the project locally and verified that there are no errors

Fixes

fixes #169

@EndyKaufman EndyKaufman changed the title feat: 🔥 add support multi-lang 🎉 🔥 feat: add support mega feature for multi-lang Sep 3, 2020
@EndyKaufman EndyKaufman mentioned this pull request Sep 3, 2020
6 tasks
@dkantereivin
Copy link

The PR description doesn't clearly explain what it's actually accomplishing and how, other than claiming to provide multilingual support... this is unclear: is it allowing localization features to be manually implemented, or does it do this automatically? For which decorators exactly? What are the behaviors?

Further, this single mega-commit PR (145 files in one commit, +12700 lines, ginormous!) has a huge amount of undocumented changes which are not explained and potentially introduce a substantial amount of maintenance overhead for what seems like a very small if present use case. I also can't think of any real use cases for localized validation -- anything that actually does differ between languages (and requires validation) can easily be validating using existing decorators. I don't see any linked issues or previous discussion either... just a ginormous PR out of nowhere.

Plus, it introduces two dependencies (out of nowhere?) and a whole bunch of localization files, while claiming to use Crowdin for localization?

Needs a lot of clarification imo.

@EndyKaufman
Copy link
Author

Hi @dkantereivin, thanks for the comment

There is not much real code there, I just wrapped all the texts with checks with the getText method, which simply decorates the lines for further replacement and parsing.

Added the ability to pass a dictionary with these keys to the validator launch parameters.

When generating an error response, the strings enclosed in getText are replaced with whatever was passed in the parameters, or the default English language is used.

All found strings are saved to a template file, which Crowdin monitors and creates translation files.

It's simple.

@dkantereivin
Copy link

I still don't understand why language localization features belong in a class validation utility. Users who need this functionality are more than welcome to implement it themselves. Just my 2 cents though, I'm not a maintainer or anything so it's ultimately up to them.

@EndyKaufman
Copy link
Author

Current the lines are built into the library, replace them with your own, there is no way when the front requests data from the back, the back always returns English errors, you have to write your own text for each error, 10,000 error lines happen, if the PR is accepted, there will be a maximum of 30 typical

@dkantereivin
Copy link

I don't see why people can't wrap their own decorators for this validation feature, and then simply use the existing validation libraries and services that are out there to perform this exact same function - or write their own. Since this seems to use a specific localization service and mechanism, it seems like a different library?

I'll leave this to the maintainers.

@EndyKaufman
Copy link
Author

The lines with the text of the errors are hardcoded in the code, you need access to them, if the PR does not accept, I will make a fork and publish it, it's not difficult, it's just that many people need this feature, not only me, so I did the PR

@EndyKaufman
Copy link
Author

Since this PR was checked for a long time, I had to send a fork to the npm register, if the current changes are accepted, then the created package will be marked "unnecessary"

https://www.npmjs.com/package/class-validator-multi-lang

@kkoomen
Copy link

kkoomen commented Sep 10, 2020

+1 for the effort that has been put into this. Would like to see this merged ASAP.

@EndyKaufman
Copy link
Author

Add feature for translate not only error messages

🔢 With change property name

import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator';

class MyClass {
  @IsOptional()
  @Equals('test')
  @ClassPropertyTitle('property "title"')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = {
  '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
};
const RU_I18N_TITLES = {
  'property "title"': 'поле "заголовок"',
};

const model = new MyClass();

validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
  console.log(errors[0].constraints);
  // out: поле "заголовок" должно быть равно test
});

🔢 With change target name

import { IsOptional, Equals, ClassPropertyTitle, validator } from 'class-validator';

@ClassTitle('object "MyClass"')
class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = {
  '$property must be equal to $constraint1': '$property в $target должно быть равно $constraint1',
};
const RU_I18N_TITLES = {
  'object "MyClass"': 'объекте "МойКласс"',
};

const model = new MyClass();

validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
  console.log(errors[0].constraints);
  // out: title в объекте "МойКласс" должно быть равно test
});

🔢 With change arguments for validation decorator

import { IsOptional, Equals, validator } from 'class-validator';

class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = {
  '$property must be equal to $constraint1': '$property должно быть равно $constraint1',
};
const RU_I18N_TITLES = {
  test: '"тест"',
};

const model = new MyClass();

validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
  console.log(errors[0].constraints);
  // out: title должно быть равно "тест"
});

🔢 With change value

import { IsOptional, Equals, validator } from 'class-validator';

class MyClass {
  @IsOptional()
  @Equals('test')
  title: string = 'bad_value';
}

const RU_I18N_MESSAGES = {
  '$property must be equal to $constraint1': '$property равно $value, а должно быть равно $constraint1',
};
const RU_I18N_TITLES = {
  bad_value: '"плохое_значение"',
};

const model = new MyClass();

validator.validate(model, { messages: RU_I18N_MESSAGES, titles: RU_I18N_TITLES }).then(errors => {
  console.log(errors[0].constraints);
  // out: title равно "плохое_значение", а должно быть равно test
});

@kkoomen
Copy link

kkoomen commented Sep 12, 2020

@EndyKaufman How is this integratable with NestJS? There'll be quite an audiance that'll use it with NestJS, the same for me. I really want to configure this globally for my project to use the Chinese version by default. How can this be achieved?

Another scenario I'd like to point it: in our current NestJS app we use an interceptor to check the language header being sent from our front-end and then use i18next.changeLanguage() to switch languages. This way you can change the language how you'd like your response to be just by passing in a language header. Is it possible to switch languages dynamically at runtime? If not, would love to see this because this is a big requirement for our project.

@EndyKaufman
Copy link
Author

Hi, @kkoomen

I started npm module for nest js with support this feature, I publish it later

Now you can override global wih

setClassValidatorMessages

For dynamic change and use language from header

You must write custom validation pipe and set message options on run validate

@kkoomen
Copy link

kkoomen commented Sep 14, 2020

I started npm module for nest js with support this feature, I publish it later

@EndyKaufman When do you think you can publish this? We're waiting for it and could highly use this.

@kkoomen
Copy link

kkoomen commented Sep 27, 2020

@EndyKaufman Any update?

@NoNameProvided
Copy link
Member

Hi @EndyKaufman!

Thanks for taking the time to open the PR but I will go ahead and close this for the reasons explained by @dkantereivin in the first comment. Why in the long-term I believe we can provide some building blocks to help localization we first have more important things to take care of in the lib.

@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging this pull request may close these issues.

How to customize validation messages globally?
4 participants