diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php index 2f4a3a6a5a..48284d8d73 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -154,7 +154,11 @@ class ViolationMapper implements ViolationMapperInterface $messageTemplate = $violation->getMessageTemplate(); if (false !== strpos($message, '{{ label }}') || false !== strpos($messageTemplate, '{{ label }}')) { - $labelFormat = $scope->getConfig()->getOption('label_format'); + $form = $scope; + + do { + $labelFormat = $form->getConfig()->getOption('label_format'); + } while (null === $labelFormat && null !== $form = $form->getParent()); if (null !== $labelFormat) { $label = str_replace( @@ -180,10 +184,16 @@ class ViolationMapper implements ViolationMapperInterface } if (null !== $this->translator) { + $form = $scope; + + do { + $translationDomain = $form->getConfig()->getOption('translation_domain'); + } while (null === $translationDomain && null !== $form = $form->getParent()); + $label = $this->translator->trans( $label, $scope->getConfig()->getOption('label_translation_parameters', []), - $scope->getConfig()->getOption('translation_domain') + $translationDomain ); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php index 2a8f92fb49..d636f9fe40 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php @@ -1742,6 +1742,50 @@ class ViolationMapperTest extends TestCase } } + public function testLabelFormatDefinedByParentType() + { + $form = $this->getForm('', null, null, [], false, true, [ + 'label_format' => 'form.%name%', + ]); + $child = $this->getForm('foo', 'foo'); + $form->add($child); + + $violation = new ConstraintViolation('Message "{{ label }}"', null, [], null, 'data.foo', null); + $this->mapper->mapViolation($violation, $form); + + $errors = iterator_to_array($child->getErrors()); + + $this->assertCount(1, $errors, $child->getName().' should have an error, but has none'); + $this->assertSame('Message "form.foo"', $errors[0]->getMessage()); + } + + public function testLabelPlaceholderTranslatedWithTranslationDomainDefinedByParentType() + { + $translator = $this->createMock(TranslatorInterface::class); + $translator->expects($this->any()) + ->method('trans') + ->with('foo', [], 'domain') + ->willReturn('translated foo label') + ; + $this->mapper = new ViolationMapper(null, $translator); + + $form = $this->getForm('', null, null, [], false, true, [ + 'translation_domain' => 'domain', + ]); + $child = $this->getForm('foo', 'foo', null, [], false, true, [ + 'label' => 'foo', + ]); + $form->add($child); + + $violation = new ConstraintViolation('Message "{{ label }}"', null, [], null, 'data.foo', null); + $this->mapper->mapViolation($violation, $form); + + $errors = iterator_to_array($child->getErrors()); + + $this->assertCount(1, $errors, $child->getName().' should have an error, but has none'); + $this->assertSame('Message "translated foo label"', $errors[0]->getMessage()); + } + public function testTranslatorNotCalledWithoutLabel() { $renderer = $this->getMockBuilder(FormRenderer::class)