twig implementation

This commit is contained in:
Nicolas Lœuillet
2013-08-03 19:26:54 +02:00
parent 2b840e0cfb
commit 4f5b44bd3b
1418 changed files with 108207 additions and 1586 deletions

View File

@ -0,0 +1,3 @@
vendor
phpunit.xml
composer.lock

View File

@ -0,0 +1,10 @@
language: php
before_script:
- curl -s http://getcomposer.org/installer | php
- php composer.phar install --dev
php:
- 5.3
- 5.4

View File

@ -0,0 +1,19 @@
Copyright (c) Саша Стаменковић <umpirsky@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,49 @@
Twig Gettext Extractor [![Build Status](https://secure.travis-ci.org/umpirsky/Twig-Gettext-Extractor.png?branch=master)](http://travis-ci.org/umpirsky/Twig-Gettext-Extractor)
======================
The Twig Gettext Extractor is [Poedit](http://www.poedit.net/download.php)
friendly tool which extracts translations from twig templates.
## Installation
The recommended way to install Twig Gettext Extractor is through
[composer](http://getcomposer.org).
```json
{
"require": {
"umpirsky/twig-gettext-extractor": "1.1.*"
}
}
```
## Setup
By default, Poedit does not have the ability to parse Twig templates.
This can be resolved by adding an additional parser (Edit > Preferences > Parsers)
with the following options:
- Language: `Twig`
- List of extensions: `*.twig`
- Invocation:
- Parser command: `<project>/vendor/bin/twig-gettext-extractor --sort-output --force-po -o %o %C %K -L PHP --files %F`
- An item in keyword list: `-k%k`
- An item in input file list: `%f`
- Source code charset: `--from-code=%c`
<img src="http://i.imgur.com/f9px2.png" />
Now you can update your catalog and Poedit will synchronize it with your twig
templates.
## Tests
To run the test suite, you need [composer](http://getcomposer.org) and
[PHPUnit](https://github.com/sebastianbergmann/phpunit).
$ composer install --dev
$ phpunit
## License
Twig Gettext Extractor is licensed under the MIT license.

View File

@ -0,0 +1,95 @@
<?php
/**
* This file is part of the Twig Gettext utility.
*
* (c) Саша Стаменковић <umpirsky@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Gettext;
use Symfony\Component\Filesystem\Filesystem;
/**
* Extracts translations from twig templates.
*
* @author Саша Стаменковић <umpirsky@gmail.com>
*/
class Extractor
{
/**
* @var \Twig_Environment
*/
protected $environment;
/**
* Template cached file names.
*
* @var string[]
*/
protected $templates;
/**
* Gettext parameters.
*
* @var string[]
*/
protected $parameters;
public function __construct(\Twig_Environment $environment)
{
$this->environment = $environment;
$this->reset();
}
protected function reset()
{
$this->templates = array();
$this->parameters = array();
}
public function addTemplate($path)
{
$this->environment->loadTemplate($path);
$this->templates[] = $this->environment->getCacheFilename($path);
}
public function addGettextParameter($parameter)
{
$this->parameters[] = $parameter;
}
public function setGettextParameters(array $parameters)
{
$this->parameters = $parameters;
}
public function extract()
{
$command = 'xgettext';
$command .= ' '.join(' ', $this->parameters);
$command .= ' '.join(' ', $this->templates);
$error = 0;
$output = system($command, $error);
if (0 !== $error) {
throw new \RuntimeException(sprintf(
'Gettext command "%s" failed with error code %s and output: %s',
$command,
$error,
$output
));
}
$this->reset();
}
public function __destruct()
{
$filesystem = new Filesystem();
$filesystem->remove($this->environment->getCache());
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* This file is part of the Twig Gettext utility.
*
* (c) Саша Стаменковић <umpirsky@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Gettext\Loader;
/**
* Loads template from the filesystem.
*
* @author Саша Стаменковић <umpirsky@gmail.com>
*/
class Filesystem extends \Twig_Loader_Filesystem
{
/**
* Hacked find template to allow loading templates by absolute path.
*
* @param string $name template name or absolute path
*/
protected function findTemplate($name)
{
// normalize name
$name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
$this->validateName($name);
$namespace = '__main__';
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new \InvalidArgumentException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$name = substr($name, $pos + 1);
}
if (!isset($this->paths[$namespace])) {
throw new \Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
}
if (is_file($name)) {
return $this->cache[$name] = $name;
}
return __DIR__.'/../Test/Fixtures/twig/empty.twig';
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* This file is part of the Twig Gettext utility.
*
* (c) Саша Стаменковић <umpirsky@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Gettext\Routing\Generator;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RequestContext;
/**
* Dummy url generator.
*
* @author Саша Стаменковић <umpirsky@gmail.com>
*/
class UrlGenerator implements UrlGeneratorInterface
{
protected $context;
public function generate($name, $parameters = array(), $absolute = false)
{
}
public function getContext()
{
return $this->context;
}
public function setContext(RequestContext $context)
{
$this->context = $context;
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* This file is part of the Twig Gettext utility.
*
* (c) Саша Стаменковић <umpirsky@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Gettext\Test;
use Twig\Gettext\Extractor;
use Twig\Gettext\Loader\Filesystem;
use Symfony\Component\Translation\Loader\PoFileLoader;
/**
* @author Саша Стаменковић <umpirsky@gmail.com>
*/
class ExtractorTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \Twig_Environment
*/
protected $twig;
/**
* @var PoFileLoader
*/
protected $loader;
protected function setUp()
{
$this->twig = new \Twig_Environment(new Filesystem('/'), array(
'cache' => '/tmp/cache/'.uniqid(),
'auto_reload' => true
));
$this->twig->addExtension(new \Twig_Extensions_Extension_I18n());
$this->loader = new PoFileLoader();
}
/**
* @dataProvider testExtractDataProvider
*/
public function testExtract(array $templates, array $parameters, array $messages)
{
$extractor = new Extractor($this->twig);
foreach ($templates as $template) {
$extractor->addTemplate($template);
}
foreach ($parameters as $parameter) {
$extractor->addGettextParameter($parameter);
}
$extractor->extract();
$catalog = $this->loader->load($this->getPotFile(), null);
foreach ($messages as $message) {
$this->assertTrue(
$catalog->has($message),
sprintf('Message "%s" not found in catalog.', $message)
);
}
}
public function testExtractDataProvider()
{
return array(
array(
array(
__DIR__.'/Fixtures/twig/singular.twig',
__DIR__.'/Fixtures/twig/plural.twig',
),
$this->getGettextParameters(),
array(
'Hello %name%!',
'Hello World!',
'Hey %name%, I have one apple.',
'Hey %name%, I have %count% apples.',
),
),
);
}
public function testExtractNoTranslations()
{
$extractor = new Extractor($this->twig);
$extractor->addTemplate(__DIR__.'/Fixtures/twig/empty.twig');
$extractor->setGettextParameters($this->getGettextParameters());
$extractor->extract();
$catalog = $this->loader->load($this->getPotFile(), null);
$this->assertEmpty($catalog->all('messages'));
}
private function getPotFile()
{
return __DIR__.'/Fixtures/messages.pot';
}
private function getGettextParameters()
{
return array(
'--force-po',
'-o',
$this->getPotFile(),
);
}
protected function tearDown()
{
if (file_exists($this->getPotFile())) {
unlink($this->getPotFile());
}
}
}

View File

@ -0,0 +1 @@
Nothing to translate here.

View File

@ -0,0 +1,5 @@
{% trans %}
Hey {{ name }}, I have one apple.
{% plural apple_count %}
Hey {{ name }}, I have {{ count }} apples.
{% endtrans %}

View File

@ -0,0 +1,9 @@
{% trans "Hello World!" %}
{% trans %}
Hello World!
{% endtrans %}
{% trans %}
Hello {{ name }}!
{% endtrans %}

View File

@ -0,0 +1,30 @@
{
"name": "umpirsky/twig-gettext-extractor",
"type": "application",
"description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates.",
"license": "MIT",
"authors": [
{
"name": "Саша Стаменковић",
"email": "umpirsky@gmail.com"
}
],
"require": {
"php": ">=5.3.3",
"twig/twig": ">=1.2.0,<2.0-dev",
"twig/extensions": "1.0.*",
"symfony/twig-bridge": ">=2.0,<3.0",
"symfony/routing": ">=2.0,<3.0",
"symfony/filesystem": ">=2.0,<3.0",
"symfony/translation": ">=2.0,<3.0",
"symfony/form": ">=2.0,<3.0"
},
"require-dev": {
"symfony/config": "2.1.*"
},
"minimum-stability": "dev",
"autoload": {
"psr-0": { "Twig\\Gettext": "." }
},
"bin": ["twig-gettext-extractor"]
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
bootstrap="./vendor/autoload.php"
>
<testsuites>
<testsuite name="Twig Gettext Extractor Test Suite">
<directory>./Twig/Gettext/Test/</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@ -0,0 +1,58 @@
#!/usr/bin/env php
<?php
/**
* This file is part of the Twig Gettext utility.
*
* (c) Саша Стаменковић <umpirsky@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Extracts translations from twig templates.
*
* @author Саша Стаменковић <umpirsky@gmail.com>
*/
if (file_exists($a = __DIR__.'/../../autoload.php')) {
require_once $a;
} else {
require_once __DIR__.'/vendor/autoload.php';
}
$twig = new Twig_Environment(new Twig\Gettext\Loader\Filesystem('/'), array(
'cache' => '/tmp/cache/'.uniqid(),
'auto_reload' => true
));
$twig->addExtension(new Symfony\Bridge\Twig\Extension\TranslationExtension(
new Symfony\Component\Translation\Translator(null)
));
$twig->addExtension(new Twig_Extensions_Extension_I18n());
$twig->addExtension(new Symfony\Bridge\Twig\Extension\RoutingExtension(
new Twig\Gettext\Routing\Generator\UrlGenerator()
));
$twig->addExtension(new Symfony\Bridge\Twig\Extension\FormExtension(
new Symfony\Bridge\Twig\Form\TwigRenderer(
new Symfony\Bridge\Twig\Form\TwigRendererEngine()
)
));
// You can add more extensions here.
array_shift($_SERVER['argv']);
$addTemplate = false;
$extractor = new Twig\Gettext\Extractor($twig);
foreach ($_SERVER['argv'] as $arg) {
if ('--files' == $arg) {
$addTemplate = true;
} else if ($addTemplate) {
$extractor->addTemplate(getcwd().DIRECTORY_SEPARATOR.$arg);
} else {
$extractor->addGettextParameter($arg);
}
}
$extractor->extract();