Skip to content

How to Translate Validation Constraint Messages

Edit this page

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