Skip to content

Commit 2cbc947

Browse files
committed
{_var} and {translate} can translate values during compile time
1 parent cef078a commit 2cbc947

File tree

5 files changed

+116
-7
lines changed

5 files changed

+116
-7
lines changed

src/Bridges/ApplicationLatte/Nodes/TranslateNode.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99

1010
namespace Nette\Bridges\ApplicationLatte\Nodes;
1111

12+
use Latte\Compiler\NodeHelpers;
1213
use Latte\Compiler\Nodes\AreaNode;
1314
use Latte\Compiler\Nodes\NopNode;
1415
use Latte\Compiler\Nodes\Php;
1516
use Latte\Compiler\Nodes\Php\ModifierNode;
1617
use Latte\Compiler\Nodes\StatementNode;
18+
use Latte\Compiler\Nodes\TextNode;
1719
use Latte\Compiler\PrintContext;
1820
use Latte\Compiler\Tag;
19-
use Latte\Helpers;
21+
use Nette\Localization\Translator;
2022

2123

2224
/**
@@ -29,7 +31,7 @@ class TranslateNode extends StatementNode
2931

3032

3133
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static|NopNode> */
32-
public static function create(Tag $tag): \Generator
34+
public static function create(Tag $tag, ?Translator $translator): \Generator
3335
{
3436
$tag->outputMode = $tag::OutputKeepIndentation;
3537

@@ -42,22 +44,38 @@ public static function create(Tag $tag): \Generator
4244
}
4345

4446
[$node->content] = yield;
47+
48+
if ($text = NodeHelpers::toText($node->content)) {
49+
$node->content = new TextNode($text);
50+
if ($translator) {
51+
try {
52+
$translation = $translator->translate($text, ...NodeHelpers::toValue($args, constants: true));
53+
if (is_string($translation)) {
54+
$node->content = new TextNode($translation);
55+
return $node;
56+
}
57+
} catch (\InvalidArgumentException) {
58+
}
59+
}
60+
}
61+
4562
array_unshift($node->modifier->filters, new Php\FilterNode(new Php\IdentifierNode('translate'), $args->toArguments()));
63+
4664
return $node;
4765
}
4866

4967

