Skip to content

Commit

Permalink
[Translation][Extractor] Allow extracting an array of files besides e…
Browse files Browse the repository at this point in the history
…xtracting a directory
  • Loading branch information
marcosdsanchez authored and fabpot committed Mar 27, 2015
1 parent 1a4d7d7 commit 9d6596c
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Twig/CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@ CHANGELOG
* added LogoutUrlExtension (provides `logout_url` and `logout_path`)
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
* added AssetExtension (provides the `asset` and `asset_version` functions)
* Added possibility to extract translation messages from a file or files besides extracting from a directory

2.5.0
-----
Expand Down
@@ -0,0 +1 @@
<h1>{{ 'Hi!'|trans }}</h1>
38 changes: 38 additions & 0 deletions src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php
Expand Up @@ -83,4 +83,42 @@ public function testExtractSyntaxError()
$extractor = new TwigExtractor($twig);
$extractor->extract(__DIR__.'/../Fixtures', new MessageCatalogue('en'));
}

/**
* @dataProvider resourceProvider
*/
public function testExtractWithFiles($resource)
{
$loader = new \Twig_Loader_Array(array());
$twig = new \Twig_Environment($loader, array(
'strict_variables' => true,
'debug' => true,
'cache' => false,
'autoescape' => false,
));
$twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface')));

$extractor = new TwigExtractor($twig);
$catalogue = new MessageCatalogue('en');
$extractor->extract($resource, $catalogue);

$this->assertTrue($catalogue->has('Hi!', 'messages'));
$this->assertEquals('Hi!', $catalogue->get('Hi!', 'messages'));
}

/**
* @return array
*/
public function resourceProvider()
{
$directory = __DIR__.'/../Fixtures/extractor/';

return array(
array($directory.'with_translations.html.twig'),
array(array($directory.'with_translations.html.twig')),
array(array(new \SplFileInfo($directory.'with_translations.html.twig'))),
array(new \ArrayObject(array($directory.'with_translations.html.twig'))),
array(new \ArrayObject(array(new \SplFileInfo($directory.'with_translations.html.twig')))),
);
}
}
31 changes: 26 additions & 5 deletions src/Symfony/Bridge/Twig/Translation/TwigExtractor.php
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Bridge\Twig\Translation;

use Symfony\Component\Finder\Finder;
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
use Symfony\Component\Translation\Extractor\ExtractorInterface;
use Symfony\Component\Translation\MessageCatalogue;

