Skip to content

Commit 9412a9e

Browse files
committed
Upgrade translation mechanism
Currently, defining translations is quite cumbersome, and the translator callback is passed to the constructor of multiple classes, which makes it quite ugly and could make translations inconsistent. This commit completely changes how translations are done in Validation. Instead of using a callback, it uses a specific class, and `Validator` will pass that object through the objects that render the messages.
1 parent 3833ad7 commit 9412a9e

30 files changed

+556
-593
lines changed

docs/04-message-translation.md

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,52 @@
11
# Message translation
22

3-
You're also able to translate your message to another language with Validation.
4-
The only thing one must do is to define the param `translator` as a callable that
5-
will handle the translation overwriting the default factory:
3+
You're able to translate message templates with Validation.
64

75
```php
8-
Factory::setDefaultInstance(
9-
(new Factory())->withTranslator('gettext')
10-
);
6+
use Respect\Validation\Message\Translator\GettextTranslator;
7+
use Respect\Validation\ValidatorDefaults;
8+
9+
ValidatorDefaults::setTranslator(new GettextTranslator());
10+
```
11+
12+
After that, if you call the methods `getMessage()`, `getMessages()`, or `getFullMessage()` from the `ValidationException`, the messages will be translated. The example above will work if you have `gettext` properly configured.
13+
14+
For non-static usage, pass the translator directly to the `Validator` constructor:
15+
16+
```php
17+
use Respect\Validation\Factory;
18+
use Respect\Validation\Message\StandardFormatter;
19+
use Respect\Validation\Message\Translator\GettextTranslator;
20+
use Respect\Validation\Validator;
21+
22+
$translator = new GettextTranslator();
23+
24+
$validator = new Validator(new Factory(), new StandardFormatter(), $translator);
1125
```
1226

13-
The example above uses `gettext()` but you can use any other callable value, like
14-
`[$translator, 'trans']` or `you_custom_function()`.
27+
## Supported translators
1528

16-
After that, if you call `getMessage()`, `getMessages()`, or `getFullMessage()`,
17-
the message will be translated.
29+
- `ArrayTranslator`: Translates messages using an array of messages.
30+
- `GettextTranslator`: Translates messages using the `gettext` extension.
31+
32+
## Custom translators
33+
34+
You can implement custom translators by creating a class that implements the `Translator` interface. Here's an example using the `stichoza/google-translate-php` package:
35+
36+
```php
37+
use Respect\Validation\Message\Translator;
38+
use Stichoza\GoogleTranslate\GoogleTranslate;
39+
40+
final class MyTranslator implements Translator
41+
{
42+
public function __construct(
43+
private readonly GoogleTranslate $googleTranslate
44+
) {
45+
}
46+
47+
public function translate(string $message): string
48+
{
49+
return $this->googleTranslate->translate($message);
50+
}
51+
}
52+
```

library/Factory.php

Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
use ReflectionException;
1414
use Respect\Validation\Exceptions\ComponentException;
1515
use Respect\Validation\Exceptions\InvalidClassException;
16-
use Respect\Validation\Message\Parameter\Processor;
17-
use Respect\Validation\Message\Parameter\Raw;
18-
use Respect\Validation\Message\Parameter\Stringify;
19-
use Respect\Validation\Message\Parameter\Trans;
2016
use Respect\Validation\Transformers\Aliases;
2117
use Respect\Validation\Transformers\DeprecatedAge;
2218
use Respect\Validation\Transformers\DeprecatedAttribute;
@@ -42,22 +38,8 @@ final class Factory
4238
*/
4339
private array $rulesNamespaces = ['Respect\\Validation\\Rules'];
4440

45-
/**
46-
* @var callable
47-
*/
48-
private $translator;
49-
50-
private Processor $processor;
51-
52-
private Transformer $transformer;
53-
54-
private static Factory $defaultInstance;
55-
56-
public function __construct()
57-
{
58-
$this->translator = static fn (string $message) => $message;
59-
$this->processor = new Raw(new Trans($this->translator, new Stringify()));
60-
$this->transformer = new DeprecatedAttribute(
41+
public function __construct(
42+
private readonly Transformer $transformer = new DeprecatedAttribute(
6143
new DeprecatedKey(
6244
new DeprecatedKeyValue(
6345
new DeprecatedMinAndMax(
@@ -67,16 +49,8 @@ public function __construct()
6749
)
6850
)
6951
)
70-
);
71-
}
72-
73-
public static function getDefaultInstance(): self
74-
{
75-
if (!isset(self::$defaultInstance)) {
76-
self::$defaultInstance = new self();
77-
}
78-
79-
return self::$defaultInstance;
52+
)
53+
) {
8054
}
8155

8256
public function withRuleNamespace(string $rulesNamespace): self
@@ -87,33 +61,6 @@ public function withRuleNamespace(string $rulesNamespace): self
8761
return $clone;
8862
}
8963

90-
public function withTranslator(callable $translator): self
91-
{
92-
$clone = clone $this;
93-
$clone->translator = $translator;
94-
$clone->processor = new Raw(new Trans($translator, new Stringify()));
95-
96-
return $clone;
97-
}
98-
99-
public function withParameterProcessor(Processor $processor): self
100-
{
101-
$clone = clone $this;
102-
$clone->processor = $processor;
103-
104-
return $clone;
105-
}
106-
107-
public function getTranslator(): callable
108-
{
109-
return $this->translator;
110-
}
111-
112-
public function getParameterProcessor(): Processor
113-
{
114-
return $this->processor;
115-
}
116-
11764
/**
11865
* @param mixed[] $arguments
11966
*/
@@ -122,11 +69,6 @@ public function rule(string $ruleName, array $arguments = []): Validatable
12269
return $this->createRuleSpec($this->transformer->transform(new RuleSpec($ruleName, $arguments)));
12370
}
12471

