From d025b8844c93e9ffcafca7d66a04c696763e1e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 18 Apr 2024 20:53:26 -0300 Subject: [PATCH] Add support for Twig 3.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MaurĂ­cio Meneghini Fauth --- src/Node/TransNode.php | 12 ++++++-- src/TokenParser/TransTokenParser.php | 10 +++++++ test/Fixtures/TransTagSetVariable.test | 10 +++++++ test/Node/MoTranslatorTransTest.php | 33 ++++++++++++++++----- test/Node/TransTest.php | 41 ++++++++++++++++++-------- 5 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 test/Fixtures/TransTagSetVariable.test diff --git a/src/Node/TransNode.php b/src/Node/TransNode.php index e12b04c..9f7acf7 100644 --- a/src/Node/TransNode.php +++ b/src/Node/TransNode.php @@ -14,6 +14,7 @@ namespace PhpMyAdmin\Twig\Extensions\Node; +use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\CheckToStringNode; use Twig\Node\Expression\AbstractExpression; @@ -26,6 +27,7 @@ use Twig\Node\TextNode; use function array_merge; +use function class_exists; use function count; use function sprintf; use function str_replace; @@ -36,6 +38,7 @@ * * Author Fabien Potencier */ +#[YieldReady] class TransNode extends Node { /** @@ -134,7 +137,7 @@ public function compile(Compiler $compiler) if ($vars) { $compiler - ->raw('echo strtr(' . $function . '('); + ->raw($this->echoOrYield() . ' strtr(' . $function . '('); if ($hasDomain) { [$domain] = $this->compileString($this->getNode('domain')); @@ -184,7 +187,7 @@ public function compile(Compiler $compiler) $compiler->raw("));\n"); } else { $compiler - ->raw('echo ' . $function . '('); + ->raw($this->echoOrYield() . ' ' . $function . '('); if ($hasDomain) { [$domain] = $this->compileString($this->getNode('domain')); @@ -314,4 +317,9 @@ protected function getTransFunction(bool $hasPlural, bool $hasContext, bool $has // gettext($msgid); return $functionPrefix . ($hasContext ? 'pgettext' : 'gettext'); } + + private function echoOrYield(): string + { + return class_exists(YieldReady::class) ? 'yield' : 'echo'; + } } diff --git a/src/TokenParser/TransTokenParser.php b/src/TokenParser/TransTokenParser.php index 78b13c8..94a7a4a 100644 --- a/src/TokenParser/TransTokenParser.php +++ b/src/TokenParser/TransTokenParser.php @@ -92,6 +92,16 @@ protected function preParse(Token $token): array $this->checkTransString($body, $lineno); + if ($notes instanceof TextNode) { + // Don't use TextNode for $notes to avoid it getting merged with $body in Twig >= 3.9.0. + $notes = new Node([], ['data' => $notes->getAttribute('data')], $notes->getTemplateLine()); + } + + if ($context instanceof TextNode) { + // Don't use TextNode for $context to avoid it getting merged with $body in Twig >= 3.9.0. + $context = new Node([], ['data' => $context->getAttribute('data')], $context->getTemplateLine()); + } + return [$body, $plural, $count, $context, $notes, $domain, $lineno, $this->getTag()]; } diff --git a/test/Fixtures/TransTagSetVariable.test b/test/Fixtures/TransTagSetVariable.test new file mode 100644 index 0000000..422f589 --- /dev/null +++ b/test/Fixtures/TransTagSetVariable.test @@ -0,0 +1,10 @@ +--TEST-- +Test assigning to a variable with set +--TEMPLATE-- +A {% set variable %}{% trans 'text' %}{% endset %} B {{ variable }} C +--DATA-- +return [] +--CONFIG-- +return [] +--EXPECT-- +A B text C diff --git a/test/Node/MoTranslatorTransTest.php b/test/Node/MoTranslatorTransTest.php index c016d64..5ae0fe9 100644 --- a/test/Node/MoTranslatorTransTest.php +++ b/test/Node/MoTranslatorTransTest.php @@ -15,6 +15,7 @@ namespace PhpMyAdmin\Tests\Twig\Extensions\Node; use PhpMyAdmin\Twig\Extensions\Node\TransNode; +use Twig\Attribute\YieldReady; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\Node; @@ -22,10 +23,16 @@ use Twig\Node\TextNode; use Twig\Test\NodeTestCase; +use function class_exists; use function sprintf; class MoTranslatorTransTest extends NodeTestCase { + private function echoOrYield(): string + { + return class_exists(YieldReady::class) ? 'yield' : 'echo'; + } + public static function setUpBeforeClass(): void { TransNode::$notesLabel = '// l10n: '; @@ -82,7 +89,10 @@ public function getTests(): array new TextNode('coredomain', 0), ], [], 0); $node = new TransNode($body, null, null, null, null, $domain, 0); - $tests[] = [$node, sprintf('echo _dgettext("coredomain", %s);', $this->getVariableGetter('foo'))]; + $tests[] = [ + $node, + sprintf($this->echoOrYield() . ' _dgettext("coredomain", %s);', $this->getVariableGetter('foo')), + ]; $body = new NameExpression('foo', 0); $domain = new Node([ @@ -94,7 +104,10 @@ public function getTests(): array $node = new TransNode($body, null, null, $context, null, $domain, 0); $tests[] = [ $node, - sprintf('echo _dpgettext("coredomain", "The context", %s);', $this->getVariableGetter('foo')), + sprintf( + $this->echoOrYield() . ' _dpgettext("coredomain", "The context", %s);', + $this->getVariableGetter('foo') + ), ]; $body = new Node([ @@ -106,7 +119,7 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(_gettext("J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', + $this->echoOrYield() . ' strtr(_gettext("J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', $this->getVariableGetter('foo') ), ]; @@ -128,7 +141,7 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(_ngettext("Hey %%name%%, I have one apple", "Hey %%name%%,' + $this->echoOrYield() . ' strtr(_ngettext("Hey %%name%%, I have one apple", "Hey %%name%%,' . ' I have %%count%% apples", abs(12)), array("%%name%%" => %s,' . ' "%%name%%" => %s, "%%count%%" => abs(12), ));', $this->getVariableGetter('name'), @@ -148,7 +161,8 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(_pgettext("The context", "J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', + $this->echoOrYield() + . ' strtr(_pgettext("The context", "J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', $this->getVariableGetter('foo') ), ]; @@ -173,7 +187,8 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(_npgettext("The context", "Hey %%name%%, I have one apple", "Hey %%name%%,' + $this->echoOrYield() + . ' strtr(_npgettext("The context", "Hey %%name%%, I have one apple", "Hey %%name%%,' . ' I have %%count%% apples", abs(12)), array("%%name%%" => %s,' . ' "%%name%%" => %s, "%%count%%" => abs(12), ));', $this->getVariableGetter('name'), @@ -196,7 +211,8 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(_dpgettext("mydomain", "The context", "J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', + $this->echoOrYield() + . ' strtr(_dpgettext("mydomain", "The context", "J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', $this->getVariableGetter('foo') ), ]; @@ -224,7 +240,8 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(_dnpgettext("mydomain", "The context", "Hey %%name%%, I have one apple",' + $this->echoOrYield() + . ' strtr(_dnpgettext("mydomain", "The context", "Hey %%name%%, I have one apple",' . ' "Hey %%name%%, I have %%count%% apples", abs(12)), array("%%name%%" => %s,' . ' "%%name%%" => %s, "%%count%%" => abs(12), ));', $this->getVariableGetter('name'), diff --git a/test/Node/TransTest.php b/test/Node/TransTest.php index a6bdaa1..d19aa37 100644 --- a/test/Node/TransTest.php +++ b/test/Node/TransTest.php @@ -15,6 +15,7 @@ namespace PhpMyAdmin\Tests\Twig\Extensions\Node; use PhpMyAdmin\Twig\Extensions\Node\TransNode; +use Twig\Attribute\YieldReady; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\NameExpression; @@ -23,10 +24,16 @@ use Twig\Node\TextNode; use Twig\Test\NodeTestCase; +use function class_exists; use function sprintf; class TransTest extends NodeTestCase { + private function echoOrYield(): string + { + return class_exists(YieldReady::class) ? 'yield' : 'echo'; + } + public function testConstructor(): void { $count = new ConstantExpression(12, 0); @@ -89,7 +96,8 @@ public function testEnableDebugNotEnabled(): void $this->assertEmpty($compiler->getDebugInfo()); $sourceCode = $compiler->compile($node)->getSource(); $this->assertSame( - '// custom: Notes for translators' . "\n" . 'echo strtr(ngettext("There is 1 pending task",' + '// custom: Notes for translators' . "\n" + . $this->echoOrYield() . ' strtr(ngettext("There is 1 pending task",' . ' "There are %count% pending tasks", abs(5)), array("%count%" => abs(5), ));' . "\n", $sourceCode ); @@ -117,7 +125,8 @@ public function testEnableDebugEnabled(): void $this->assertEmpty($compiler->getDebugInfo()); $sourceCode = $compiler->compile($node)->getSource(); $this->assertSame( - '// line 80' . "\n" . '// custom: Notes for translators' . "\n" . 'echo strtr(ngettext("There' + '// line 80' . "\n" . '// custom: Notes for translators' . "\n" + . $this->echoOrYield() . ' strtr(ngettext("There' . ' is 1 pending task", "There are %count% pending tasks", abs(5)), array("%count%" => abs(5), ));' . "\n", $sourceCode ); @@ -138,21 +147,24 @@ public function getTests(): array new TextNode('coredomain', 0), ], [], 0); $node = new TransNode($body, null, null, null, null, $domain, 0); - $tests[] = [$node, sprintf('echo dgettext("coredomain", %s);', $this->getVariableGetter('foo'))]; + $tests[] = [ + $node, + sprintf($this->echoOrYield() . ' dgettext("coredomain", %s);', $this->getVariableGetter('foo')), + ]; $body = new NameExpression('foo', 0); $node = new TransNode($body, null, null, null, null, null, 0); - $tests[] = [$node, sprintf('echo gettext(%s);', $this->getVariableGetter('foo'))]; + $tests[] = [$node, sprintf($this->echoOrYield() . ' gettext(%s);', $this->getVariableGetter('foo'))]; $body = new ConstantExpression('Hello', 0); $node = new TransNode($body, null, null, null, null, null, 0); - $tests[] = [$node, 'echo gettext("Hello");']; + $tests[] = [$node, $this->echoOrYield() . ' gettext("Hello");']; $body = new Node([ new TextNode('Hello', 0), ], [], 0); $node = new TransNode($body, null, null, null, null, null, 0); - $tests[] = [$node, 'echo gettext("Hello");']; + $tests[] = [$node, $this->echoOrYield() . ' gettext("Hello");']; $body = new Node([ new TextNode('J\'ai ', 0), @@ -163,7 +175,7 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(gettext("J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', + $this->echoOrYield() . ' strtr(gettext("J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', $this->getVariableGetter('foo') ), ]; @@ -185,7 +197,7 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(ngettext("Hey %%name%%, I have one apple", "Hey %%name%%, I have' + $this->echoOrYield() . ' strtr(ngettext("Hey %%name%%, I have one apple", "Hey %%name%%, I have' . ' %%count%% apples", abs(12)), array("%%name%%" => %s,' . ' "%%name%%" => %s, "%%count%%" => abs(12), ));', $this->getVariableGetter('name'), @@ -207,7 +219,7 @@ public function getTests(): array $tests[] = [ $node, sprintf( - 'echo strtr(gettext("J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', + $this->echoOrYield() . ' strtr(gettext("J\'ai %%foo%% pommes"), array("%%foo%%" => %s, ));', $this->getVariableGetter('foo') ), ]; @@ -216,12 +228,16 @@ public function getTests(): array $body = new ConstantExpression('Hello', 0); $notes = new TextNode('Notes for translators', 0); $node = new TransNode($body, null, null, null, $notes, null, 0); - $tests[] = [$node, "// notes: Notes for translators\necho gettext(\"Hello\");"]; + $tests[] = [$node, "// notes: Notes for translators\n" . $this->echoOrYield() . ' gettext("Hello");']; $body = new ConstantExpression('Hello', 0); $notes = new TextNode("Notes for translators\nand line breaks", 0); $node = new TransNode($body, null, null, null, $notes, null, 0); - $tests[] = [$node, "// notes: Notes for translators and line breaks\necho gettext(\"Hello\");"]; + $tests[] = [ + $node, + "// notes: Notes for translators and line breaks\n" + . $this->echoOrYield() . ' gettext("Hello");', + ]; $count = new ConstantExpression(5, 0); $body = new TextNode('There is 1 pending task', 0); @@ -234,7 +250,8 @@ public function getTests(): array $node = new TransNode($body, $plural, $count, null, $notes, null, 0); $tests[] = [ $node, - '// notes: Notes for translators' . "\n" . 'echo strtr(ngettext("There is 1 pending task",' + '// notes: Notes for translators' . "\n" + . $this->echoOrYield() . ' strtr(ngettext("There is 1 pending task",' . ' "There are %count% pending tasks", abs(5)), array("%count%" => abs(5), ));', ];