Expand All @@ -21,7 +22,7 @@
* @author Michel Salib <michelsalib@hotmail.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class TwigExtractor implements ExtractorInterface
class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface
{
/**
* Default domain for found messages.
Expand Down Expand Up @@ -52,11 +53,9 @@ public function __construct(\Twig_Environment $twig)
/**
* {@inheritdoc}
*/
public function extract($directory, MessageCatalogue $catalogue)
public function extract($resource, MessageCatalogue $catalogue)
{
// load any existing translation files
$finder = new Finder();
$files = $finder->files()->name('*.twig')->sortByName()->in($directory);
$files = $this->extractFiles($resource);
foreach ($files as $file) {
try {
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
Expand Down Expand Up @@ -89,4 +88,26 @@ protected function extractTemplate($template, MessageCatalogue $catalogue)

$visitor->disable();
}

/**
* @param string $file
*
* @return bool
*/
protected function canBeExtracted($file)
{
return $this->isFile($file) && 'twig' === pathinfo($file, PATHINFO_EXTENSION);
}

/**
* @param string|array $directory
*
* @return array
*/
protected function extractFromDirectory($directory)
{
$finder = new Finder();

return $finder->files()->name('*.twig')->in($directory);
}
}
2 changes: 1 addition & 1 deletion src/Symfony/Bridge/Twig/composer.json
Expand Up @@ -28,7 +28,7 @@
"symfony/intl": "~2.3|~3.0.0",
"symfony/routing": "~2.2|~3.0.0",
"symfony/templating": "~2.1|~3.0.0",
"symfony/translation": "~2.2|~3.0.0",
"symfony/translation": "~2.7|~3.0.0",
"symfony/yaml": "~2.0,>=2.0.5|~3.0.0",
"symfony/security": "~2.6|~3.0.0",
"symfony/stopwatch": "~2.2|~3.0.0",
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========

2.7.0
-----

* Added possibility to extract translation messages from a file or files besides extracting from a directory

2.6.0
-----

Expand Down
Expand Up @@ -17,15 +17,20 @@

class PhpExtractorTest extends TestCase
{
public function testExtraction()
/**
* @dataProvider resourcesProvider
*
* @param array|string $resource
*/
public function testExtraction($resource)
{
// Arrange
$extractor = new PhpExtractor();
$extractor->setPrefix('prefix');
$catalogue = new MessageCatalogue('en');

// Act
$extractor->extract(__DIR__.'/../Fixtures/Resources/views/', $catalogue);
$extractor->extract($resource, $catalogue);

$expectedHeredoc = <<<EOF
heredoc key with whitespace and escaped \$\n sequences
Expand All @@ -50,4 +55,28 @@ public function testExtraction()

$this->assertEquals($expectedCatalogue, $actualCatalogue);
}

public function resourcesProvider()
{
$directory = __DIR__.'/../Fixtures/Resources/views/';
$splFiles = array();
foreach (new \DirectoryIterator($directory) as $fileInfo) {
if ($fileInfo->isDot()) {
continue;
}
if ('translation.html.php' === $fileInfo->getBasename()) {
$phpFile = $fileInfo->getPathname();
}
$splFiles[] = $fileInfo->getFileInfo();
}

return array(
array($directory),
array($phpFile),
array(glob($directory.'*')),
array($splFiles),
array(new \ArrayObject(glob($directory.'*'))),
array(new \ArrayObject($splFiles)),
);
}
}
33 changes: 28 additions & 5 deletions src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Translation;

use Symfony\Component\Finder\Finder;
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Extractor\ExtractorInterface;

Expand All @@ -20,7 +21,7 @@
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class PhpExtractor implements ExtractorInterface
class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
{
const MESSAGE_TOKEN = 300;

Expand Down Expand Up @@ -54,11 +55,9 @@ class PhpExtractor implements ExtractorInterface
/**
* {@inheritdoc}
*/
public function extract($directory, MessageCatalogue $catalog)
public function extract($resource, MessageCatalogue $catalog)
{
// load any existing translation files
$finder = new Finder();
$files = $finder->files()->name('*.php')->in($directory);
$files = $this->extractFiles($resource);
foreach ($files as $file) {
$this->parseTokens(token_get_all(file_get_contents($file)), $catalog);
}
Expand Down Expand Up @@ -174,4 +173,28 @@ protected function parseTokens($tokens, MessageCatalogue $catalog)
}
}
}

/**
* @param string $file
*
* @throws \InvalidArgumentException
*
* @return bool
*/
protected function canBeExtracted($file)
{
return $this->isFile($file) && 'php' === pathinfo($file, PATHINFO_EXTENSION);
}

/**
* @param string|array $directory
*
* @return array
*/
protected function extractFromDirectory($directory)
{
$finder = new Finder();

return $finder->files()->name('*.php')->in($directory);
}
}
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/FrameworkBundle/composer.json
Expand Up @@ -29,7 +29,7 @@
"symfony/security-csrf": "~2.6|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0",
"symfony/templating": "~2.1|~3.0.0",
"symfony/translation": "~2.6|~3.0.0",
"symfony/translation": "~2.7|~3.0.0",
"doctrine/annotations": "~1.0"
},
"require-dev": {
Expand Down
@@ -0,0 +1,83 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Translation\Extractor;

/**
* Base class used by classes that extract translation messages from files.
*
* @author Marcos D. Sánchez <marcosdsanchez@gmail.com>
*/
abstract class AbstractFileExtractor
{
/**
* @param string|array $resource files, a file or a directory
*
* @return array
*/
protected function extractFiles($resource)
{
if (is_array($resource) || $resource instanceof \Traversable) {
$files = array();
foreach ($resource as $file) {
if ($this->canBeExtracted($file)) {
$files[] = $this->toSplFileInfo($file);
}
}
} elseif (is_file($resource)) {
$files = $this->canBeExtracted($resource) ? array($this->toSplFileInfo($resource)) : array();
} else {
$files = $this->extractFromDirectory($resource);
}

return $files;
}

/**
* @param string $file
*
* @return \SplFileInfo
*/
private function toSplFileInfo($file)
{
return ($file instanceof \SplFileInfo) ? $file : new \SplFileInfo($file);
}

/**
* @param string $file
*
* @throws \InvalidArgumentException
*
* @return bool
*/
protected function isFile($file)
{
if (!is_file($file)) {
throw new \InvalidArgumentException(sprintf('The "%s" file does not exist.', $file));
}

return true;
}

/**
* @param string $file
*
* @return bool
*/
abstract protected function canBeExtracted($file);

/**
* @param string|array $resource files, a file or a directory
*
* @return array files to be extracted
*/
abstract protected function extractFromDirectory($resource);
}
Expand Up @@ -14,20 +14,20 @@
use Symfony\Component\Translation\MessageCatalogue;

/**
* Extracts translation messages from a template directory to the catalogue.
* Extracts translation messages from a directory or files to the catalogue.
* New found messages are injected to the catalogue using the prefix.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
interface ExtractorInterface
{
/**
* Extracts translation messages from a template directory to the catalogue.
* Extracts translation messages from files, a file or a directory to the catalogue.
*
* @param string $directory The path to look into
* @param string|array $resource files, a file or a directory
* @param MessageCatalogue $catalogue The catalogue
*/
public function extract($directory, MessageCatalogue $catalogue);
public function extract($resource, MessageCatalogue $catalogue);

/**
* Sets the prefix that should be used for new found messages.
Expand Down

0 comments on commit 9d6596c

Please sign in to comment.