125-
public static function setDefaultInstance(self $defaultInstance): void
126-
{
127-
self::$defaultInstance = $defaultInstance;
128-
}
129-
13072
private function createRuleSpec(RuleSpec $ruleSpec): Validatable
13173
{
13274
$rule = $this->createRule($ruleSpec->name, $ruleSpec->arguments);

library/Message/Formatter.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ interface Formatter
1616
/**
1717
* @param array<string, mixed> $templates
1818
*/
19-
public function main(Result $result, array $templates): string;
19+
public function main(Result $result, array $templates, Translator $translator): string;
2020

2121
/**
2222
* @param array<string, mixed> $templates
2323
*/
24-
public function full(Result $result, array $templates, int $depth = 0): string;
24+
public function full(Result $result, array $templates, Translator $translator, int $depth = 0): string;
2525

2626
/**
2727
* @param array<string, mixed> $templates
2828
*
2929
* @return array<string, mixed>
3030
*/
31-
public function array(Result $result, array $templates): array;
31+
public function array(Result $result, array $templates, Translator $translator): array;
3232
}

library/Message/Parameter/Processor.php

Lines changed: 0 additions & 15 deletions
This file was deleted.

library/Message/Parameter/Raw.php

Lines changed: 0 additions & 30 deletions
This file was deleted.

library/Message/Parameter/Stringify.php

Lines changed: 0 additions & 25 deletions
This file was deleted.

library/Message/Parameter/Trans.php

Lines changed: 0 additions & 35 deletions
This file was deleted.

library/Message/Renderer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313

1414
interface Renderer
1515
{
16-
public function render(Result $result, ?string $template = null): string;
16+
public function render(Result $result, Translator $translator, ?string $template = null): string;
1717
}

library/Message/StandardFormatter.php

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,29 @@
2929
final class StandardFormatter implements Formatter
3030
{
3131
public function __construct(
32-
private readonly Renderer $renderer,
32+
private readonly Renderer $renderer = new StandardRenderer(),
3333
) {
3434
}
3535

3636
/**
3737
* @param array<string, mixed> $templates
3838
*/
39-
public function main(Result $result, array $templates): string
39+
public function main(Result $result, array $templates, Translator $translator): string
4040
{
4141
$selectedTemplates = $this->selectTemplates($result, $templates);
4242
if (!$this->isFinalTemplate($result, $selectedTemplates)) {
4343
foreach ($this->extractDeduplicatedChildren($result) as $child) {
44-
return $this->main($child, $selectedTemplates);
44+
return $this->main($child, $selectedTemplates, $translator);
4545
}
4646
}
4747

48-
return $this->renderer->render($this->getTemplated($result, $selectedTemplates));
48+
return $this->renderer->render($this->getTemplated($result, $selectedTemplates), $translator);
4949
}
5050

5151
/**
5252
* @param array<string, mixed> $templates
5353
*/
54-
public function full(Result $result, array $templates, int $depth = 0): string
54+
public function full(Result $result, array $templates, Translator $translator, int $depth = 0): string
5555
{
5656
$selectedTemplates = $this->selectTemplates($result, $templates);
5757
$isFinalTemplate = $this->isFinalTemplate($result, $selectedTemplates);
@@ -62,14 +62,14 @@ public function full(Result $result, array $templates, int $depth = 0): string
6262
$rendered .= sprintf(
6363
'%s- %s' . PHP_EOL,
6464
$indentation,
65-
$this->renderer->render($this->getTemplated($result, $selectedTemplates)),
65+
$this->renderer->render($this->getTemplated($result, $selectedTemplates), $translator),
6666
);
6767
$depth++;
6868
}
6969

7070
if (!$isFinalTemplate) {
7171
foreach ($this->extractDeduplicatedChildren($result) as $child) {
72-
$rendered .= $this->full($child, $selectedTemplates, $depth);
72+
$rendered .= $this->full($child, $selectedTemplates, $translator, $depth);
7373
$rendered .= PHP_EOL;
7474
}
7575
}
@@ -82,17 +82,23 @@ public function full(Result $result, array $templates, int $depth = 0): string
8282
*
8383
* @return array<string, mixed>
8484
*/
85-
public function array(Result $result, array $templates): array
85+
public function array(Result $result, array $templates, Translator $translator): array
8686
{
8787
$selectedTemplates = $this->selectTemplates($result, $templates);
8888
$deduplicatedChildren = $this->extractDeduplicatedChildren($result);
8989
if (count($deduplicatedChildren) === 0 || $this->isFinalTemplate($result, $selectedTemplates)) {
90-
return [$result->id => $this->renderer->render($this->getTemplated($result, $selectedTemplates))];
90+
return [
91+
$result->id => $this->renderer->render($this->getTemplated($result, $selectedTemplates), $translator),
92+
];
9193
}
9294

9395
$messages = [];
9496
foreach ($deduplicatedChildren as $child) {
95-
$messages[$child->id] = $this->array($child, $this->selectTemplates($child, $selectedTemplates));
97+
$messages[$child->id] = $this->array(
98+
$child,
99+
$this->selectTemplates($child, $selectedTemplates),
100+
$translator
101+
);
96102
if (count($messages[$child->id]) !== 1) {
97103
continue;
98104
}
@@ -101,7 +107,9 @@ public function array(Result $result, array $templates): array
101107
}
102108

103109
if (count($messages) > 1) {
104-
$self = ['__root__' => $this->renderer->render($this->getTemplated($result, $selectedTemplates))];
110+
$self = [
111+
'__root__' => $this->renderer->render($this->getTemplated($result, $selectedTemplates), $translator),
112+
];
105113

106114
return $self + $messages;
107115
}

0 commit comments

Comments
 (0)