10000 feature #13942 [2.7][Translation] generate translation cache at warmu… · symfony/symfony@ce3b8fd · GitHub
[go: up one dir, main page]

Skip to content

Commit ce3b8fd

Browse files
committed
feature #13942 [2.7][Translation] generate translation cache at warmup (xavierleune)
This PR was merged into the 2.7 branch. Discussion ---------- [2.7][Translation] generate translation cache at warmup | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #13919 | License | MIT | Doc PR | NA This PR uses the parameters "locale" and "fallback_locales" to generate the catalogues at warmup, avoiding the creation of files at runtime. Commits ------- 94d3876 FIX #13919 added TranslationsCacheWarmer to generate catalogues at warmup
2 parents 40a350b + 94d3876 commit ce3b8fd

File tree

9 files changed

+134
-29
lines changed

9 files changed

+134
-29
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* Added possibility to extract translation messages from a file or files besides extracting from a directory
8+
* Added `TranslationsCacheWarmer` to create catalogues at warmup
89

910
2.6.0
1011
-----
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Bundle\FrameworkBundle\CacheWarmer;
13+
14+
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
15+
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
16+
use Symfony\Component\Translation\TranslatorInterface;
17+
18+
/**
19+
* Generates the catalogues for translations.
20+
*
21+
* @author Xavier Leune <xavier.leune@gmail.com>
22+
*/
23+
class TranslationsCacheWarmer implements CacheWarmerInterface
24+
{
25+
private $translator;
26+
27+
public function __construct(TranslatorInterface $translator)
28+
{
29+
$this->translator = $translator;
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function warmUp($cacheDir)
36+
{
37+
if ($this->translator instanceof WarmableInterface) {
38+
$this->translator->warmUp($cacheDir);
39+
}
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function isOptional()
46+
{
47+
return true;
48+
}
49+
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/LoggingTranslatorPass.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\ContainerBuilder;
1515
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16+
use Symfony\Component\DependencyInjection\Reference;
1617

1718
/**
1819
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
@@ -38,6 +39,7 @@ public function process(ContainerBuilder $container)
3839
$refClass = new \ReflectionClass($class);
3940
if ($refClass->implementsInterface('Symfony\Component\Translation\TranslatorInterface') && $refClass->implementsInterface('Symfony\Component\Translation\TranslatorBagInterface')) {
4041
$container->getDefinition('translator.logging')->setDecoratedService('translator');
42+
$container->getDefinition('translation.warmer')->replaceArgument(0, new Reference('translator.logging.inner'));
4143
}
4244
}
4345
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,11 +705,22 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
705705
->in($dirs)
706706
;
707707

708+
$locales = array();
708709
foreach ($finder as $file) {
709-
$files[] = (string) $file;
710+
list($domain, $locale, $format) = explode('.', $file->getBasename(), 3);
711+
if (!isset($files[$locale])) {
712+
$files[$locale] = array();
713+
}
714+
715+
$files[$locale][] = (string) $file;
710716
}
711717

712-
$translator->replaceArgument(4, $files);
718+
$options = array_merge(
719+
$translator->getArgument(3),
720+
array('resource_files' => $files)
721+
);
722+
723+
$translator->replaceArgument(3, $options);
713724
}
714725
}
715726

src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,5 +152,10 @@
152152
<service id="translation.extractor" class="%translation.extractor.class%"/>
153153

154154
<service id="translation.writer" class="%translation.writer.class%"/>
155+
156+
<service id="translation.warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\TranslationsCacheWarmer" public="false">
157+
<argument type="service" id="translator" />
158+
<tag name="kernel.cache_warmer" />
159+
</service>
155160
</services>
156161
</container>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LoggingTranslatorPassTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function testProcess()
3535
->method('getAlias')
3636
->will($this->returnValue('translation.default'));
3737

38-
$container->expects($this->exactly(2))
38+
$container->expects($this->exactly(3))
3939
->method('getDefinition')
4040
->will($this->returnValue($definition));
4141

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ public function testTranslator()
223223
$container = $this->createContainerFromFile('full');
224224
$this->assertTrue($container->hasDefinition('translator.default'), '->registerTranslatorConfiguration() loads translation.xml');
225225
$this->assertEquals('translator.default', (string) $container->getAlias('translator'), '->registerTranslatorConfiguration() redefines translator service from identity to real translator');
226-
$resources = $container->getDefinition('translator.default')->getArgument(4);
226+
$options = $container->getDefinition('translator.default')->getArgument(3);
227227

228-
$files = array_map(function ($resource) { return realpath($resource); }, $resources);
228+
$files = array_map(function ($resource) { return realpath($resource); }, $options['resource_files']['en']);
229229
$ref = new \ReflectionClass('Symfony\Component\Validator\Validation');
230230
$this->assertContains(
231231
strtr(dirname($ref->getFileName()).'/Resources/translations/validators.en.xlf', '/', DIRECTORY_SEPARATOR),

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

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function testTransWithCaching()
9595
public function testTransWithCachingWithInvalidLocale()
9696
{
9797
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
98-
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), array(), 'loader', '\Symfony\Bundle\FrameworkBundle\Tests\Translation\TranslatorWithInvalidLocale');
98+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), 'loader', '\Symfony\Bundle\FrameworkBundle\Tests\Translation\TranslatorWithInvalidLocale');
9999
$translator->setLocale('invalid locale');
100100

101101
$this->setExpectedException('\InvalidArgumentException');
@@ -106,23 +106,25 @@ public function testLoadRessourcesWithCaching()
106106
{
107107
$loader = new \Symfony\Component\Translation\Loader\YamlFileLoader();
108108
$resourceFiles = array(
109-
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
109+
'fr' => array(
110+
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
111+
),
110112
);
111113

112114
// prime the cache
113-
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), $resourceFiles, 'yml');
115+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml');
114116
$translator->setLocale('fr');
115117

116118
$this->assertEquals('répertoire', $translator->trans('folder'));
117119

118120
// do it another time as the cache is primed now
119-
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), array(), 'yml');
121+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), 'yml');
120122
$translator->setLocale('fr');
121123

122124
$this->assertEquals('répertoire', $translator->trans('folder'));
123125

124126
// refresh cache when resources is changed in debug mode.
125-
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'debug' => true), array(), 'yml');
127+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'debug' => true), 'yml');
126128
$translator->setLocale('fr');
127129

128130
$this->assertEquals('folder', $translator->trans('folder'));
@@ -132,10 +134,12 @@ public function testLoadRessourcesWithoutCaching()
132134
{
133135
$loader = new \Symfony\Component\Translation\Loader\YamlFileLoader();
134136
$resourceFiles = array(
135-
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
137+
'fr' => array(
138+
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
139+
),
136140
);
137141

138-
$translator = $this->getTranslator($loader, array(), $resourceFiles, 'yml');
142+
$translator = $this->getTranslator($loader, array('resource_files' => $resourceFiles), 'yml');
139143
$translator->setLocale('fr');
140144

141145
$this->assertEquals('répertoire', $translator->trans('folder'));
@@ -221,14 +225,13 @@ protected function getContainer($loader)
221225
return $container;
222226
}
223227

224-
public function getTranslator($loader, $options = array(), $resources = array(), $loaderFomat = 'loader', $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator')
228+
public function getTranslator($loader, $options = array(), $loaderFomat = 'loader', $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator')
225229
{
226230
$translator = new $translatorClass(
227231
$this->getContainer($loader),
228232
new MessageSelector(),
229233
array($loaderFomat => array($loaderFomat)),
230-
$options,
231-
$resources
234+
$options
232235
);
233236

234237
if ('loader' === $loaderFomat) {
@@ -243,6 +246,22 @@ public function getTranslator($loader, $options = array(), $resources = array(),
243246

244247
return $translator;
245248
}
249+
250+
public function testWarmup()
251+
{
252+
$loader = new \Symfony\Component\Translation\Loader\YamlFileLoader();
253+
$resourceFiles = array(
254+
'fr' => array(
255+
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
256+
),
257+
);
258+
259+
// prime the cache
260+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml');
261+
$this->assertFalse(file_exists($this->tmpDir.'/catalogue.fr.php'));
262+
$translator->warmup($this->tmpDir);
263+
$this->assertTrue(file_exists($this->tmpDir.'/catalogue.fr.php'));
264+
}
246265
}
247266

248267
class TranslatorWithInvalidLocale extends Translator

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

Lines changed: 32 additions & 14 deletions
55
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Translation;
1313

14+
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
1415
use Symfony\Component\Translation\Translator as BaseTranslator;
1516
use Symfony\Component\Translation\MessageSelector;
1617
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -20,52 +21,67 @@
2021
*
2122
* @author Fabien Potencier <fabien@symfony.com>
2223
*/
23-
class Translator extends BaseTranslator
24+
class Translator extends BaseTranslator implements WarmableInterface
2425
{
2526
protected $container;
2627
protected $loaderIds;
27-
protected $resourceFiles;
2828

2929
protected $options = array(
3030
'cache_dir' => null,
3131
'debug' => false,
32+
'resource_files' => array(),
3233
);
3334

35+
/**
36+
* @var array
37+
*/
38+
private $resourceLocales;
39+
3440
/**
3541
* Constructor.
3642
*
3743
* Available options:
3844
*
3945
* * cache_dir: The cache directory (or null to disable caching)
4046
* * debug: Whether to enable debugging or not (false by default)
47+
* * resource_files: List of translation resources available grouped by locale.
4148
*
42-
* @param ContainerInterface $container A ContainerInterface instance
43-
* @param MessageSelector $selector The message selector for pluralization
44-
* @param array $loaderIds An array of loader Ids
45-
* @param array $options An array of options
46-
* @param array $resourceFiles An array of resource directories
49+
* @param ContainerInterface $container A ContainerInterface instance
50+
* @param MessageSelector $selector The message selector for pluralization
51+
* @param array $loaderIds An array of loader Ids
52+
* @param array $options An array of options
4753
*
4854
* @throws \InvalidArgumentException
4955
*/
50-
public function __construct(ContainerInterface $container, MessageSelector $selector, $loaderIds = array(), array $options = array(), $resourceFiles = array())
56+
public function __construct(ContainerInterface $container, MessageSelector $selector, $loaderIds = array(), array $options = array())
5157
{
5258
$this->container = $container;
5359
$this->loaderIds = $loaderIds;
54-
$this->resourceFiles = $resourceFiles;
60

5661
// check option names
5762
if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
5863
throw new \InvalidArgumentException(sprintf('The Translator does not support the following options: \'%s\'.', implode('\', \'', $diff)));
5964
}
6065

6166
$this->options = array_merge($this->options, $options);
67+
$this->resourceLocales = array_keys($this->options['resource_files']);
6268
if (null !== $this->options['cache_dir'] && $this->options['debug']) {
6369
$this->loadResources();
6470
}
6571

6672
parent::__construct(null, $selector, $this->options['cache_dir'], $this->options['debug']);
6773
}
6874

75+
/**
76+
* {@inheritdoc}
77+
*/
78+
public function warmUp($cacheDir)
79+
{
80+
foreach ($this->resourceLocales as $locale) {
81+
$this->loadCatalogue($locale);
82+
}
83+
}
84+
6985
/**
7086
* {@inheritdoc}
7187
*/
@@ -87,11 +103,13 @@ protected function initialize()
87103

88104
private function loadResources()
89105
{
90-
foreach ($this->resourceFiles as $key => $file) {
91-
// filename is domain.locale.format
92-
list($domain, $locale, $format) = explode('.', basename($file), 3);
93-
$this->addResource($format, $file, $locale, $domain);
94-
unset($this->resourceFiles[$key]);
106+
foreach ($this->options['resource_files'] as $locale => $files) {
107+
foreach ($files as $key => $file) {
108+
// filename is domain.locale.format
109+
list($domain, $locale, $format) = explode('.', basename($file), 3);
110+
$this->addResource($format, $file, $locale, $domain);
111+
unset($this->options['resource_files'][$locale][$key]);
112+
}
95113
}
96114
}
97115
}

0 commit comments

Comments
 (0)
0