diff --git a/src/Symfony/Component/Validator/Constraints/AtLeastOneOfValidator.php b/src/Symfony/Component/Validator/Constraints/AtLeastOneOfValidator.php index 888f583eb92b..692b1176b6e5 100644 --- a/src/Symfony/Component/Validator/Constraints/AtLeastOneOfValidator.php +++ b/src/Symfony/Component/Validator/Constraints/AtLeastOneOfValidator.php @@ -31,7 +31,11 @@ public function validate($value, Constraint $constraint) $validator = $this->context->getValidator(); - $messages = [$constraint->message]; + // Build a first violation to have the base message of the constraint translated + $baseMessageContext = clone $this->context; + $baseMessageContext->buildViolation($constraint->message)->addViolation(); + $baseViolations = $baseMessageContext->getViolations(); + $messages = [(string) $baseViolations->get(\count($baseViolations) - 1)->getMessage()]; foreach ($constraint->constraints as $key => $item) { if (!\in_array($this->context->getGroup(), $item->groups, true)) { diff --git a/src/Symfony/Component/Validator/Tests/Constraints/AtLeastOneOfValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/AtLeastOneOfValidatorTest.php index 3685a67b65de..961607b4b7a4 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/AtLeastOneOfValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/AtLeastOneOfValidatorTest.php @@ -22,6 +22,7 @@ use Symfony\Component\Validator\Constraints\GreaterThan; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\IdenticalTo; +use Symfony\Component\Validator\Constraints\IsNull; use Symfony\Component\Validator\Constraints\Language; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\LessThan; @@ -37,6 +38,9 @@ use Symfony\Component\Validator\Mapping\MetadataInterface; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; use Symfony\Component\Validator\Validation; +use Symfony\Contracts\Translation\LocaleAwareInterface; +use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorTrait; /** * @author Przemysław Bogusz @@ -258,6 +262,40 @@ public function testNestedConstraintsAreNotExecutedWhenGroupDoesNotMatch() $this->assertCount(1, $violations); } + + public function testTranslatorIsCalledOnConstraintBaseMessageAndViolations() + { + $translator = new class() implements TranslatorInterface, LocaleAwareInterface { + use TranslatorTrait; + + public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string + { + if ('This value should satisfy at least one of the following constraints:' === $id) { + return 'Dummy translation:'; + } + + if ('This value should be null.' === $id) { + return 'Dummy violation.'; + } + + return $id; + } + }; + + $validator = Validation::createValidatorBuilder() + ->setTranslator($translator) + ->getValidator() + ; + + $violations = $validator->validate('Test', [ + new AtLeastOneOf([ + new IsNull(), + ]), + ]); + + $this->assertCount(1, $violations); + $this->assertSame('Dummy translation: [1] Dummy violation.', $violations->get(0)->getMessage()); + } } class ExpressionConstraintNested