title: Why does the automatic translation of constraint messages fail in twig/symfony?
body: <p>First of all: I'm new to Symfony4 and Twig. Yet I hope I have read the docs as far as my problem is concerned. :)</p>
  
  <p><strong>Introduction</strong></p>
  
  <p>Ok, my aim is to integrate the Symfony Form component along with other suitable Symfony components into an existing PHP application. The form I have created also relies on the Translation, Validator and Twig-Bridge component. I have setup the code as suggested in the official docs. Everything works as expected except for the translation of the constraint messages, albeit form labels are translated properly.</p>
  
  <p><strong>Details</strong></p>
  
  <p>The Translator is instanciated with the <code>'de'</code> locale. Fallback locales are set to <code>['de']</code>. The German default translations (xlf) from the Form and Validator component are loaded first, with my custom translations (yaml) following after and overriding the former if needed. I have setup two translation domains: messages and validators.</p>
  
  <p>I have checked that the catalogue contains all German default messages including the constraint translations. That means the translation files are loaded correctly. Manually translating a constraint message in the controller or Twig template works fine. But the automatic translation in the template fails.</p>
  
  <p>I fear it's a simple configuration problem but I have no clue what else I could try to make the translation work. Building each form field individually within the Twig template seems no option to me.</p>
  
  <p>Since there is no translation cache, caching can't be the problem.</p>
  
  <p>(validators.de.yaml)</p>
  
  <pre><code>// creating the custom constraint message
  
  entity.name.not_blank: 'Bitte einen Namen eingeben!'
  </code></pre>
  
  <p>(Controller.php)</p>
  
  <pre><code>// creating the translator
  
  $translator = new Translator('de');
  $translator-&gt;setFallbackLocales(['de']);
  $translator-&gt;addLoader('xlf', new XliffFileLoader());
  $translator-&gt;addLoader('yml', new YamlFileLoader());
  
  // adding default translations
  $translator-&gt;addResource('xlf', "path/to/vendor/symfony/form/Resources/translations/validators.de.xlf", 'de', 'validators');
  $translator-&gt;addResource('xlf', "path/to/validator/Resources/translations/validators.de.xlf", 'de', 'validators');
  
  // adding custom translations
  $translator-&gt;addResource('yml', "path/to/messages.de.yaml", 'de');
  $translator-&gt;addResource('yml', "path/to/validators.de.yaml", 'de', 'validators');
  
  …
  
  // setting up Twig
  
  $defaultFormTheme = 'bootstrap_4_layout.html.twig';
  $appVariableReflection = new \ReflectionClass('\Symfony\Bridge\Twig\AppVariable');
  
  $twig = new Environment(new FilesystemLoader(['/path/to/views', '/path/to/Resources/views/Form']));
  
  $formEngine = new TwigRendererEngine([$defaultFormTheme], $twig);
  
  $twig-&gt;addRuntimeLoader(
    new FactoryRuntimeLoader([
      FormRenderer::class =&gt; function () use($formEngine, $csrfManager) {
        return new FormRenderer($formEngine, $csrfManager);
      }
    ])
  );
  
  $twig-&gt;addExtension(new FormExtension());
  $twig-&gt;addExtension(new TranslationExtension($translator));
  
  …
  
  // creating the form factory adding the Validator extension
  
  $validator = Validation::createValidator();
  $formFactory = Forms::createFormFactoryBuilder()
      -&gt;addExtension(new ValidatorExtension($validator))
      -&gt;getFormFactory();
  
  …
  
  // rendering the form using Twig
  
  echo $this-&gt;getTwig()-&gt;render('form.html.twig', [
          'form' =&gt; $form-&gt;createView()
      ]);
  </code></pre>
  
  <p>(Entity.php)</p>
  
  <pre><code>// setting up the EntityType form
  
  public function buildForm(FormBuilderInterface $builder, array $options) {
      $builder
        -&gt;add('name', TextType::class, [
            'constraints' =&gt; [
                new NotBlank(['message' =&gt; 'entity.name.not_blank'])
            ]
        ]);
  }
  </code></pre>
  
  <p><strong>Tests and Results</strong></p>
  
  <p>The constraint message should translate to "<em>Bitte einen Namen eingeben!</em>", instead the message key "<em>entity.name.not_blank</em>" is shown. Setting no message key on the constraint results in "<em>This value should not be blank.</em>" being shown instead of "<em>Dieser Wert sollte nicht leer sein.</em>".</p>
  
  <p>Yet, the following <strong>works</strong>:</p>
  
  <ul>
  <li>translating the message key manually with <code>{% trans from 'validators' %}entity.name.not_blank{% endtrans %}</code> or <code>{% trans from 'validators' %}This value should not be blank.{% endtrans %}</code> respectively</li>
  <li>translating the error tag that precedes the constraint message ("ERROR" is correctly substituted with "FEHLER")</li>
  <li>translating form labels</li>
  </ul>
  
  <p>What I have tried so far but <strong>doesn't help</strong>:</p>
  
  <ul>
  <li><code>{{ form_widget(form, {'translation_domain': 'validators'}) }}</code></li>
  <li><code>{% trans_default_domain 'validators' %}</code></li>
  <li><code>$session-&gt;set('_locale', 'de')</code></li>
  <li><code>$this-&gt;getRequest()-&gt;setLocale('de')</code></li>
  </ul>
  
  <p><em>Fun fact:</em> Testing a comparable setup with the symfony framework <strong>is successful</strong>. Yet unfortunately, the framework is no option for me.</p>
  
  <p>Thanks for reading! Any helpful comment is highly appreciated. :)</p>