From 0240807b77e0f02dd02841137fbccbe9f7dbee72 Mon Sep 17 00:00:00 2001 From: Alexandre Gomes Gaigalas Date: Wed, 4 Feb 2026 17:43:33 -0300 Subject: [PATCH] Update translation docs The documents on translation were updated to feature symfony with an array provider. Duplicated container notes were extracted to a single configuration.md file. An API for accessing the messages, so users don't have to copy and paste them from the source or docs, was provided and TemplateResolver was refactored to use it. --- docs/case-sensitiveness.md | 2 +- docs/configuration.md | 19 ++++ docs/messages/placeholder-conversion.md | 14 +-- docs/messages/translation.md | 54 +++++++----- docs/migrating-from-v2-to-v3.md | 7 ++ src/ContainerRegistry.php | 4 +- src/Message/Formatter/TemplateResolver.php | 25 ++---- src/Message/TemplateRegistry.php | 56 ++++++++++++ tests/feature/TranslatorTest.php | 30 ++++--- .../Formatter/TemplateResolverTest.php | 3 +- .../Message/InterpolationRendererTest.php | 42 ++++++--- tests/unit/Message/TemplateRegistryTest.php | 86 +++++++++++++++++++ 12 files changed, 265 insertions(+), 77 deletions(-) create mode 100644 docs/configuration.md create mode 100644 src/Message/TemplateRegistry.php create mode 100644 tests/unit/Message/TemplateRegistryTest.php diff --git a/docs/case-sensitiveness.md b/docs/case-sensitiveness.md index 3ad39fbe9..f13227fdb 100644 --- a/docs/case-sensitiveness.md +++ b/docs/case-sensitiveness.md @@ -7,7 +7,7 @@ SPDX-FileContributor: Henrique Moody # Case Insensitive Validation -For most simple cases, you can use `v::call` wrappers to perform +For most simple cases, you can use `v::after` wrappers to perform case normalization before comparison. For strings: diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 000000000..aaa3d818c --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,19 @@ + + +# Configuration + +## Container configuration + +The `ContainerRegistry::createContainer()` method returns a [PHP-DI](https://php-di.org/) container. The definitions array follows the [PHP-DI definitions format](https://php-di.org/doc/php-definitions.html). + +If you prefer to use a different container, `ContainerRegistry::setContainer()` accepts any [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible container: + +```php +use Respect\Validation\ContainerRegistry; + +ContainerRegistry::setContainer($yourPsr11Container); +``` diff --git a/docs/messages/placeholder-conversion.md b/docs/messages/placeholder-conversion.md index 68d2017e2..bb11fee4f 100644 --- a/docs/messages/placeholder-conversion.md +++ b/docs/messages/placeholder-conversion.md @@ -35,19 +35,7 @@ ContainerRegistry::setContainer( ); ``` -See [PlaceholderFormatter][] documentation for more information on creating custom modifiers. - -## Container configuration - -The `ContainerRegistry::createContainer()` method returns a [PHP-DI](https://php-di.org/) container. The definitions array follows the [PHP-DI definitions format](https://php-di.org/doc/php-definitions.html). - -If you prefer to use a different container, `ContainerRegistry::setContainer()` accepts any [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible container: - -```php -use Respect\Validation\ContainerRegistry; - -ContainerRegistry::setContainer($yourPsr11Container); -``` +See [PlaceholderFormatter][] documentation for more information on creating custom modifiers and the [configuration](../configuration.md) section for more details on container setup. [PlaceholderFormatter]: https://github.com/Respect/StringFormatter/blob/main/docs/PlaceholderFormatter.md [Respect\StringFormatter]: https://github.com/Respect/StringFormatter diff --git a/docs/messages/translation.md b/docs/messages/translation.md index b75d56649..cea9bf819 100644 --- a/docs/messages/translation.md +++ b/docs/messages/translation.md @@ -1,39 +1,63 @@ # Message translation -Validation uses [symfony/translation](https://symfony.com/doc/current/translation.html) for message translation, providing interoperability with the Symfony ecosystem and other PHP projects. +Validation provides full translation capabilities, but they are not enabled by default nor +do we provide official translations for our messages other than English. -By default, validation messages are not translated. To enable translation, provide a `Symfony\Contracts\Translation\TranslatorInterface` implementation to `ContainerRegistry::createContainer()`: +Therefore, if you want to use it with translation, you must provide the translations yourself +using a compatible [translation contract](https://github.com/symfony/translation-contracts). + +Here's a quick setup using [symfony/translation](https://symfony.com/doc/current/translation.html): ```php use Respect\Validation\ContainerRegistry; +use Respect\Validation\Message\TemplateRegistry; +use Respect\Validation\Validators as vs; +use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\Translator; use Symfony\Contracts\Translation\TranslatorInterface; -// Create your Symfony Translator instance -// See: https://symfony.com/doc/current/translation.html +$templates = new TemplateRegistry(); $translator = new Translator('pt_BR'); -// ... configure loaders and resources +$translator->addLoader('array', new ArrayLoader()); // Choose the loader of your preference +$translator->addResource('array', [ + // Reference standard template by class (StringVal, Intval, ...) and mode (default or inverted) + $templates->get(vs\IntVal::class)->default => '{{subject}} DEVE ser um inteiro.', + $templates->get(vs\IntVal::class)->inverted => '{{subject}} NÃO DEVE ser um inteiro.', + + // Reference alternative templates by their id (second argument) + $templates->get(vs\AllOf::class, vs\AllOf::TEMPLATE_ALL)->default => 'Todas as regras requeridas DEVEM passar para {{subject}}', + + // You can also just translate messages directly + '{{subject}} must be a URL' => '{{subject}} DEVE ser uma URL' +]); $container = ContainerRegistry::createContainer([ TranslatorInterface::class => $translator, + TemplateRegistry::class => $templates ]); - ContainerRegistry::setContainer($container); ``` -After setting up the container, all messages produced by Validation will your translator. +You only need to do this once before you perform any validation, and messages will start +being produced with your translation setup. If you're using a framework, you can configure +this in the service provider of your choice. + +Check out the documentation for each validator for its available modes and existing messages +and the [configuration](../configuration.md) section. ## Translating dynamic values Validation messages contain placeholders like `{{subject}}` and `{{minValue}}` that are replaced with actual values. Some of these values may also need translation. -Use the `|trans` modifier to translate parameter values: +You will encounter several messages with `|trans` in different validators. Those enable the +translation of such dynamic values automatically. ```php // Message template @@ -44,6 +68,8 @@ Use the `|trans` modifier to translate parameter values: 'Palestine' => 'Palestina', ``` +The `|trans` modifier will also work with custom templates defined by [Templated](../validators/Templated.md) or provided by [`assert`](../handling-exceptions.md). + ## Translating lists When using validators that display lists of values, use the `|list:or` or `|list:and` modifiers. These modifiers also require translating the conjunctions: @@ -63,15 +89,3 @@ When using validators that display lists of values, use the `|list:or` or `|list '{{haystack|list:and}} are the only possible names' => '{{haystack|list:and}} são os únicos nomes possíveis', 'and' => 'e', ``` - -## Container configuration - -The `ContainerRegistry::createContainer()` method returns a [PHP-DI](https://php-di.org/) container. The definitions array follows the [PHP-DI definitions format](https://php-di.org/doc/php-definitions.html). - -If you prefer to use a different container, `ContainerRegistry::setContainer()` accepts any [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible container: - -```php -use Respect\Validation\ContainerRegistry; - -ContainerRegistry::setContainer($yourPsr11Container); -``` diff --git a/docs/migrating-from-v2-to-v3.md b/docs/migrating-from-v2-to-v3.md index ec71b90cb..82cf2e368 100644 --- a/docs/migrating-from-v2-to-v3.md +++ b/docs/migrating-from-v2-to-v3.md @@ -932,6 +932,13 @@ v::email()->assert( ); ``` +### Translation + +The project now uses Symfony [translation contracts](https://github.com/symfony/translation-contracts) +instead of a custom callback. + +See [messages/translation.md](messages/translation.md) for more info. + ### Placeholder pipes Customize how values are rendered in templates using pipes: diff --git a/src/ContainerRegistry.php b/src/ContainerRegistry.php index 4e34ac73d..c2dd2bb8b 100644 --- a/src/ContainerRegistry.php +++ b/src/ContainerRegistry.php @@ -38,6 +38,7 @@ use Respect\Validation\Message\Parameters\PathHandler; use Respect\Validation\Message\Parameters\ResultHandler; use Respect\Validation\Message\Renderer; +use Respect\Validation\Message\TemplateRegistry; use Respect\Validation\Transformers\Prefix; use Respect\Validation\Transformers\Transformer; use Symfony\Contracts\Translation\TranslatorInterface; @@ -56,7 +57,8 @@ public static function createContainer(array $definitions = []): Container return new Container($definitions + [ PhoneNumberUtil::class => factory(static fn() => PhoneNumberUtil::getInstance()), Transformer::class => create(Prefix::class), - TemplateResolver::class => create(TemplateResolver::class), + TemplateRegistry::class => create(TemplateRegistry::class), + TemplateResolver::class => autowire(TemplateResolver::class), TranslatorInterface::class => autowire(BypassTranslator::class), Renderer::class => autowire(InterpolationRenderer::class), ResultFilter::class => create(OnlyFailedChildrenResultFilter::class), diff --git a/src/Message/Formatter/TemplateResolver.php b/src/Message/Formatter/TemplateResolver.php index ebedc9270..373f33e8e 100644 --- a/src/Message/Formatter/TemplateResolver.php +++ b/src/Message/Formatter/TemplateResolver.php @@ -11,11 +11,9 @@ namespace Respect\Validation\Message\Formatter; -use ReflectionClass; -use Respect\Validation\Message\Template; +use Respect\Validation\Message\TemplateRegistry; use Respect\Validation\Path; use Respect\Validation\Result; -use Respect\Validation\Validator; use function array_reduce; use function array_reverse; @@ -24,8 +22,10 @@ final class TemplateResolver { - /** @var array> */ - private array $templates = []; + public function __construct( + private TemplateRegistry $templateRegistry, + ) { + } /** @param array $templates */ public function getGivenTemplate(Result $result, array $templates): string|null @@ -53,7 +53,7 @@ public function getGivenTemplate(Result $result, array $templates): string|null public function getValidatorTemplate(Result $result): string { - foreach ($this->extractTemplates($result->validator) as $template) { + foreach ($this->templateRegistry->getTemplates($result->validator::class) as $template) { if ($template->id !== $result->template) { continue; } @@ -68,19 +68,6 @@ public function getValidatorTemplate(Result $result): string return $result->template; } - /** @return array