5068
public function print(PrintContext $context): string
5169
{
52-
if ($text = Helpers::toTextualContent($this->content)) {
70+
if ($this->content instanceof TextNode) {
5371
return $context->format(
5472
<<<'XX'
5573
$ʟ_fi = new LR\FilterInfo(%dump);
5674
echo %modifyContent(%dump) %line;
5775
XX,
5876
$context->getEscaper()->export(),
5977
$this->modifier,
60-
$text,
78+
$this->content->content,
6179
$this->position,
6280
);
6381

src/Bridges/ApplicationLatte/Template.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public function addFunction(string $name, callable $callback)
105105
* Sets translate adapter.
106106
* @return static
107107
*/
108-
public function setTranslator(?Nette\Localization\Translator $translator)
108+
public function setTranslator(?Nette\Localization\Translator $translator, ?string $language = null)
109109
{
110110
if (version_compare(Latte\Engine::VERSION, '3', '<')) {
111111
$this->latte->addFilter(
@@ -117,7 +117,7 @@ function (Latte\Runtime\FilterInfo $fi, ...$args) use ($translator): string {
117117
}
118118
);
119119
} else {
120-
$this->latte->addExtension(new TranslatorExtension($translator));
120+
$this->latte->addExtension(new TranslatorExtension($translator, $language));
121121
}
122122
return $this;
123123
}

src/Bridges/ApplicationLatte/TranslatorExtension.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
namespace Nette\Bridges\ApplicationLatte;
1111

1212
use Latte;
13+
use Latte\Compiler\NodeHelpers;
1314
use Latte\Compiler\Nodes\Php;
1415
use Latte\Compiler\Tag;
16+
use Latte\Engine;
1517
use Latte\Essential\Nodes\PrintNode;
1618
use Nette\Localization\Translator;
1719

@@ -23,6 +25,7 @@ final class TranslatorExtension extends Latte\Extension
2325
{
2426
public function __construct(
2527
private ?Translator $translator,
28+
private ?string $key = null,
2629
) {
2730
}
2831

@@ -31,7 +34,7 @@ public function getTags(): array
3134
{
3235
return [
3336
'_' => [$this, 'parseTranslate'],
34-
'translate' => [Nodes\TranslateNode::class, 'create'],
37+
'translate' => fn(Tag $tag): \Generator => Nodes\TranslateNode::create($tag, $this->key ? $this->translator : null),
3538
];
3639
}
3740

@@ -46,6 +49,12 @@ public function getFilters(): array
4649
}
4750

4851

52+
public function getCacheKey(Engine $engine): mixed
53+
{
54+
return $this->key;
55+
}
56+
57+
4958
/**
5059
* {_ ...}
5160
*/
@@ -59,8 +68,24 @@ public function parseTranslate(Tag $tag): PrintNode
5968
if ($tag->parser->stream->tryConsume(',')) {
6069
$args = $tag->parser->parseArguments();
6170
}
71+
6272
$node->modifier = $tag->parser->parseModifier();
6373
$node->modifier->escape = true;
74+
75+
if ($this->translator && $this->key) {
76+
try {
77+
$translation = $this->translator->translate(
78+
NodeHelpers::toValue($node->expression, constants: true),
79+
...NodeHelpers::toValue($args, constants: true),
80+
);
81+
if (is_string($translation)) {
82+
$node->expression = new Php\Scalar\StringNode($translation);
83+
return $node;
84+
}
85+
} catch (\InvalidArgumentException) {
86+
}
87+
}
88+
6489
array_unshift($node->modifier->filters, new Php\FilterNode(new Php\IdentifierNode('translate'), $args->toArguments()));
6590
return $node;
6691
}

tests/Bridges.Latte3/{_var}.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
declare(strict_types=1);
66

7+
use Nette\Localization\Translator;
78
use Tester\Assert;
89

910
require __DIR__ . '/../bootstrap.php';
@@ -31,3 +32,35 @@ Assert::contains(
3132
'echo LR\Filters::escapeHtmlText(($this->filters->translate)($var, 10, 20)) /* line 1 */;',
3233
$latte->compile('{_$var, 10, 20}'),
3334
);
35+
36+
37+
class MyTranslator implements Translator
38+
{
39+
public function translate($message, ...$parameters): string
40+
{
41+
return strrev($message) . implode(',', $parameters);
42+
}
43+
}
44+
45+
$latte = new Latte\Engine;
46+
$latte->setLoader(new Latte\Loaders\StringLoader);
47+
$latte->addExtension(new Nette\Bridges\ApplicationLatte\TranslatorExtension(new MyTranslator));
48+
Assert::contains(
49+
'echo LR\Filters::escapeHtmlText(($this->filters->translate)(\'a&b\', 1, 2))',
50+
$latte->compile('{_"a&b", 1, 2}'),
51+
);
52+
Assert::same(
53+
'b&amp;a1,2',
54+
$latte->renderToString('{_"a&b", 1, 2}'),
55+
);
56+
57+
58+
$latte->addExtension(new Nette\Bridges\ApplicationLatte\TranslatorExtension(new MyTranslator, 'en'));
59+
Assert::contains(
60+
'echo LR\Filters::escapeHtmlText(\'b&a1,2\')',
61+
$latte->compile('{_"a&b", 1, 2}'),
62+
);
63+
Assert::same(
64+
'b&amp;a1,2',
65+
$latte->renderToString('{_"a&b", 1, 2}'),
66+
);

tests/Bridges.Latte3/{translate}.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
declare(strict_types=1);
66

7+
use Nette\Localization\Translator;
78
use Tester\Assert;
89

910
require __DIR__ . '/../bootstrap.php';
@@ -65,3 +66,35 @@ Assert::notContains(
6566
"'translate'",
6667
$latte->compile('{translate /}'),
6768
);
69+
70+
71+
class MyTranslator implements Translator
72+
{
73+
public function translate($message, ...$parameters): string
74+
{
75+
return strrev($message) . implode(',', $parameters);
76+
}
77+
}
78+
79+
$latte = new Latte\Engine;
80+
$latte->setLoader(new Latte\Loaders\StringLoader);
81+
$latte->addExtension(new Nette\Bridges\ApplicationLatte\TranslatorExtension(new MyTranslator));
82+
Assert::contains(
83+
'echo LR\Filters::convertTo($ʟ_fi, \'html\', $this->filters->filterContent(\'translate\', $ʟ_fi, \'a&b\', 1, 2))',
84+
$latte->compile('{translate 1,2}a&b{/translate}'),
85+
);
86+
Assert::same(
87+
'b&a1,2',
88+
$latte->renderToString('{translate 1,2}a&b{/translate}'),
89+
);
90+
91+
92+
$latte->addExtension(new Nette\Bridges\ApplicationLatte\TranslatorExtension(new MyTranslator, 'en'));
93+
Assert::contains(
94+
'echo LR\Filters::convertTo($ʟ_fi, \'html\', \'b&a1,2\')',
95+
$latte->compile('{translate 1,2}a&b{/translate}'),
96+
);
97+
Assert::same(
98+
'b&a1,2',
99+
$latte->renderToString('{translate 1,2}a&b{/translate}'),
100+
);

0 commit comments

Comments
 (0)