From 2e5514143132e04cb7381c5faf8182f19ceaff3d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 15 Dec 2010 08:28:13 +0100 Subject: [PATCH] moved the i18n extension to the Twig Extensions repository --- CHANGELOG | 1 + doc/02-Twig-for-Template-Designers.markdown | 57 ------------ doc/03-Twig-for-Developers.markdown | 32 ------- doc/06-Recipes.markdown | 58 ------------- lib/Twig/Extension/I18n.php | 44 ---------- lib/Twig/Node/Trans.php | 124 --------------------------- lib/Twig/TokenParser/Trans.php | 80 ----------------- test/Twig/Tests/Node/TransTest.php | 93 -------------------- 8 files changed, 1 insertions(+), 488 deletions(-) delete mode 100644 lib/Twig/Extension/I18n.php delete mode 100644 lib/Twig/Node/Trans.php delete mode 100644 lib/Twig/TokenParser/Trans.php delete mode 100644 test/Twig/Tests/Node/TransTest.php diff --git a/CHANGELOG b/CHANGELOG index 0159a8a..e42511f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ Backward incompatibilities: * 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: diff --git a/doc/02-Twig-for-Template-Designers.markdown b/doc/02-Twig-for-Template-Designers.markdown index 9adde3d..a554f69 100644 --- a/doc/02-Twig-for-Template-Designers.markdown +++ b/doc/02-Twig-for-Template-Designers.markdown @@ -834,63 +834,6 @@ But you can still create an alias by importing from the `_self` variable:

{{ forms.textarea('comment') }}

-### 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 ----------- diff --git a/doc/03-Twig-for-Developers.markdown b/doc/03-Twig-for-Developers.markdown index c2bd26e..4ced847 100644 --- a/doc/03-Twig-for-Developers.markdown +++ b/doc/03-Twig-for-Developers.markdown @@ -243,8 +243,6 @@ Twig comes bundled with the following extensions: * *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). @@ -434,36 +432,6 @@ extension constructor: [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: diff --git a/doc/06-Recipes.markdown b/doc/06-Recipes.markdown index eb16080..05f7d0e 100644 --- a/doc/06-Recipes.markdown +++ b/doc/06-Recipes.markdown @@ -206,61 +206,3 @@ you can use the `set` tag: {% 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) }} diff --git a/lib/Twig/Extension/I18n.php b/lib/Twig/Extension/I18n.php deleted file mode 100644 index 8b29677..0000000 --- a/lib/Twig/Extension/I18n.php +++ /dev/null @@ -1,44 +0,0 @@ - new Twig_Filter_Function('gettext'), - ); - } - - /** - * Returns the name of the extension. - * - * @return string The extension name - */ - public function getName() - { - return 'i18n'; - } -} diff --git a/lib/Twig/Node/Trans.php b/lib/Twig/Node/Trans.php deleted file mode 100644 index 376b9af..0000000 --- a/lib/Twig/Node/Trans.php +++ /dev/null @@ -1,124 +0,0 @@ - - */ -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); - } -} diff --git a/lib/Twig/TokenParser/Trans.php b/lib/Twig/TokenParser/Trans.php deleted file mode 100644 index 2c11d07..0000000 --- a/lib/Twig/TokenParser/Trans.php +++ /dev/null @@ -1,80 +0,0 @@ -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); - } - } -} diff --git a/test/Twig/Tests/Node/TransTest.php b/test/Twig/Tests/Node/TransTest.php deleted file mode 100644 index c1495e4..0000000 --- a/test/Twig/Tests/Node/TransTest.php +++ /dev/null @@ -1,93 +0,0 @@ -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; - } -} -- 1.7.2.5