浏览代码

[TwigBundle] added helpers for translations

Fabien Potencier 14 年之前
父节点
当前提交
d6f55c31d1

+ 10 - 0
src/Symfony/Bundle/TwigBundle/Extension/Helpers.php

@@ -4,6 +4,8 @@ namespace Symfony\Bundle\TwigBundle\Extension;
 
 use Symfony\Component\Templating\Engine;
 use Symfony\Bundle\TwigBundle\TokenParser\HelperTokenParser;
+use Symfony\Bundle\TwigBundle\TokenParser\TransTokenParser;
+use Symfony\Bundle\TwigBundle\TokenParser\TransChoiceTokenParser;
 
 /*
  * This file is part of the Symfony package.
@@ -51,6 +53,14 @@ class Helpers extends \Twig_Extension
 
             // {% flash 'notice' %}
             new HelperTokenParser('flash', '<name>', 'session', 'flash'),
+
+            // {% trans "Symfony is great!" %}
+            new TransTokenParser(),
+
+            // {% transchoice count %}
+            //     {0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples
+            // {% endtranschoice %}
+            new TransChoiceTokenParser(),
         );
     }
 

+ 94 - 0
src/Symfony/Bundle/TwigBundle/Node/TransNode.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace Symfony\Bundle\TwigBundle\Node;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * 
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class TransNode extends \Twig_Node
+{
+    public function __construct(\Twig_NodeInterface $body, \Twig_NodeInterface $domain, \Twig_Node_Expression $count = null, $lineno, $tag = null)
+    {
+        parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain), array(), $lineno, $tag);
+    }
+
+    /**
+     * Compiles the node to PHP.
+     *
+     * @param \Twig_Compiler A Twig_Compiler instance
+     */
+    public function compile($compiler)
+    {
+        $compiler->addDebugInfo($this);
+
+        list($msg, $vars) = $this->compileString($this->body);
+
+        $method = null === $this->count ? 'trans' : 'transChoice';
+
+        $compiler
+            ->write('echo $context[\'_view\'][\'translator\']->'.$method.'(')
+            ->subcompile($msg)
+        ;
+
+        $compiler->raw(', ');
+
+        if (null !== $this->count) {
+            $compiler
+                ->subcompile($this->count)
+                ->raw(', ')
+            ;
+        }
+
+        $compiler->raw('array(');
+
+        foreach ($vars as $var) {
+            $compiler
+                ->string('{{ '.$var['name'].' }}')
+                ->raw(' => ')
+                ->subcompile($var)
+                ->raw(', ')
+            ;
+        }
+
+        $compiler
+            ->raw("), ")
+            ->subcompile($this->domain)
+            ->raw(");\n")
+        ;
+    }
+
+    protected function compileString(\Twig_NodeInterface $body)
+    {
+        if ($body instanceof \Twig_Node_Expression_Name || $body instanceof \Twig_Node_Expression_Constant) {
+            return array($body, array());
+        }
+
+        $msg = '';
+        $vars = array();
+        foreach ($body as $node) {
+            if ($node instanceof \Twig_Node_Print) {
+                $n = $node->expr;
+                while ($n instanceof \Twig_Node_Expression_Filter) {
+                    $n = $n->node;
+                }
+                $msg .= sprintf('{{ %s }}', $n['name']);
+                $vars[] = new \Twig_Node_Expression_Name($n['name'], $n->getLine());
+            } else {
+                $msg .= $node['data'];
+            }
+        }
+
+        return array(new \Twig_Node(array(new \Twig_Node_Expression_Constant(trim($msg), $node->getLine()))), $vars);
+    }
+}

+ 68 - 0
src/Symfony/Bundle/TwigBundle/TokenParser/TransChoiceTokenParser.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace Symfony\Bundle\TwigBundle\TokenParser;
+
+use Symfony\Bundle\TwigBundle\Node\TransNode;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * 
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class TransChoiceTokenParser extends TransTokenParser
+{
+    /**
+     * 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)
+    {
+        $lineno = $token->getLine();
+        $stream = $this->parser->getStream();
+
+        $count = $this->parser->getExpressionParser()->parseExpression();
+
+        $domain = new \Twig_Node_Expression_Constant('messages', $lineno);
+        if (!$stream->test(\Twig_Token::BLOCK_END_TYPE) && $stream->test('from')) {
+            $stream->next();
+            $domain = $this->parser->getExpressionParser()->parseExpression();
+        }
+
+        $stream->expect(\Twig_Token::BLOCK_END_TYPE);
+
+        $body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true);
+
+        $stream->expect(\Twig_Token::BLOCK_END_TYPE);
+
+        $this->checkTransString($body, $lineno);
+
+        return new TransNode($body, $domain, $count, $lineno, $this->getTag());
+    }
+
+    public function decideTransChoiceFork($token)
+    {
+        return $token->test(array('endtranschoice'));
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @param string The tag name
+     */
+    public function getTag()
+    {
+        return 'transchoice';
+    }
+}

+ 86 - 0
src/Symfony/Bundle/TwigBundle/TokenParser/TransTokenParser.php

@@ -0,0 +1,86 @@
+<?php
+
+namespace Symfony\Bundle\TwigBundle\TokenParser;
+
+use Symfony\Bundle\TwigBundle\Node\TransNode;
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * 
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+class TransTokenParser 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)
+    {
+        $lineno = $token->getLine();
+        $stream = $this->parser->getStream();
+
+        $domain = new \Twig_Node_Expression_Constant('messages', $lineno);
+        if (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
+            if (!$stream->test('from')) {
+                $body = $this->parser->getExpressionParser()->parseExpression();
+            }
+
+            if ($stream->test('from')) {
+                $stream->next();
+                $domain = $this->parser->getExpressionParser()->parseExpression();
+            }
+        } else {
+            $stream->expect(\Twig_Token::BLOCK_END_TYPE);
+            $body = $this->parser->subparse(array($this, 'decideTransFork'));
+        }
+
+        $stream->expect(\Twig_Token::BLOCK_END_TYPE);
+
+        $this->checkTransString($body, $lineno);
+
+        return new TransNode($body, $domain, null, $lineno, $this->getTag());
+    }
+
+    public function decideTransFork($token)
+    {
+        return $token->test(array('endtrans'));
+    }
+
+    /**
+     * Gets the tag name associated with this token parser.
+     *
+     * @param string The tag name
+     */
+    public function getTag()
+    {
+        return 'trans';
+    }
+
+    protected function checkTransString(\Twig_NodeInterface $body, $lineno)
+    {
+        foreach ($body as $i => $node) {
+            if (
+                $node instanceof \Twig_Node_Text
+                ||
+                ($node instanceof \Twig_Node_Print && $node->expr instanceof \Twig_Node_Expression_Name)
+            ) {
+                continue;
+            }
+
+            throw new \Twig_SyntaxError(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno);
+        }
+    }
+}