8000 feature #14002 [Translation][Extractor] Allow extracting an array of … · symfony/symfony@b910e06 · GitHub
[go: up one dir, main page]

Skip to content

Commit b910e06

Browse files
committed
feature #14002 [Translation][Extractor] Allow extracting an array of files besides extracting a directory (marcosdsanchez)
This PR was squashed before being merged into the 2.7 branch (closes #14002). Discussion ---------- [Translation][Extractor] Allow extracting an array of files besides extracting a directory | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | N/A | License | MIT | Doc PR | N/A Give ability to extractors to extract from an array of files a file, or a Traversable besides a directory. The following commit adds the new feature to the following extractors: PhpExtractor and TwigExtractor. It also corrects the interface documentation to show the new options allowed as a parameter. I found this change useful as I've got a custom translation:update command that instead of extracting from $rootPath. '/Resources/views/' it extracts from the files that git is showing as modified. The command usually runs much faster than the default as it only parses the needed files. Commits ------- 9d6596c [Translation][Extractor] Allow extracting an array of files besides extracting a directory
2 parents 350f30b + 9d6596c commit b910e06

File tree

11 files changed

+219
-18
lines changed

11 files changed

+219
-18
lines changed

src/Symfony/Bridge/Twig/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* added LogoutUrlExtension (provides `logout_url` and `logout_path`)
88
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
99
* added AssetExtension (provides the `asset` and `asset_version` functions)
10+
* Added possibility to extract translation messages from a file or files besides extracting from a directory
1011

1112
2.5.0
1213
-----
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<h1>{{ 'Hi!'|trans }}</h1>

src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,42 @@ public function testExtractSyntaxError()
8383
$extractor = new TwigExtractor($twig);
8484
$extractor->extract(__DIR__.'/../Fixtures', new MessageCatalogue('en'));
8585
}
86+
87+
/**
88+
* @dataProvider resourceProvider
89+
*/
90+
public function testExtractWithFiles($resource)
91+
{
92+
$loader = new \Twig_Loader_Array(array());
93+
$twig = new \Twig_Environment($loader, array(
94+
'strict_variables' => true,
95+
'debug' => true,
96+
'cache' => false,
97+
'autoescape' => false,
98+
));
99+
$twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface')));
100+
101+
$extractor = new TwigExtractor($twig);
102+
$catalogue = new MessageCatalogue('en');
103+
$extractor->extract($resource, $catalogue);
104+
105+
$this->assertTrue($catalogue->has('Hi!', 'messages'));
106+
$this->assertEquals('Hi!', $catalogue->get('Hi!', 'messages'));
107+
}
108+
109+
/**
110+
* @return array
111+
*/
112+
public function resourceProvider()
113+
{
114+
$directory = __DIR__.'/../Fixtures/extractor/';
115+
116+
return array(
117+
array($directory.'with_translations.html.twig'),
118+
array(array($directory.'with_translations.html.twig')),
119+
array(array(new \SplFileInfo($directory.'with_translations.html.twig'))),
120+
array(new \ArrayObject(array($directory.'with_translations.html.twig'))),
121+
array(new \ArrayObject(array(new \SplFileInfo($directory.'with_translations.html.twig')))),
122+
);
123+
}
86124
}

src/Symfony/Bridge/Twig/Translation/TwigExtractor.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bridge\Twig\Translation;
1313

1414
use Symfony\Component\Finder\Finder;
15+
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
1516
use Symfony\Component\Translation\Extractor\ExtractorInterface;
1617
use Symfony\Component\Translation\MessageCatalogue;
1718

