From ce6399e254d57fda8b4a98eab52bf79c57597507 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 2 Jan 2012 17:47:49 +0100 Subject: [PATCH] [TwigBridge] added a way to specify a default domain for a Twig template (via the 'trans_default_domain' tag) Note that the tag only influences the current templates. It has no effect on included files to avoid unwanted side-effects. --- CHANGELOG-2.1.md | 4 + .../Twig/Extension/TranslationExtension.php | 7 +- .../Twig/Node/TransDefaultDomainNode.php | 33 ++++++++ .../TranslationDefaultDomainNodeVisitor.php | 81 +++++++++++++++++++ .../NodeVisitor/TranslationNodeVisitor.php | 2 +- .../TransDefaultDomainTokenParser.php | 48 +++++++++++ .../Extension/TranslationExtensionTest.php | 49 ++++++++++- 7 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php create mode 100644 src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php create mode 100644 src/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md index 629d2233b9f7..90e835a379f0 100644 --- a/CHANGELOG-2.1.md +++ b/CHANGELOG-2.1.md @@ -15,6 +15,10 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * added a default implementation of the ManagerRegistry * added a session storage for Doctrine DBAL +### TwigBridge + + * added a way to specify a default domain for a Twig template (via the 'trans_default_domain' tag) + ### AbstractDoctrineBundle * This bundle has been removed and the relevant code has been moved to the Doctrine bridge diff --git a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php index 90d36a85a68c..3718e9e2c4d8 100644 --- a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php @@ -13,8 +13,10 @@ use Symfony\Bridge\Twig\TokenParser\TransTokenParser; use Symfony\Bridge\Twig\TokenParser\TransChoiceTokenParser; +use Symfony\Bridge\Twig\TokenParser\TransDefaultDomainTokenParser; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor; +use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor; /** * Provides integration of the Translation component with Twig. @@ -63,6 +65,9 @@ public function getTokenParsers() // {0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples // {% endtranschoice %} new TransChoiceTokenParser(), + + // {% trans_default_domain "foobar" %} + new TransDefaultDomainTokenParser(), ); } @@ -71,7 +76,7 @@ public function getTokenParsers() */ public function getNodeVisitors() { - return array($this->translationNodeVisitor); + return array($this->translationNodeVisitor, new TranslationDefaultDomainNodeVisitor()); } public function getTranslationNodeVisitor() diff --git a/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php b/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php new file mode 100644 index 000000000000..adee71ffc5dc --- /dev/null +++ b/src/Symfony/Bridge/Twig/Node/TransDefaultDomainNode.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Node; + +/** + * @author Fabien Potencier + */ +class TransDefaultDomainNode extends \Twig_Node +{ + public function __construct(\Twig_Node_Expression $expr, $lineno = 0, $tag = null) + { + parent::__construct(array('expr' => $expr), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param \Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(\Twig_Compiler $compiler) + { + // noop as this node is just a marker for TranslationDefaultDomainNodeVisitor + } +} diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php new file mode 100644 index 000000000000..c7bebdd12a57 --- /dev/null +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\NodeVisitor; + +use Symfony\Bridge\Twig\Node\TransNode; +use Symfony\Bridge\Twig\Node\TransDefaultDomainNode; + +/** + * TranslationDefaultDomainNodeVisitor. + * + * @author Fabien Potencier + */ +class TranslationDefaultDomainNodeVisitor implements \Twig_NodeVisitorInterface +{ + private $domain; + + /** + * {@inheritdoc} + */ + public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env) + { + if ($node instanceof \Twig_Node_Module) { + $this->domain = null; + } + + if ($node instanceof TransDefaultDomainNode) { + $var = $env->getParser()->getVarName(); + $name = new \Twig_Node_Expression_AssignName($var, $node->getLine()); + $this->domain = new \Twig_Node_Expression_Name($var, $node->getLine()); + + return new \Twig_Node_Set(false, new \Twig_Node(array($name)), new \Twig_Node(array($node->getNode('expr'))), $node->getLine()); + } + + if (null === $this->domain) { + return $node; + } + + if ($node instanceof \Twig_Node_Expression_Filter && in_array($node->getNode('filter')->getAttribute('value'), array('trans', 'transchoice'))) { + $ind = 'trans' === $node->getNode('filter')->getAttribute('value') ? 1 : 2; + $arguments = $node->getNode('arguments'); + if (!$arguments->hasNode($ind)) { + if (!$arguments->hasNode($ind - 1)) { + $arguments->setNode($ind - 1, new \Twig_Node_Expression_Array(array(), $node->getLine())); + } + + $arguments->setNode($ind, $this->domain); + } + } elseif ($node instanceof TransNode) { + if (null === $node->getNode('domain')) { + $node->setNode('domain', $this->domain); + } + } + + return $node; + } + + /** + * {@inheritdoc} + */ + public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env) + { + return $node; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } +} diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php index 2ce1c303bc3c..3a943f7106ca 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php @@ -93,6 +93,6 @@ public function leaveNode(\Twig_NodeInterface $node, \Twig_Environment $env) */ public function getPriority() { - return 255; + return -10; } } diff --git a/src/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php b/src/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php new file mode 100644 index 000000000000..7030dfff6c81 --- /dev/null +++ b/src/Symfony/Bridge/Twig/TokenParser/TransDefaultDomainTokenParser.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\TokenParser; + +use Symfony\Bridge\Twig\Node\TransDefaultDomainNode; + +/** + * Token Parser for the 'trans_default_domain' tag. + * + * @author Fabien Potencier + */ +class TransDefaultDomainTokenParser extends \Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param \Twig_Token $token A Twig_Token instance + * + * @return \Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(\Twig_Token $token) + { + $expr = $this->parser->getExpressionParser()->parseExpression(); + + $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); + + return new TransDefaultDomainNode($expr, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'trans_default_domain'; + } +} diff --git a/tests/Symfony/Tests/Bridge/Twig/Extension/TranslationExtensionTest.php b/tests/Symfony/Tests/Bridge/Twig/Extension/TranslationExtensionTest.php index 4ec0dd7de2ae..dfd931522a3d 100644 --- a/tests/Symfony/Tests/Bridge/Twig/Extension/TranslationExtensionTest.php +++ b/tests/Symfony/Tests/Bridge/Twig/Extension/TranslationExtensionTest.php @@ -14,6 +14,7 @@ use Symfony\Bridge\Twig\Extension\TranslationExtension; use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\MessageSelector; +use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Tests\Bridge\Twig\TestCase; class TranslationExtensionTest extends TestCase @@ -91,11 +92,53 @@ public function getTransTests() ); } - protected function getTemplate($template) + public function testDefaultTranslationDomain() { - $loader = new \Twig_Loader_Array(array('index' => $template)); + $templates = array( + 'index' => ' + {%- extends "base" %} + + {%- trans_default_domain "foo" %} + + {%- block content %} + {%- trans %}foo{% endtrans %} + {%- trans from "custom" %}foo{% endtrans %} + {{- "foo"|trans }} + {{- "foo"|trans({}, "custom") }} + {{- "foo"|transchoice(1) }} + {{- "foo"|transchoice(1, {}, "custom") }} + {% endblock %} + ', + + 'base' => ' + {%- block content "" %} + ', + ); + + $translator = new Translator('en', new MessageSelector()); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', array('foo' => 'foo (messages)'), 'en'); + $translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom'); + $translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo'); + + $template = $this->getTemplate($templates, $translator); + + $this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array()))); + } + + protected function getTemplate($template, $translator = null) + { + if (null === $translator) { + $translator = new Translator('en', new MessageSelector()); + } + + if (is_array($template)) { + $loader = new \Twig_Loader_Array($template); + } else { + $loader = new \Twig_Loader_Array(array('index' => $template)); + } $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); - $twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector()))); + $twig->addExtension(new TranslationExtension($translator)); return $twig->loadTemplate('index'); }