Browse Source

[TwigBundle] replaced current {{ foo }} syntax for translation placeholders to %foo%

Fabien Potencier 14 years ago
parent
commit
0e487cdda6

+ 49 - 45
src/Symfony/Bundle/TwigBundle/Node/TransNode.php

@@ -18,9 +18,9 @@ namespace Symfony\Bundle\TwigBundle\Node;
  */
 class TransNode extends \Twig_Node
 {
-    public function __construct(\Twig_NodeInterface $body, \Twig_NodeInterface $domain, \Twig_Node_Expression $count = null, \Twig_Node_Expression $vars = null, $isSimple, $lineno, $tag = null)
+    public function __construct(\Twig_NodeInterface $body, \Twig_NodeInterface $domain, \Twig_Node_Expression $count = null, \Twig_Node_Expression $vars = null, $lineno, $tag = null)
     {
-        parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain, 'vars' => $vars), array('is_simple' => $isSimple), $lineno, $tag);
+        parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain, 'vars' => $vars), array(), $lineno, $tag);
     }
 
     /**
@@ -32,13 +32,15 @@ class TransNode extends \Twig_Node
     {
         $compiler->addDebugInfo($this);
 
-        $defaults = null;
-        if ($this->getAttribute('is_simple')) {
-            list($msg, $defaults) = $this->compileString($this->getNode('body'));
-        } else {
-            $msg = $this->getNode('body');
+        $vars = $this->getNode('vars');
+        $defaults = new \Twig_Node_Expression_Array(array(), -1);
+        if ($vars instanceof \Twig_Node_Expression_Array) {
+            $defaults = $this->getNode('vars');
+            $vars = null;
         }
 
+        list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults);
+
         $method = null === $this->getNode('count') ? 'trans' : 'transChoice';
 
         $compiler
@@ -55,56 +57,58 @@ class TransNode extends \Twig_Node
             ;
         }
 
-        $compiler->raw('array_merge(');
-
-        if (null === $defaults) {
-            $compiler->raw('array()');
-        } else {
-            $compiler->raw('array(');
-            foreach ($defaults as $default) {
-                $compiler
-                    ->string('{{ '.$default->getAttribute('name').' }}')
-                    ->raw(' => ')
-                    ->subcompile($default)
-                    ->raw(', ')
-                ;
-            }
-            $compiler->raw(')');
-        }
-
-        $compiler->raw(', ');
-
-        if (null === $this->getNode('vars')) {
-            $compiler->raw('array()');
+        if (null !== $vars) {
+            $compiler->raw('array_merge(');
+            $this->compileDefaults($compiler, $defaults);
+            $compiler
+                ->raw(', ')
+                ->subcompile($this->getNode('vars'))
+                ->raw(')')
+            ;
         } else {
-            $compiler->subcompile($this->getNode('vars'));
+            $this->compileDefaults($compiler, $defaults);
         }
 
         $compiler
-            ->raw('), ')
+            ->raw(', ')
             ->subcompile($this->getNode('domain'))
             ->raw(");\n")
         ;
     }
 
-    protected function compileString(\Twig_NodeInterface $body)
+    protected function compileDefaults(\Twig_Compiler $compiler, \Twig_Node_Expression_Array $defaults)
     {
-        if ($body instanceof \Twig_Node_Expression_Name || $body instanceof \Twig_Node_Expression_Constant) {
-            return array($body, array());
+        $compiler->raw('array(');
+        foreach ($defaults as $name => $default) {
+            $compiler
+                ->repr($name)
+                ->raw(' => ')
+                ->subcompile($default)
+                ->raw(', ')
+            ;
+        }
+        $compiler->raw(')');
+    }
+
+    protected function compileString(\Twig_NodeInterface $body, \Twig_Node_Expression_Array $vars)
+    {
+        if ($body instanceof \Twig_Node_Expression_Constant) {
+            $msg = $body->getAttribute('value');
+        } elseif ($body instanceof \Twig_Node_Text) {
+            $msg = $body->getAttribute('data');
+        } else {
+            return array($body, $vars);
+        }
+
+        $current = array();
+        foreach ($vars as $name => $var) {
+            $current[$name] = true;
         }
 
-        $msg = '';
-        $vars = array();
-        foreach ($body as $node) {
-            if ($node instanceof \Twig_Node_Print) {
-                $n = $node->getNode('expr');
-                while ($n instanceof \Twig_Node_Expression_Filter) {
-                    $n = $n->getNode('node');
-                }
-                $msg .= sprintf('{{ %s }}', $n->getAttribute('name'));
-                $vars[] = new \Twig_Node_Expression_Name($n->getAttribute('name'), $n->getLine());
-            } else {
-                $msg .= $node->getAttribute('data');
+        preg_match_all('/\%([^\%]+)\%/', $msg, $matches);
+        foreach ($matches[1] as $var) {
+            if (!isset($current['%'.$var.'%'])) {
+                $vars->setNode('%'.$var.'%', new \Twig_Node_Expression_Name($var, $body->getLine()));
             }
         }
 

+ 13 - 12
src/Symfony/Bundle/TwigBundle/Tests/TransTest.php

@@ -41,35 +41,36 @@ class TransTest extends TestCase
         return array(
             // trans tag
             array('{% trans "Hello" %}', 'Hello'),
+            array('{% trans "Hello %name%" %}', 'Hello Symfony2', array('name' => 'Symfony2')),
             array('{% trans name %}', 'Symfony2', array('name' => 'Symfony2')),
-            array('{% trans hello with { \'{{ name }}\': \'Symfony2\' } %}', 'Hello Symfony2', array('hello' => 'Hello {{ name }}')),
-            array('{% set vars = { \'{{ name }}\': \'Symfony2\' } %}{% trans hello with vars %}', 'Hello Symfony2', array('hello' => 'Hello {{ name }}')),
+            array('{% trans hello with { \'%name%\': \'Symfony2\' } %}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
+            array('{% set vars = { \'%name%\': \'Symfony2\' } %}{% trans hello with vars %}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
 
             array('{% trans %}Hello{% endtrans %}', 'Hello'),
-            array('{% trans %}{{ name }}{% endtrans %}', 'Symfony2', array('name' => 'Symfony2')),
+            array('{% trans %}%name%{% endtrans %}', 'Symfony2', array('name' => 'Symfony2')),
 
             array('{% trans "Hello" from elsewhere %}', 'Hello'),
             array('{% trans from elsewhere %}Hello{% endtrans %}', 'Hello'),
 
-            array('{% trans %}Hello {{ name }}{% endtrans %}', 'Hello Symfony2', array('name' => 'Symfony2')),
-            array('{% trans with { \'{{ name }}\': \'Symfony2\' } %}Hello {{ name }}{% endtrans %}', 'Hello Symfony2'),
-            array('{% set vars = { \'{{ name }}\': \'Symfony2\' } %}{% trans with vars %}Hello {{ name }}{% endtrans %}', 'Hello Symfony2'),
+            array('{% trans %}Hello %name%{% endtrans %}', 'Hello Symfony2', array('name' => 'Symfony2')),
+            array('{% trans with { \'%name%\': \'Symfony2\' } %}Hello %name%{% endtrans %}', 'Hello Symfony2'),
+            array('{% set vars = { \'%name%\': \'Symfony2\' } %}{% trans with vars %}Hello %name%{% endtrans %}', 'Hello Symfony2'),
 
             // transchoice
-            array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples{% endtranschoice %}',
+            array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
                 'There is no apples', array('count' => 0)),
-            array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples{% endtranschoice %}',
+            array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
                 'There is 5 apples', array('count' => 5)),
-            array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples ({{ name }}){% endtranschoice %}',
+            array('{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
                 'There is 5 apples (Symfony2)', array('count' => 5, 'name' => 'Symfony2')),
-            array('{% transchoice count with { \'{{ name }}\': \'Symfony2\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is {{ count }} apples ({{ name }}){% endtranschoice %}',
+            array('{% transchoice count with { \'%name%\': \'Symfony2\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
                 'There is 5 apples (Symfony2)', array('count' => 5)),
 
             // trans filter
             array('{{ "Hello"|trans }}', 'Hello'),
             array('{{ name|trans }}', 'Symfony2', array('name' => 'Symfony2')),
-            array('{{ hello|trans({ \'{{ name }}\': \'Symfony2\' }) }}', 'Hello Symfony2', array('hello' => 'Hello {{ name }}')),
-            array('{% set vars = { \'{{ name }}\': \'Symfony2\' } %}{{ hello|trans(vars) }}', 'Hello Symfony2', array('hello' => 'Hello {{ name }}')),
+            array('{{ hello|trans({ \'%name%\': \'Symfony2\' }) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
+            array('{% set vars = { \'%name%\': \'Symfony2\' } %}{{ hello|trans(vars) }}', 'Hello Symfony2', array('hello' => 'Hello %name%')),
         );
     }
 

+ 5 - 4
src/Symfony/Bundle/TwigBundle/TokenParser/TransChoiceTokenParser.php

@@ -32,7 +32,7 @@ class TransChoiceTokenParser extends TransTokenParser
         $lineno = $token->getLine();
         $stream = $this->parser->getStream();
 
-        $vars = null;
+        $vars = new \Twig_Node_Expression_Array(array(), $lineno);
 
         $count = $this->parser->getExpressionParser()->parseExpression();
 
@@ -53,13 +53,14 @@ class TransChoiceTokenParser extends TransTokenParser
         $stream->expect(\Twig_Token::BLOCK_END_TYPE);
 
         $body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true);
-        if ('Twig_Node' !== get_class($body)) {
-            $body = new \Twig_Node(array($body), array(), $body->getLine());
+
+        if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
+            throw new \Twig_Error_Syntax('A message must be a simple text', -1);
         }
 
         $stream->expect(\Twig_Token::BLOCK_END_TYPE);
 
-        return new TransNode($body, $domain, $count, $vars, $this->isSimpleString($body), $lineno, $this->getTag());
+        return new TransNode($body, $domain, $count, $vars, $lineno, $this->getTag());
     }
 
     public function decideTransChoiceFork($token)

+ 7 - 25
src/Symfony/Bundle/TwigBundle/TokenParser/TransTokenParser.php

@@ -32,9 +32,8 @@ class TransTokenParser extends \Twig_TokenParser
         $lineno = $token->getLine();
         $stream = $this->parser->getStream();
 
-        $vars = null;
         $body = null;
-        $isSimple = false;
+        $vars = new \Twig_Node_Expression_Array(array(), $lineno);
         $domain = new \Twig_Node_Expression_Constant('messages', $lineno);
         if (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
             if (!$stream->test('from') && !$stream->test('with')) {
@@ -54,7 +53,7 @@ class TransTokenParser extends \Twig_TokenParser
                 $stream->next();
                 $domain = $this->parser->getExpressionParser()->parseExpression();
             } elseif (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
-                throw new \Twig_SyntaxError(sprintf('Unexpected token. Twig was looking for the "from" keyword line %s)', $lineno), -1);
+                throw new \Twig_Error_Syntax(sprintf('Unexpected token. Twig was looking for the "from" keyword line %s)', $lineno), -1);
             }
         }
 
@@ -62,15 +61,15 @@ class TransTokenParser extends \Twig_TokenParser
             // {% trans %}message{% endtrans %}
             $stream->expect(\Twig_Token::BLOCK_END_TYPE);
             $body = $this->parser->subparse(array($this, 'decideTransFork'), true);
-            if ('Twig_Node' !== get_class($body)) {
-                $body = new \Twig_Node(array($body), array(), $body->getLine());
-            }
-            $isSimple = $this->isSimpleString($body);
+        }
+
+        if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
+            throw new \Twig_Error_Syntax('A message must be a simple text', -1);
         }
 
         $stream->expect(\Twig_Token::BLOCK_END_TYPE);
 
-        return new TransNode($body, $domain, null, $vars, $isSimple, $lineno, $this->getTag());
+        return new TransNode($body, $domain, null, $vars, $lineno, $this->getTag());
     }
 
     public function decideTransFork($token)
@@ -78,23 +77,6 @@ class TransTokenParser extends \Twig_TokenParser
         return $token->test(array('endtrans'));
     }
 
-    protected function isSimpleString(\Twig_NodeInterface $body)
-    {
-        foreach ($body as $i => $node) {
-            if (
-                $node instanceof \Twig_Node_Text
-                ||
-                ($node instanceof \Twig_Node_Print && $node->getNode('expr') instanceof \Twig_Node_Expression_Name)
-            ) {
-                continue;
-            }
-
-            return false;
-        }
-
-        return true;
-    }
-
     /**
      * Gets the tag name associated with this token parser.
      *