Skip to content

[RFC][Validator] Allow to set the translation domain or disable translations on a per-constraint level #59770

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

Open
wants to merge 4 commits into
base: 7.3
Choose a base branch
from

Conversation

mpdude
Copy link
Contributor

@mpdude mpdude commented Feb 13, 2025

Q A
Branch? 7.3
Bug fix? no
New feature? yes
Deprecations? no
Issues
License MIT

This PR builds upon the work in #48852 and makes it possible to specify the translation domain for validation constraints on a per-constraint level. This can happen either when using the constraint as an attribute, or when creating constraint instances e. g. when building a form.

   $formBuilder
            ->add('some_field', TextType::class, [
                'label' => 'Something',
                'constraints' => [new NotBlank(['message' => 'standard.notblank.message', 'translation_domain' => 'my_special_domain'])],
            ])
            ->add('other_field', TextType::class, [
                'label' => 'Elsething',
                'constraints' => [new NotBlank(['message' => 'Use this text as-is, do not attempt to translate', 'translation_domain' => false])],
            ]);

The setting works similar to the translation_domain option for form types. Setting it to false disables translations (for that constraint) altogether.

TODO

  •  Add documentation PR
  • Apply enhancement to all constraints once we agree on the basics; for now, it's just NotBlank
  • Add tests
  • Update src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php

@carsonbot carsonbot added this to the 7.3 milestone Feb 13, 2025
@mpdude mpdude changed the title Allow to set the translation domain or disable translations on a per-constraint level [RFC][Validator] Allow to set the translation domain or disable translations on a per-constraint level Feb 13, 2025
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there really a use case for that?

@mpdude
Copy link
Contributor Author

mpdude commented Feb 20, 2025

We have monitoring in place that reports certain errors from production systems, and the translator warnings are among those.

Sometimes, you don't want to go through the hassle of maintaining translation catalogues and put the plain text into the code directly (single-lang apps).

In that case, it would be nice if translations could be disabled.

@nicolas-grekas
Copy link
Member

How do you deal with that at the moment?
I feel like the proposed strategy has too much impact for achieving your use case.
Any other idea that'd be less invasive?

@mpdude
Copy link
Contributor Author

mpdude commented Feb 21, 2025

How do you deal with that at the moment?
I feel like the proposed strategy has too much impact for achieving your use case.
Any other idea that'd be less invasive?

Not really, yet. Right now, in such cases, my logs are full with warnings from LoggingTranslator. When I feel that these log messages are getting too much (like dozens of megabytes of log volume per day), I'd change the code to use "real" message-IDs instead, and move the text to a validators message catalogue.

I care mostly about validation constraint messages added when form types are being built. But since the form types come from different bundles and some of them provide translations whereas others do not, I cannot use the solution from #50797 to disable all translations altogether.

#48852 put the logic in place to change or disable the translation domain for individual (project-specific) validators, but does not make this feature available for the built-in constraints.

To me, it felt natural if the same translation_domain parameter that can be used for the form types could be used on for the constraints as well (consider my initial example).

@mpdude
Copy link
Contributor Author

mpdude commented Feb 21, 2025

Any other idea that'd be less invasive?

... or do you mean "achieves the same without a repeating code pattern in all constraints and validators"?

Full ack, I do not fancy putting the same change into lots of classes over and over again.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Feb 24, 2025

Thanks for the hints. I've no better idea so I feel like this might be good to me.
I'm just wondering: would it make sense to allow defining the translation domain by contraint's FQCN in config/packages/validation.yaml? This way one could say that all #[SomeConstraint] messages should use some domain?

@nicolas-grekas
Copy link
Member

... or do you mean "achieves the same without a repeating code pattern in all constraints and validators"?

That's what I meant yes.
Maybe my config idea could be enough?

validation:
  translation_domains:
    SomeConstraint: some-domain

@mpdude
Copy link
Contributor Author

mpdude commented Feb 24, 2025

Not sure – assume you have two bundles that build a FormType each. And in those FormTypes, they both use the NotBlank constraint with message-IDs.

To me, it would make sense if both bundles could keep their respective validation/constraint message in their "own" translation domain, as suggested by the best practice.

That would not be possible with a config setting as suggested, or am I missing something?

Would you be fine with a solution that involves something with traits to plug-in the translation_domain into all the constraints?

Still, that does not allow to pass it as a constructor argument. 🤔

Also, since the validator class calls $this->context->buildViolation() to create the ConstraintViolationBuilder, but never passes it somewhere else, and ends with calling addViolation() without ever passing the Constraint instance, I am afraid there is nothing we can do with the current code design to centralizetranslation_domain handling.

Maybe GitHub Copilot can pull it off for us 😹?

@mpdude
Copy link
Contributor Author

mpdude commented Feb 24, 2025

@ro0NL You made a comment about TranslatableMessage support; did you withdraw that for good reasons? Probably makes the change even bigger.

@welcoMattic
Copy link
Member

Adding this feature will break the PhpAstExtractor as it is. Actually, to extract translation keys from Constraints, it leverages https://github.com/symfony/symfony/blob/7.3/src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php, which is looking keys and extract them in validators domain by default.

Introducing translation_domain option here means to update the ConstraintVisitor to handle the translation_domain option value to extract keys in the correct domain (or validators by default as it is now).

IIUC, the main reason of this feature is:

#48852 put the logic in place to change or disable the translation domain for individual (project-specific) validators, but does not make this feature available for the built-in constraints.

But I'm wondering why do you need to change the translation domain of built-in constraints? Did I miss something?

@mpdude
Copy link
Contributor Author

mpdude commented Mar 6, 2025

@welcoMattic thank you for the heads up! If I get you right, I'll need to update the src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php as well.

It's not about changing the translation domain for built-in messages; it's great that Symfony ships with translations for those!

My use case is about using the constraints like NotBlank in custom form types, potentially shipped in bundles, with custom validation error messages. For those, I'd like to be able to control the message catalogue. See my initial comment for the example.

Does that make sense?

Still, I have no better idea yet how to approach this apart from making the same kind of change in all constraints. Anyone else?

@mpdude mpdude force-pushed the set-translation-domain-in-constraint branch from 5986ddf to c8f94d4 Compare March 11, 2025 17:59
@mpdude mpdude force-pushed the set-translation-domain-in-constraint branch from c8f94d4 to 4a4905d Compare March 11, 2025 18:08
@nicolas-grekas
Copy link
Member

nicolas-grekas commented Mar 11, 2025

So, instead of spreading this everywhere, maybe we could just update the NotBlank one?
And maybe a few more constraints where changing the default message makes sense?

@mpdude
Copy link
Contributor Author

mpdude commented Mar 11, 2025

I've fixed tests and added an example of what a test case might look like. 

The complete change ain't gonna be fun – so maybe @nicolas-grekas can give me a 👍 that you would indeed merge it if I go the whole way of adding it? 😉

Sorry, we both posted at the same time.

@mpdude
Copy link
Contributor Author

mpdude commented Mar 11, 2025

So you'd prefer changing only a few constraints over consistency of usage?

@nicolas-grekas
Copy link
Member

I do yes. Consistency is a superficial thing compared to code complexity.

@nicolas-grekas
Copy link
Member

Up to finish this PR @mpdude ?

@mpdude
Copy link
Contributor Author

mpdude commented Apr 28, 2025

I checked out the codebase where I'd benefit from this change and was daunted due to the number of validators actually used 🙈.

Let me think through again whether I really want to go on this journey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants