Skip to content

How to Translate Validation Constraint Messages

Warning: You are browsing the documentation for Symfony 6.3, which is no longer maintained.

Read the updated version of this page for Symfony 7.1 (the current stable version).

The validation constraints used in forms can translate their error messages by creating a translation resource for the validators translation domain.

First of all, install the Symfony translation component (if it's not already installed in your application) running the following command:

1
$ composer require symfony/translation

Suppose you've created a plain-old-PHP object that you need to use somewhere in your application:

1
2
3
4
5
6
7
// src/Entity/Author.php
namespace App\Entity;

class Author
{
    public string $name;
}

Add constraints through any of the supported methods. Set the message option to the translation source text. For example, to guarantee that the $name property is not empty, add the following:

1
2
3
4
5
6
7
8
9
10
// src/Entity/Author.php
namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    #[Assert\NotBlank(message: 'author.name.not_blank')]
    public string $name;
}

Now, create a validators catalog file in the translations/ directory:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- translations/validators/validators.en.xlf -->
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="author.name.not_blank">
                <source>author.name.not_blank</source>
                <target>Please enter an author name.</target>
            </trans-unit>
        </body>
    </file>
</xliff>

You may need to clear your cache (even in the dev environment) after creating this file for the first time.

Tip

Symfony will also create translation files for the built-in validation messages. You can optionally set the enabled_locales option to restrict the available locales in your application. This will improve performance a bit because Symfony will only generate the translation files for those locales instead of all of them.

You can also use TranslatableMessage to build your violation message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

#[Assert\Callback]
public function validate(ExecutionContextInterface $context, mixed $payload): void
{
    // somehow you have an array of "fake names"
    $fakeNames = [/* ... */];

    // check if the name is actually a fake name
    if (in_array($this->getFirstName(), $fakeNames, true)) {
        $context->buildViolation(new TranslatableMessage('author.name.fake', [], 'validators'))
            ->atPath('firstName')
            ->addViolation()
        ;
    }
}

You can learn more about translatable messages in the dedicated section.

Custom Translation Domain

The default translation domain can be changed globally using the FrameworkBundle configuration:

1
2
3
4
# config/packages/validator.yaml
framework:
    validation:
        translation_domain: validation_errors

Or it can be customized for a specific violation from a constraint validator:

1
2
3
4
5
6
7
8
9
public function validate($value, Constraint $constraint): void
{
    // validation logic

    $this->context->buildViolation($constraint->message)
        ->setParameter('{{ string }}', $value)
        ->setTranslationDomain('validation_errors')
        ->addViolation();
}
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version