* arrays keep the same syntax with square brackets: [1, 2]
* hashes now use curly braces (["a": "b"] should now be written as {"a": "b"})
* support for "arrays with keys" and "hashes without keys" is not supported anymore ([1, "foo": "bar"] or {"foo": "bar", 1})
+ * the i18n extension is now part of the Twig Extensions repository
Changes:
<p>{{ forms.textarea('comment') }}</p>
-### Internationalization (new in Twig 0.9.6)
-
-When the `i18n` extension is enabled, use the `trans` block to mark parts in
-the template as translatable:
-
- [twig]
- {% trans "Hello World!" %}
-
- {% trans string_var %}
-
- {% trans %}
- Hello World!
- {% endtrans %}
-
->**CAUTION**
->The `I18n` extension only works if the PHP
->[gettext](http://www.php.net/gettext) extension is enabled.
-
-In a translatable string, you can embed variables:
-
- [twig]
- {% trans %}
- Hello {{ name }}!
- {% endtrans %}
-
->**NOTE**
->`{% trans "Hello {{ name }}!" %}` is not a valid statement.
-
-If you need to apply filters to the variables, you first need to assign the
-result to a variable:
-
- [twig]
- {% set name = name|capitalize %}
-
- {% trans %}
- Hello {{ name }}!
- {% endtrans %}
-
-To pluralize a translatable string, use the `plural` block:
-
- [twig]
- {% trans %}
- Hey {{ name }}, I have one apple.
- {% plural apple_count %}
- Hey {{ name }}, I have {{ count }} apples.
- {% endtrans %}
-
-The `plural` tag should provide the `count` used to select the right string.
-Within the translatable string, the special `count` variable always contain
-the count value (here the value of `apple_count`).
-
-Within an expression or in a tag, you can use the `trans` filter to translate
-simple strings or variables (new in Twig 0.9.9):
-
- [twig]
- {{ var|default(default_value|trans) }}
-
Expressions
-----------
* *Twig_Extension_Sandbox*: Adds a sandbox mode to the default Twig environment, making it
safe to evaluated untrusted code.
- * *Twig_Extension_I18n*: Adds internationalization support via the gettext library.
-
* *Twig_Extension_Optimizer*: Optimizers the node tree before compilation (as
of Twig 0.9.10).
[php]
$sandbox = new Twig_Extension_Sandbox($policy, true);
-### I18n Extension
-
-The `i18n` extension adds [gettext](http://www.php.net/gettext) support to
-Twig. It defines one tag, `trans`.
-
-You need to register this extension before using the `trans` block:
-
- [php]
- $twig->addExtension(new Twig_Extension_I18n());
-
-Note that you must configure the gettext extension before rendering any
-internationalized template. Here is a simple configuration example from the
-PHP [documentation](http://fr.php.net/manual/en/function.gettext.php):
-
- [php]
- // Set language to French
- putenv('LC_ALL=fr_FR');
- setlocale(LC_ALL, 'fr_FR');
-
- // Specify the location of the translation tables
- bindtextdomain('myAppPhp', 'includes/locale');
- bind_textdomain_codeset('myAppPhp', 'UTF-8');
-
- // Choose domain
- textdomain('myAppPhp');
-
->**NOTE**
->The chapter "Twig for Web Designers" contains more information about how to
->use the `trans` block in your templates.
-
### Optimizer Extension (as of Twig 0.9.10)
The `optimizer` extension optimizes the node tree before compilation:
{% endset %}
{{ form.row('Label', theinput) }}
-
-Extracting Template Strings for Internationalization
-----------------------------------------------------
-
-If you use the Twig I18n extension, you will probably need to extract the
-template strings at some point. Unfortunately, the `xgettext` utility does not
-understand Twig templates natively. But there is a simple workaround: as Twig
-converts templates to PHP files, you can use `xgettext` on the template cache
-instead.
-
-Create a script that forces the generation of the cache for all your
-templates. Here is a simple example to get you started:
-
- [php]
- $tplDir = dirname(__FILE__).'/templates';
- $tmpDir = '/tmp/cache/';
- $loader = new Twig_Loader_Filesystem($tplDir);
-
- // force auto-reload to always have the latest version of the template
- $twig = new Twig_Environment($loader, array(
- 'cache' => $tmpDir,
- 'auto_reload' => true
- ));
- $twig->addExtension(new Twig_Extension_I18n());
- // configure Twig the way you want
-
- // iterate over all your templates
- foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($tplDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file)
- {
- // force compilation
- $twig->loadTemplate(str_replace($tplDir.'/', '', $file));
- }
-
-Use the standard `xgettext` utility as you would have done with plain PHP
-code:
-
- xgettext --default-domain=messages -p ./locale --from-code=UTF-8 -n --omit-header -L PHP /tmp/cache/*.php
-
-Complex Translations within an Expression or Tag
-------------------------------------------------
-
-Translations can be done with both the `trans` tag and the `trans` filter. The
-filter is less powerful as it only works for simple variables or strings. For
-more complex scenario, like pluralization, you can use a two-step strategy
-(new in Twig 0.9.9):
-
- [twig]
- {# assign the translation to a temporary variable #}
- {% set default_value %}
- {% trans %}
- Hey {{ name }}, I have one apple.
- {% plural apple_count %}
- Hey {{ name }}, I have {{ count }} apples.
- {% endtrans %}
- {% endset %}
-
- {# use the temporary variable within an expression #}
- {{ var|default(default_value|trans) }}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_Extension_I18n extends Twig_Extension
-{
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- public function getTokenParsers()
- {
- return array(new Twig_TokenParser_Trans());
- }
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- public function getFilters()
- {
- return array(
- 'trans' => new Twig_Filter_Function('gettext'),
- );
- }
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'i18n';
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-/**
- * Represents a trans node.
- *
- * @package twig
- * @author Fabien Potencier <fabien.potencier@symfony-project.com>
- */
-class Twig_Node_Trans extends Twig_Node
-{
- public function __construct(Twig_NodeInterface $body, Twig_NodeInterface $plural = null, Twig_Node_Expression $count = null, $lineno, $tag = null)
- {
- parent::__construct(array('count' => $count, 'body' => $body, 'plural' => $plural), 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->getNode('body'));
-
- if (null !== $this->getNode('plural')) {
- list($msg1, $vars1) = $this->compileString($this->getNode('plural'));
-
- $vars = array_merge($vars, $vars1);
- }
-
- $function = null === $this->getNode('plural') ? 'gettext' : 'ngettext';
-
- if ($vars) {
- $compiler
- ->write('echo strtr('.$function.'(')
- ->subcompile($msg)
- ;
-
- if (null !== $this->getNode('plural')) {
- $compiler
- ->raw(', ')
- ->subcompile($msg1)
- ->raw(', abs(')
- ->subcompile($this->getNode('count'))
- ->raw(')')
- ;
- }
-
- $compiler->raw('), array(');
-
- foreach ($vars as $var) {
- if ('count' === $var->getAttribute('name')) {
- $compiler
- ->string('%count%')
- ->raw(' => abs(')
- ->subcompile($this->getNode('count'))
- ->raw('), ')
- ;
- } else {
- $compiler
- ->string('%'.$var->getAttribute('name').'%')
- ->raw(' => ')
- ->subcompile($var)
- ->raw(', ')
- ;
- }
- }
-
- $compiler->raw("));\n");
- } else {
- $compiler
- ->write('echo '.$function.'(')
- ->subcompile($msg)
- ;
-
- if (null !== $this->getNode('plural')) {
- $compiler
- ->raw(', ')
- ->subcompile($msg1)
- ->raw(', abs(')
- ->subcompile($this->getNode('count'))
- ->raw(')')
- ;
- }
-
- $compiler->raw(');');
- }
- }
-
- 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->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');
- }
- }
-
- return array(new Twig_Node(array(new Twig_Node_Expression_Constant(trim($msg), $node->getLine()))), $vars);
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) 2010 Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-class Twig_TokenParser_Trans 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();
- $count = null;
- $plural = null;
-
- if (!$stream->test(Twig_Token::BLOCK_END_TYPE)) {
- $body = $this->parser->getExpressionParser()->parseExpression();
- } else {
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $body = $this->parser->subparse(array($this, 'decideForFork'));
- if ('plural' === $stream->next()->getValue()) {
- $count = $this->parser->getExpressionParser()->parseExpression();
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
- $plural = $this->parser->subparse(array($this, 'decideForEnd'), true);
- }
- }
-
- $stream->expect(Twig_Token::BLOCK_END_TYPE);
-
- $this->checkTransString($body, $lineno);
-
- return new Twig_Node_Trans($body, $plural, $count, $lineno, $this->getTag());
- }
-
- public function decideForFork($token)
- {
- return $token->test(array('plural', 'endtrans'));
- }
-
- public function decideForEnd($token)
- {
- return $token->test('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->getNode('expr') instanceof Twig_Node_Expression_Name)
- ) {
- continue;
- }
-
- throw new Twig_Error_Syntax(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno);
- }
- }
-}
+++ /dev/null
-<?php
-
-/*
- * This file is part of Twig.
- *
- * (c) Fabien Potencier
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-require_once dirname(__FILE__).'/TestCase.php';
-
-class Twig_Tests_Node_TransTest extends Twig_Tests_Node_TestCase
-{
- /**
- * @covers Twig_Node_Trans::__construct
- */
- public function testConstructor()
- {
- $count = new Twig_Node_Expression_Constant(12, 0);
- $body = new Twig_Node(array(
- new Twig_Node_Text('Hello', 0),
- ), array(), 0);
- $plural = new Twig_Node(array(
- new Twig_Node_Text('Hey ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Name('name', 0), 0),
- new Twig_Node_Text(', I have ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Name('count', 0), 0),
- new Twig_Node_Text(' apples', 0),
- ), array(), 0);
- $node = new Twig_Node_Trans($body, $plural, $count, 0);
-
- $this->assertEquals($body, $node->getNode('body'));
- $this->assertEquals($count, $node->getNode('count'));
- $this->assertEquals($plural, $node->getNode('plural'));
- }
-
- public function getTests()
- {
- $tests = array();
-
- $body = new Twig_Node_Expression_Name('foo', 0);
- $node = new Twig_Node_Trans($body, null, null, 0);
- $tests[] = array($node, 'echo gettext((isset($context[\'foo\']) ? $context[\'foo\'] : null));');
-
- $body = new Twig_Node_Expression_Constant('Hello', 0);
- $node = new Twig_Node_Trans($body, null, null, 0);
- $tests[] = array($node, 'echo gettext("Hello");');
-
- $body = new Twig_Node(array(
- new Twig_Node_Text('Hello', 0),
- ), array(), 0);
- $node = new Twig_Node_Trans($body, null, null, 0);
- $tests[] = array($node, 'echo gettext("Hello");');
-
- $body = new Twig_Node(array(
- new Twig_Node_Text('J\'ai ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0),
- new Twig_Node_Text(' pommes', 0),
- ), array(), 0);
- $node = new Twig_Node_Trans($body, null, null, 0);
- $tests[] = array($node, 'echo strtr(gettext("J\'ai %foo% pommes"), array("%foo%" => (isset($context[\'foo\']) ? $context[\'foo\'] : null), ));');
-
- $count = new Twig_Node_Expression_Constant(12, 0);
- $body = new Twig_Node(array(
- new Twig_Node_Text('Hey ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Name('name', 0), 0),
- new Twig_Node_Text(', I have one apple', 0),
- ), array(), 0);
- $plural = new Twig_Node(array(
- new Twig_Node_Text('Hey ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Name('name', 0), 0),
- new Twig_Node_Text(', I have ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Name('count', 0), 0),
- new Twig_Node_Text(' apples', 0),
- ), array(), 0);
- $node = new Twig_Node_Trans($body, $plural, $count, 0);
- $tests[] = array($node, 'echo strtr(ngettext("Hey %name%, I have one apple", "Hey %name%, I have %count% apples", abs(12)), array("%name%" => (isset($context[\'name\']) ? $context[\'name\'] : null), "%name%" => (isset($context[\'name\']) ? $context[\'name\'] : null), "%count%" => abs(12), ));');
-
- // with escaper extension set to on
- $body = new Twig_Node(array(
- new Twig_Node_Text('J\'ai ', 0),
- new Twig_Node_Print(new Twig_Node_Expression_Filter(new Twig_Node_Expression_Name('foo', 0), new Twig_Node_Expression_Constant('escape', 0), new Twig_Node(), 0), 0),
- new Twig_Node_Text(' pommes', 0),
- ), array(), 0);
-
- $node = new Twig_Node_Trans($body, null, null, 0);
- $tests[] = array($node, 'echo strtr(gettext("J\'ai %foo% pommes"), array("%foo%" => (isset($context[\'foo\']) ? $context[\'foo\'] : null), ));');
-
- return $tests;
- }
-}