diff --git a/Changelog.md b/Changelog.md index 8a4a8e39..77eea3d6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,16 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" betwee ### Added +- Support for `desc` filter in Twig. + +### Changed + +- Twig extension `TranslationExtension` was renamed to `EditInPlaceExtension` + +## 0.5.0 + +### Added + - Symfony 4 support - New `--cache` option on the `translation:download` allowing to clear the cache automatically if the downloaded translations have changed. - Support for Yandex translator diff --git a/Resources/config/edit_in_place.yml b/Resources/config/edit_in_place.yml index 6d89c949..43bfbda2 100644 --- a/Resources/config/edit_in_place.yml +++ b/Resources/config/edit_in_place.yml @@ -23,7 +23,7 @@ services: php_translation.edit_in_place.extension.trans: public: false - class: Translation\Bundle\Twig\TranslationExtension + class: Translation\Bundle\Twig\EditInPlaceExtension arguments: - '@php_translator.edit_in_place.xtrans_html_translator' calls: diff --git a/Resources/config/extractors.yml b/Resources/config/extractors.yml index efb9c280..4edbfa48 100644 --- a/Resources/config/extractors.yml +++ b/Resources/config/extractors.yml @@ -73,7 +73,7 @@ services: public: false php_translation.extractor.twig.visitor.twig: - class: Translation\Bundle\Twig\DummyTwigVisitor + class: Translation\Bundle\Twig\Visitor\DummyTwigVisitor factory: ["@php_translation.extractor.twig.factory", create] tags: - { name: 'php_translation.visitor', type: 'twig' } diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 89bd5b9e..3877bd97 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -56,6 +56,7 @@ services: arguments: [] php_translation.twig_extension: - class: Translation\Extractor\Twig\TranslationExtension + class: Translation\Bundle\Twig\TranslationExtension + arguments: ['@translator', "%kernel.debug%"] tags: - - { name: twig.extension } \ No newline at end of file + - { name: twig.extension } diff --git a/Service/Importer.php b/Service/Importer.php index b8125f0f..1760b77d 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -120,6 +120,9 @@ private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, S $meta = $this->getMetadata($catalogue, $key, $domain); $meta->addCategory('file-source', sprintf('%s:%s', substr($sourceLocation->getPath(), $trimLength), $sourceLocation->getLine())); + if (isset($sourceLocation->getContext()['desc'])) { + $meta->addCategory('desc', $sourceLocation->getContext()['desc']); + } $this->setMetadata($catalogue, $key, $domain, $meta); } } diff --git a/Tests/Unit/Twig/BaseTwigTestCase.php b/Tests/Unit/Twig/BaseTwigTestCase.php new file mode 100644 index 00000000..7ef74766 --- /dev/null +++ b/Tests/Unit/Twig/BaseTwigTestCase.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Unit\Twig; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Translation\MessageSelector; +use Symfony\Component\Translation\IdentityTranslator; +use Symfony\Bridge\Twig\Extension\TranslationExtension as SymfonyTranslationExtension; +use Translation\Bundle\Twig\TranslationExtension; + +/** + * @author Johannes M. Schmitt + */ +abstract class BaseTwigTestCase extends TestCase +{ + final protected function parse($file, $debug = false) + { + $content = file_get_contents(__DIR__.'/Fixture/'.$file); + + $env = new \Twig_Environment(new \Twig_Loader_Array([])); + $env->addExtension(new SymfonyTranslationExtension($translator = new IdentityTranslator(new MessageSelector()))); + $env->addExtension(new TranslationExtension($translator, $debug)); + + return $env->parse($env->tokenize(new \Twig_Source($content, null)))->getNode('body'); + } +} diff --git a/Tests/Unit/Twig/DefaultApplyingNodeVisitorTest.php b/Tests/Unit/Twig/DefaultApplyingNodeVisitorTest.php new file mode 100644 index 00000000..bee3c488 --- /dev/null +++ b/Tests/Unit/Twig/DefaultApplyingNodeVisitorTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Unit\Twig; + +/** + * @author Johannes M. Schmitt + */ +class DefaultApplyingNodeVisitorTest extends BaseTwigTestCase +{ + public function testApply() + { + $this->assertEquals( + $this->parse('apply_default_value_compiled.html.twig', true), + $this->parse('apply_default_value.html.twig', true) + ); + } +} diff --git a/Tests/Unit/Twig/Fixture/apply_default_value.html.twig b/Tests/Unit/Twig/Fixture/apply_default_value.html.twig new file mode 100644 index 00000000..ccb4d458 --- /dev/null +++ b/Tests/Unit/Twig/Fixture/apply_default_value.html.twig @@ -0,0 +1,4 @@ +{{ "form.label.firstname"|trans|desc("Firstname") }} + +{{ "foo.%bar%"|trans({"%bar%": "baz"})|desc("Foo %bar%") }} + diff --git a/Tests/Unit/Twig/Fixture/apply_default_value_compiled.html.twig b/Tests/Unit/Twig/Fixture/apply_default_value_compiled.html.twig new file mode 100644 index 00000000..254e765d --- /dev/null +++ b/Tests/Unit/Twig/Fixture/apply_default_value_compiled.html.twig @@ -0,0 +1,4 @@ +{{ "form.label.firstname"|trans == "form.label.firstname" ? "Firstname" : "form.label.firstname"|trans }} + +{{ "foo.%bar%"|trans({}) == "foo.%bar%" ? "Foo %bar%"|replace({"%bar%": "baz"}) : "foo.%bar%"|trans({"%bar%": "baz"}) }} + diff --git a/Tests/Unit/Twig/Fixture/binary_concat_of_constants.html.twig b/Tests/Unit/Twig/Fixture/binary_concat_of_constants.html.twig new file mode 100644 index 00000000..99cc553e --- /dev/null +++ b/Tests/Unit/Twig/Fixture/binary_concat_of_constants.html.twig @@ -0,0 +1,3 @@ +{{ "foo" + ~ "bar" + ~ "baz" }} \ No newline at end of file diff --git a/Tests/Unit/Twig/Fixture/binary_concat_of_constants_compiled.html.twig b/Tests/Unit/Twig/Fixture/binary_concat_of_constants_compiled.html.twig new file mode 100644 index 00000000..ed9aff23 --- /dev/null +++ b/Tests/Unit/Twig/Fixture/binary_concat_of_constants_compiled.html.twig @@ -0,0 +1 @@ +{{ "foobarbaz" }} \ No newline at end of file diff --git a/Tests/Unit/Twig/Fixture/simple_template.html.twig b/Tests/Unit/Twig/Fixture/simple_template.html.twig new file mode 100644 index 00000000..2d56ebef --- /dev/null +++ b/Tests/Unit/Twig/Fixture/simple_template.html.twig @@ -0,0 +1,21 @@ +{{ "text.foo"|trans|desc("Foo Bar")|meaning("Some Meaning")}} + +{{ "text.bar"|trans|desc("Foo") }} + +{{ "text.baz"|trans|meaning("Bar") }} + +{{ "text.foo_bar"|trans({}, "foo") }} + +{% trans with {'%name%': 'Johannes'} from "app" %}text.name{% endtrans %} + +{% transchoice count with {'%name%': 'Johannes'} from "app" %}text.apple_choice{% endtranschoice %} + +{{ "foo.bar" | trans }} + +{{ "foo.bar2" | transchoice(5) }} + +{{ "foo.bar3" | trans({'%name%': 'Johannes'}, "app") }} + +{{ "foo.bar4" | transchoice(5, {'%name%': 'Johannes'}, 'app') }} + +{% trans %}text.default_domain{% endtrans %} \ No newline at end of file diff --git a/Tests/Unit/Twig/Fixture/simple_template_compiled.html.twig b/Tests/Unit/Twig/Fixture/simple_template_compiled.html.twig new file mode 100644 index 00000000..4f262627 --- /dev/null +++ b/Tests/Unit/Twig/Fixture/simple_template_compiled.html.twig @@ -0,0 +1,21 @@ +{{ "text.foo"|trans }} + +{{ "text.bar"|trans }} + +{{ "text.baz"|trans }} + +{{ "text.foo_bar"|trans({}, "foo") }} + +{% trans with {'%name%': 'Johannes'} from "app" %}text.name{% endtrans %} + +{% transchoice count with {'%name%': 'Johannes'} from "app" %}text.apple_choice{% endtranschoice %} + +{{ "foo.bar" | trans }} + +{{ "foo.bar2" | transchoice(5) }} + +{{ "foo.bar3" | trans({'%name%': 'Johannes'}, "app") }} + +{{ "foo.bar4" | transchoice(5, {'%name%': 'Johannes'}, 'app') }} + +{% trans %}text.default_domain{% endtrans %} \ No newline at end of file diff --git a/Tests/Unit/Twig/NormalizingNodeVisitorTest.php b/Tests/Unit/Twig/NormalizingNodeVisitorTest.php new file mode 100644 index 00000000..1879b102 --- /dev/null +++ b/Tests/Unit/Twig/NormalizingNodeVisitorTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Unit\Twig; + +/** + * @author Johannes M. Schmitt + */ +class NormalizingNodeVisitorTest extends BaseTwigTestCase +{ + public function testBinaryConcatOfConstants() + { + $this->assertEquals( + $this->parse('binary_concat_of_constants_compiled.html.twig'), + $this->parse('binary_concat_of_constants.html.twig') + ); + } +} diff --git a/Tests/Unit/Twig/RemovingNodeVisitorTest.php b/Tests/Unit/Twig/RemovingNodeVisitorTest.php new file mode 100644 index 00000000..09b92b4d --- /dev/null +++ b/Tests/Unit/Twig/RemovingNodeVisitorTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Unit\Twig; + +/** + * @author Johannes M. Schmitt + */ +class RemovingNodeVisitorTest extends BaseTwigTestCase +{ + public function testRemovalWithSimpleTemplate() + { + $expected = $this->parse('simple_template_compiled.html.twig'); + $actual = $this->parse('simple_template.html.twig'); + + $this->assertEquals($expected, $actual); + } +} diff --git a/Twig/EditInPlaceExtension.php b/Twig/EditInPlaceExtension.php new file mode 100644 index 00000000..14eb9923 --- /dev/null +++ b/Twig/EditInPlaceExtension.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Twig; + +use Symfony\Component\HttpFoundation\RequestStack; +use Translation\Bundle\EditInPlace\ActivatorInterface; + +/** + * Override the `trans` functions `is_safe` option to allow HTML output from the + * translator. This extension is used by for the EditInPlace feature. + * + * @author Damien Alexandre + */ +final class EditInPlaceExtension extends \Symfony\Bridge\Twig\Extension\TranslationExtension +{ + /** + * @var ActivatorInterface + */ + private $activator; + + /** + * @var RequestStack + */ + private $requestStack; + + /** + * {@inheritdoc} + */ + public function getFilters() + { + return [ + new \Twig_SimpleFilter('trans', [$this, 'trans'], ['is_safe_callback' => [$this, 'isSafe']]), + new \Twig_SimpleFilter('transchoice', [$this, 'transchoice'], ['is_safe_callback' => [$this, 'isSafe']]), + ]; + } + + /** + * Escape output if the EditInPlace is disabled. + * + * @return array + */ + public function isSafe($node) + { + return $this->activator->checkRequest($this->requestStack->getMasterRequest()) ? ['html'] : []; + } + + /** + * @param ActivatorInterface $activator + */ + public function setActivator(ActivatorInterface $activator) + { + $this->activator = $activator; + } + + /** + * @param RequestStack $requestStack + */ + public function setRequestStack(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return self::class; + } +} diff --git a/Twig/Node/Transchoice.php b/Twig/Node/Transchoice.php new file mode 100644 index 00000000..654688f3 --- /dev/null +++ b/Twig/Node/Transchoice.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Twig\Node; + +class Transchoice extends \Twig_Node_Expression +{ + public function __construct(\Twig_Node_Expression_Array $arguments, $lineno) + { + parent::__construct(['arguments' => $arguments], [], $lineno); + } + + public function compile(\Twig_Compiler $compiler) + { + $compiler->raw( + sprintf( + '$this->env->getExtension(\'%s\')->%s(', + 'Translation\Bundle\Twig\TranslationExtension', + 'transchoiceWithDefault' + ) + ); + + $first = true; + foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { + if (!$first) { + $compiler->raw(', '); + } + $first = false; + + $compiler->subcompile($pair['value']); + } + + $compiler->raw(')'); + } +} diff --git a/Twig/TranslationExtension.php b/Twig/TranslationExtension.php index 2da44391..02c556a2 100644 --- a/Twig/TranslationExtension.php +++ b/Twig/TranslationExtension.php @@ -11,69 +11,110 @@ namespace Translation\Bundle\Twig; -use Symfony\Component\HttpFoundation\RequestStack; -use Translation\Bundle\EditInPlace\ActivatorInterface; +use Symfony\Component\Translation\TranslatorInterface; +use Translation\Bundle\Twig\Visitor\DefaultApplyingNodeVisitor; +use Translation\Bundle\Twig\Visitor\NormalizingNodeVisitor; +use Translation\Bundle\Twig\Visitor\RemovingNodeVisitor; /** - * Override the `trans` functions `is_safe` option to allow HTML output from the - * translator. This extension is used by for the EditInPlace feature. - * - * @author Damien Alexandre + * @author Johannes M. Schmitt + * @author Tobias Nyholm */ -class TranslationExtension extends \Symfony\Bridge\Twig\Extension\TranslationExtension +final class TranslationExtension extends \Twig_Extension { /** - * @var ActivatorInterface + * @var TranslatorInterface */ - private $activator; + private $translator; /** - * @var RequestStack + * @var bool */ - private $requestStack; + private $debug; + + /** + * @param TranslatorInterface $translator + * @param bool $debug + */ + public function __construct(TranslatorInterface $translator, $debug = false) + { + $this->translator = $translator; + $this->debug = $debug; + } /** - * {@inheritdoc} + * @return array */ public function getFilters() { return [ - new \Twig_SimpleFilter('trans', [$this, 'trans'], ['is_safe_callback' => [$this, 'isSafe']]), - new \Twig_SimpleFilter('transchoice', [$this, 'transchoice'], ['is_safe_callback' => [$this, 'isSafe']]), + new \Twig_SimpleFilter('desc', [$this, 'desc']), + new \Twig_SimpleFilter('meaning', [$this, 'meaning']), ]; } /** - * Escape output if the EditInPlace is disabled. - * * @return array */ - public function isSafe($node) + public function getNodeVisitors() { - return $this->activator->checkRequest($this->requestStack->getMasterRequest()) ? ['html'] : []; + $visitors = [ + new NormalizingNodeVisitor(), + new RemovingNodeVisitor(), + ]; + + if ($this->debug) { + $visitors[] = new DefaultApplyingNodeVisitor(); + } + + return $visitors; } /** - * @param ActivatorInterface $activator + * @param string $message + * @param string $defaultMessage + * @param int $count + * @param array $arguments + * @param null|string $domain + * @param null|string $locale + * + * @return string */ - public function setActivator(ActivatorInterface $activator) + public function transchoiceWithDefault($message, $defaultMessage, $count, array $arguments = [], $domain = null, $locale = null) { - $this->activator = $activator; + if (null === $domain) { + $domain = 'messages'; + } + + if (false === $this->translator->getCatalogue($locale)->defines($message, $domain)) { + return $this->translator->transChoice($defaultMessage, $count, array_merge(['%count%' => $count], $arguments), $domain, $locale); + } + + return $this->translator->transChoice($message, $count, array_merge(['%count%' => $count], $arguments), $domain, $locale); } /** - * @param RequestStack $requestStack + * @param $v + * + * @return mixed */ - public function setRequestStack(RequestStack $requestStack) + public function desc($v) { - $this->requestStack = $requestStack; + return $v; } /** - * {@inheritdoc} + * @param $v + * + * @return mixed */ + public function meaning($v) + { + return $v; + } + public function getName() { - return self::class; + return 'php-translation'; } } diff --git a/Twig/Visitor/DefaultApplyingNodeVisitor.php b/Twig/Visitor/DefaultApplyingNodeVisitor.php new file mode 100644 index 00000000..a6618eaa --- /dev/null +++ b/Twig/Visitor/DefaultApplyingNodeVisitor.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Twig\Visitor; + +use Translation\Bundle\Twig\Node\Transchoice; + +/** + * Applies the value of the "desc" filter if the "trans" filter has no + * translations. + * + * This is only active in your development environment. + * + * @author Johannes M. Schmitt + */ +final class DefaultApplyingNodeVisitor extends \Twig_BaseNodeVisitor +{ + /** + * @var bool + */ + private $enabled = true; + + /** + * @param $bool + */ + public function setEnabled($bool) + { + $this->enabled = (bool) $bool; + } + + /** + * @param \Twig_Node $node + * @param \Twig_Environment $env + * + * @return \Twig_Node + */ + public function doEnterNode(\Twig_Node $node, \Twig_Environment $env) + { + if (!$this->enabled) { + return $node; + } + + if ($node instanceof \Twig_Node_Expression_Filter && 'desc' === $node->getNode('filter')->getAttribute('value')) { + $transNode = $node->getNode('node'); + while ($transNode instanceof \Twig_Node_Expression_Filter + && 'trans' !== $transNode->getNode('filter')->getAttribute('value') + && 'transchoice' !== $transNode->getNode('filter')->getAttribute('value')) { + $transNode = $transNode->getNode('node'); + } + + if (!$transNode instanceof \Twig_Node_Expression_Filter) { + throw new \RuntimeException(sprintf('The "desc" filter must be applied after a "trans", or "transchoice" filter.')); + } + + $wrappingNode = $node->getNode('node'); + $testNode = clone $wrappingNode; + $defaultNode = $node->getNode('arguments')->getNode(0); + + // if the |transchoice filter is used, delegate the call to the TranslationExtension + // so that we can catch a possible exception when the default translation has not yet + // been extracted + if ('transchoice' === $transNode->getNode('filter')->getAttribute('value')) { + $transchoiceArguments = new \Twig_Node_Expression_Array([], $transNode->getTemplateLine()); + $transchoiceArguments->addElement($wrappingNode->getNode('node')); + $transchoiceArguments->addElement($defaultNode); + foreach ($wrappingNode->getNode('arguments') as $arg) { + $transchoiceArguments->addElement($arg); + } + + $transchoiceNode = new Transchoice($transchoiceArguments, $transNode->getTemplateLine()); + $node->setNode('node', $transchoiceNode); + + return $node; + } + + // if the |trans filter has replacements parameters + // (e.g. |trans({'%foo%': 'bar'})) + if ($wrappingNode->getNode('arguments')->hasNode(0)) { + $lineno = $wrappingNode->getTemplateLine(); + + // remove the replacements from the test node + $testNode->setNode('arguments', clone $testNode->getNode('arguments')); + $testNode->getNode('arguments')->setNode(0, new \Twig_Node_Expression_Array([], $lineno)); + + // wrap the default node in a |replace filter + $defaultNode = new \Twig_Node_Expression_Filter( + clone $node->getNode('arguments')->getNode(0), + new \Twig_Node_Expression_Constant('replace', $lineno), + new \Twig_Node([ + clone $wrappingNode->getNode('arguments')->getNode(0), + ]), + $lineno + ); + } + + $condition = new \Twig_Node_Expression_Conditional( + new \Twig_Node_Expression_Binary_Equal($testNode, $transNode->getNode('node'), $wrappingNode->getTemplateLine()), + $defaultNode, + clone $wrappingNode, + $wrappingNode->getTemplateLine() + ); + $node->setNode('node', $condition); + } + + return $node; + } + + /** + * @param \Twig_Node $node + * @param \Twig_Environment $env + * + * @return \Twig_Node + */ + public function doLeaveNode(\Twig_Node $node, \Twig_Environment $env) + { + return $node; + } + + /** + * @return int + */ + public function getPriority() + { + return -2; + } +} diff --git a/Twig/DummyTwigVisitor.php b/Twig/Visitor/DummyTwigVisitor.php similarity index 91% rename from Twig/DummyTwigVisitor.php rename to Twig/Visitor/DummyTwigVisitor.php index 467ca2be..6e983e28 100644 --- a/Twig/DummyTwigVisitor.php +++ b/Twig/Visitor/DummyTwigVisitor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Translation\Bundle\Twig; +namespace Translation\Bundle\Twig\Visitor; /** * This dummy extractor is used to be compatible with both Twig1 and Twig2. It is only used in dependency injection diff --git a/Twig/Visitor/NormalizingNodeVisitor.php b/Twig/Visitor/NormalizingNodeVisitor.php new file mode 100644 index 00000000..9b600bd4 --- /dev/null +++ b/Twig/Visitor/NormalizingNodeVisitor.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Twig\Visitor; + +/** + * Performs equivalence transformations on the AST to ensure that + * subsequent visitors do not need to be aware of different syntaxes. + * + * E.g. "foo" ~ "bar" ~ "baz" would become "foobarbaz" + * + * @author Johannes M. Schmitt + */ +final class NormalizingNodeVisitor extends \Twig_BaseNodeVisitor +{ + /** + * @param \Twig_Node $node + * @param \Twig_Environment $env + * + * @return \Twig_Node + */ + protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) + { + return $node; + } + + /** + * @param \Twig_Node $node + * @param \Twig_Environment $env + * + * @return \Twig_Node_Expression_Constant|\Twig_Node + */ + protected function doLeaveNode(\Twig_Node $node, \Twig_Environment $env) + { + if ($node instanceof \Twig_Node_Expression_Binary_Concat + && ($left = $node->getNode('left')) instanceof \Twig_Node_Expression_Constant + && ($right = $node->getNode('right')) instanceof \Twig_Node_Expression_Constant) { + return new \Twig_Node_Expression_Constant($left->getAttribute('value').$right->getAttribute('value'), $left->getTemplateLine()); + } + + return $node; + } + + /** + * @return int + */ + public function getPriority() + { + return -3; + } +} diff --git a/Twig/Visitor/RemovingNodeVisitor.php b/Twig/Visitor/RemovingNodeVisitor.php new file mode 100644 index 00000000..ff69a3f3 --- /dev/null +++ b/Twig/Visitor/RemovingNodeVisitor.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Twig\Visitor; + +/** + * Removes translation metadata filters from the AST. + * + * @author Johannes M. Schmitt + */ +final class RemovingNodeVisitor extends \Twig_BaseNodeVisitor +{ + /** + * @var bool + */ + private $enabled = true; + + /** + * @param $bool + */ + public function setEnabled($bool) + { + $this->enabled = (bool) $bool; + } + + /** + * @param \Twig_Node $node + * @param \Twig_Environment $env + * + * @return \Twig_Node + */ + protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) + { + if ($this->enabled && $node instanceof \Twig_Node_Expression_Filter) { + $name = $node->getNode('filter')->getAttribute('value'); + + if ('desc' === $name || 'meaning' === $name) { + return $this->enterNode($node->getNode('node'), $env); + } + } + + return $node; + } + + /** + * @param \Twig_Node $node + * @param \Twig_Environment $env + * + * @return \Twig_Node + */ + protected function doLeaveNode(\Twig_Node $node, \Twig_Environment $env) + { + return $node; + } + + /** + * @return int + */ + public function getPriority() + { + return -1; + } +}