@@ -21,7 +22,7 @@
2122
* @author Michel Salib <michelsalib@hotmail.com>
2223
* @author Fabien Potencier <fabien@symfony.com>
2324
*/
24-
class TwigExtractor implements ExtractorInterface
25+
class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface
2526
{
2627
/**
2728
* Default domain for found messages.
@@ -52,11 +53,9 @@ public function __construct(\Twig_Environment $twig)
5253
/**
5354
* {@inheritdoc}
5455
*/
55-
public function extract($directory, MessageCatalogue $catalogue)
56+
public function extract($resource, MessageCatalogue $catalogue)
5657
{
57-
// load any existing translation files
58-
$finder = new Finder();
59-
$files = $finder->files()->name('*.twig')->sortByName()->in($directory);
58+
$files = $this->extractFiles($resource);
6059
foreach ($files as $file) {
6160
try {
6261
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
@@ -89,4 +88,26 @@ protected function extractTemplate($template, MessageCatalogue $catalogue)
8988

9089
$visitor->disable();
9190
}
91+
92+
/**
93+
* @param string $file
94+
*
95+
* @return bool
96+
*/
97+
protected function canBeExtracted($file)
98+
{
99+
return $this->isFile($file) && 'twig' === pathinfo($file, PATHINFO_EXTENSION);
100+
}
101+
102+
/**
103+
* @param string|array $directory
104+
*
105+
* @return array
106+
*/
107+
protected function extractFromDirectory($directory)
108+
{
109+
$finder = new Finder();
110+
111+
return $finder->files()->name('*.twig')->in($directory);
112+
}
92113
}

src/Symfony/Bridge/Twig/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"symfony/intl": "~2.3|~3.0.0",
2929
"symfony/routing": "~2.2|~3.0.0",
3030
"symfony/templating": "~2.1|~3.0.0",
31-
"symfony/translation": "~2.2|~3.0.0",
31+
"symfony/translation": "~2.7|~3.0.0",
3232
"symfony/yaml": "~2.0,>=2.0.5|~3.0.0",
3333
"symfony/security": "~2.6|~3.0.0",
3434
"symfony/stopwatch": "~2.2|~3.0.0",

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.7.0
5+
-----
6+
7+
* Added possibility to extract translation messages from a file or files besides extracting from a directory
8+
49
2.6.0
510
-----
611

src/Symfony/Bundle/FrameworkBundle/Tests/Translation/PhpExtractorTest.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@
1717

1818
class PhpExtractorTest extends TestCase
1919
{
20-
public function testExtraction()
20+
/**
21+
* @dataProvider resourcesProvider
22+
*
23+
* @param array|string $resource
24+
*/
25+
public function testExtraction($resource)
2126
{
2227
// Arrange
2328
$extractor = new PhpExtractor();
2429
$extractor->setPrefix('prefix');
2530
$catalogue = new MessageCatalogue('en');
2631

2732
// Act
28-
$extractor->extract(__DIR__.'/../Fixtures/Resources/views/', $catalogue);
33+
$extractor->extract($resource, $catalogue);
2934

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

5156
$this->assertEquals($expectedCatalogue, $actualCatalogue);
5257
}
58+
59+
public function resourcesProvider()
60+
{
61+
$directory = __DIR__.'/../Fixtures/Resources/views/';
62+
$splFiles = array();
63+
foreach (new \DirectoryIterator($directory) as $fileInfo) {
64+
if ($fileInfo->isDot()) {
65+
continue;
66+
}
67+
if ('translation.html.php' === $fileInfo->getBasename()) {
68+
$phpFile = $fileInfo->getPathname();
69+
}
70+
$splFiles[] = $fileInfo->getFileInfo();
71+
}
72+
73+
return array(
74+
array($directory),
75+
array($phpFile),
76+
array(glob($directory.'*')),
77+
array($splFiles),
78+
array(new \ArrayObject(glob($directory.'*'))),
79+
array(new \ArrayObject($splFiles)),
80+
);
81+
}
5382
}

src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Translation;
1313

1414
use Symfony\Component\Finder\Finder;
15+
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
1516
use Symfony\Component\Translation\MessageCatalogue;
1617
use Symfony\Component\Translation\Extractor\ExtractorInterface;
1718

@@ -20,7 +21,7 @@
2021
*
2122
* @author Michel Salib <michelsalib@hotmail.com>
2223
*/
23-
class PhpExtractor implements ExtractorInterface
24+
class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
2425
{
2526
const MESSAGE_TOKEN = 300;
2627

@@ -54,11 +55,9 @@ class PhpExtractor implements ExtractorInterface
5455
/**
5556
* {@inheritdoc}
5657
*/
57-
public function extract($directory, MessageCatalogue $catalog)
58+
public function extract($resource, MessageCatalogue $catalog)
5859
{
59-
// load any existing translation files
60-
$finder = new Finder();
61-
$files = $finder->files()->name('*.php')->in($directory);
60+
$files = $this->extractFiles($resource);
6261
foreach ($files as $file) {
6362
$this->parseTokens(token_get_all(file_get_contents($file)), $catalog);
6463
}
@@ -174,4 +173,28 @@ protected function parseTokens($tokens, MessageCatalogue $catalog)
174173
}
175174
}
176175
}
176+
177+
/**
178+
* @param string $file
179+
*
180+
* @throws \InvalidArgumentException
181+
*
182+
* @return bool
183+
*/
184+
protected function canBeExtracted($file)
185+
{
186+
return $this->isFile($file) && 'php' === pathinfo($file, PATHINFO_EXTENSION);
187+
}
188+
189+
/**
190+
* @param string|array $directory
191+
*
192+
* @return array
193+
*/
194+
protected function extractFromDirectory($directory)
195+
{
196+
$finder = new Finder();
197+
198+
return $finder->files()->name('*.php')->in($directory);
199+
}
177200
}

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"symfony/security-csrf": "~2.6|~3.0.0",
3030
"symfony/stopwatch": "~2.3|~3.0.0",
3131
"symfony/templating": "~2.1|~3.0.0",
32-
"symfony/translation": "~2.6|~3.0.0",
32+
"symfony/translation": "~2.7|~3.0.0",
3333
"doctrine/annotations": "~1.0"
3434
},
3535
"require-dev": {
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Translation\Extractor;
13+
14+
/**
15+
* Base class used by classes that extract translation messages from files.
16+
*
17+
* @author Marcos D. Sánchez <marcosdsanchez@gmail.com>
18+
*/
19+
abstract class AbstractFileExtractor
20+
{
21+
/**
22+
* @param string|array $resource files, a file or a directory
23+
*
24+
* @return array
25+
*/
26+
protected function extractFiles($resource)
27+
{
28+
if (is_array($resource) || $resource instanceof \Traversable) {
29+
$files = array();
30+
foreach ($resource as $file) {
31+
if ($this->canBeExtracted($file)) {
32+
$files[] = $this->toSplFileInfo($file);
33+
}
34+
}
35+
} elseif (is_file($resource)) {
36+
$files = $this->canBeExtracted($resource) ? array($this->toSplFileInfo($resource)) : array();
37+
} else {
38+
$files = $this->extractFromDirectory($resource);
39+
}
40+
41+
return $files;
42+
}
43+
44+
/**
45+
* @param string $file
46+
*
47+
* @return \SplFileInfo
48+
*/
49+
private function toSplFileInfo($file)
50+
{
51+
return ($file instanceof \SplFileInfo) ? $file : new \SplFileInfo($file);
52+
}
53+
54+
/**
55+
* @param string $file
56+
*
57+
* @throws \InvalidArgumentException
58+
*
59+
* @return bool
60+
*/
61+
protected function isFile($file)
62+
{
63+
if (!is_file($file)) {
64+
throw new \InvalidArgumentException(sprintf('The "%s" file does not exist.', $file));
65+
}
66+
67+
return true;
68+
}
69+
70+
/**
71+
* @param string $file
72+
*
73+
* @return bool
74+
*/
75+
abstract protected function canBeExtracted($file);
76+
77+
/**
78+
* @param string|array $resource files, a file or a directory
79+
*
80+
* @return array files to be extracted
81+
*/
82+
abstract protected function extractFromDirectory($resource);
83+
}

src/Symfony/Component/Translation/Extractor/ExtractorInterface.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@
1414
use Symfony\Component\Translation\MessageCatalogue;
1515

1616
/**
17-
* Extracts translation messages from a template directory to the catalogue.
17+
* Extracts translation messages from a directory or files to the catalogue.
1818
* New found messages are injected to the catalogue using the prefix.
1919
*
2020
* @author Michel Salib <michelsalib@hotmail.com>
2121
*/
2222
interface ExtractorInterface
2323
{
2424
/**
25-
* Extracts translation messages from a template directory to the catalogue.
25+
* Extracts translation messages from files, a file or a directory to the catalogue.
2626
*
27-
* @param string $directory The path to look into
27+
* @param string|array $resource files, a file or a directory
2828
* @param MessageCatalogue $catalogue The catalogue
2929
*/
30-
public function extract($directory, MessageCatalogue $catalogue);
30+
public function extract($resource, MessageCatalogue $catalogue);
3131

3232
/**
3333
* Sets the prefix that should be used for new found messages.

0 commit comments

Comments
 (0)
0