8000 feature #11373 [FrameworkBundle][Translation] moved cache to Translat… · symfony/symfony@784df79 · GitHub
[go: up one dir, main page]

Skip to content

Commit 784df79

Browse files
committed
feature #11373 [FrameworkBundle][Translation] moved cache to Translation component (new PR) (aitboudad, OwlyCode)
This PR was merged into the 2.6-dev branch. Discussion ---------- [FrameworkBundle][Translation] moved cache to Translation component (new PR) | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #10628 | License | MIT | Doc PR | This supersedes the PR #11197 (while including the changes made by it). I removed the `$options` argument for `Symfony\Component\Translation\Translator` and replaced it by a public method `enableCache($cacheDir, $debug = false)`. It aims to solve what @fabpot said about passing an array of options in #11197 <s>while not modifying the existing constructors</s>. Commits ------- 30fed6a [Translation][Cache] Removed the options from the arguments of Translator 8b2d9a8 [FrameworkBundle][Translation] moved cache to Translation component
2 parents eb1e3c3 + 30fed6a commit 784df79

File tree

4 files changed

+344
-69
lines changed

4 files changed

+344
-69
lines changed

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

Lines changed: 6 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Symfony\Component\Translation\Translator as BaseTranslator;
1515
use Symfony\Component\Translation\MessageSelector;
1616
use Symfony\Component\DependencyInjection\ContainerInterface;
17-
use Symfony\Component\Config\ConfigCache;
1817

1918
/**
2019
* Translator.
@@ -24,11 +23,12 @@
2423
class Translator extends BaseTranslator
2524
{
2625
protected $container;
26+
protected $loaderIds;
27+
2728
protected $options = array(
2829
'cache_dir' => null,
2930
'debug' => false,
3031
);
31-
protected $loaderIds;
3232

3333
/**
3434
* Constructor.
@@ -57,7 +57,7 @@ public function __construct(ContainerInterface $container, MessageSelector $sele
5757

5858
$this->options = array_merge($this->options, $options);
5959

60-
parent::__construct(null, $selector);
60+
parent::__construct(null, $selector, $this->options['cache_dir'], $this->options['debug']);
6161
}
6262

6363
/**
@@ -80,72 +80,10 @@ public function getLocale()
8080
/**
8181
* {@inheritdoc}
8282
*/
83-
protected function loadCatalogue($locale)
83+
protected function initializeCatalogue($locale)
8484
{
85-
if (isset($this->catalogues[$locale])) {
86-
return;
87-
}
88-
89-
if (null === $this->options['cache_dir']) {
90-
$this->initialize();
91-
92-
return parent::loadCatalogue($locale);
93-
}
94-
95-
$this->assertValidLocale($locale);
96-
97-
$cache = new ConfigCache($this->options['cache_dir'].'/catalogue.'.$locale.'.php', $this->options['debug']);
98-
if (!$cache->isFresh()) {
99-
$this->initialize();
100-
101-
parent::loadCatalogue($locale);
102-
103-
$fallbackContent = '';
104-
$current = '';
105-
$replacementPattern = '/[^a-z0-9_]/i';
106-
foreach ($this->computeFallbackLocales($locale) as $fallback) {
107-
$fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback));
108-
$currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current));
109-
110-
$fallbackContent .= sprintf(<<<EOF
111-
\$catalogue%s = new MessageCatalogue('%s', %s);
112-
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);
113-
114-
115-
EOF
116-
,
117-
$fallbackSuffix,
118-
$fallback,
119-
var_export($this->catalogues[$fallback]->all(), true),
120-
$currentSuffix,
121-
$fallbackSuffix
122-
);
123-
$current = $fallback;
124-
}
125-
126-
$content = sprintf(<<<EOF
127-
<?php
128-
129-
use Symfony\Component\Translation\MessageCatalogue;
130-
131-
\$catalogue = new MessageCatalogue('%s', %s);
132-
133-
%s
134-
return \$catalogue;
135-
136-
EOF
137-
,
138-
$locale,
139-
var_export($this->catalogues[$locale]->all(), true),
140-
$fallbackContent
141-
);
142-
143-
$cache->write($content, $this->catalogues[$locale]->getResources());
144-
145-
return;
146-
}
147-
148-
$this->catalogues[$locale] = include $cache;
85+
$this->initialize();
86+
parent::initializeCatalogue($locale);
14987
}
15088

15189
protected function initialize()

src/Symfony/Component/Translation/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.6.0
5+
-----
6+
7+
* added possibility to cache catalogues
8+
49
2.5.0
510
-----
611

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
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\Tests;
13+
14+
use Symfony\Component\Translation\Translator;
15+
use Symfony\Component\Translation\MessageCatalogue;
16+
use Symfony\Component\Translation\MessageSelector;
17+
18+
class TranslatorCacheTest extends \PHPUnit_Framework_TestCase
19+
{
20+
protected $tmpDir;
21+
22+
protected function setUp()
23+
{
24+
$this->tmpDir = sys_get_temp_dir().'/sf2_translation';
25+
$this->deleteTmpDir();
26+
}
27+
28+
public function tearDown()
29+
{
30+
$this->deleteTmpDir();
31+
}
32+
33+
protected function deleteTmpDir()
34+
{
35+
if (!file_exists($dir = $this->tmpDir)) {
36+
return;
37+
}
38+
39+
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->tmpDir), \RecursiveIteratorIterator::CHILD_FIRST);
40+
foreach ($iterator as $path) {
41+
if (preg_match('#[/\\\\]\.\.?$#', $path->__toString())) {
42+
continue;
43+
}
44+
if ($path->isDir()) {
45+
rmdir($path->__toString());
46+
} else {
47+
unlink($path->__toString());
48+
}
49+
}
50+
rmdir($this->tmpDir);
51+
}
52+
53+
public function testTransWithoutCaching()
54+
{
55+
$translator = $this->getTranslator($this->getLoader());
56+
$translator->setLocale('fr');
57+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
58+
59+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
60+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
61+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
62+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
63+
$this->assertEquals('no translation', $translator->trans('no translation'));
64+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
65+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
66+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
67+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
68+
}
69+
70+
public function testTransWithCaching()
71+
{
72+
// prime the cache
73+
$translator = $this->getTranslator($this->getLoader(), $this->tmpDir);
74+
$translator->setLocale('fr');
75+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
76+
77+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
78+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
79+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
80+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
81+
$this->assertEquals('no translation', $translator->trans('no translation'));
82+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
83+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
84+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
85+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
86+
87+
// do it another time as the cache is primed now
88+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
89+
$translator = $this->getTranslator($loader, $this->tmpDir);
90+
$translator->setLocale('fr');
91+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
92+
93+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
94+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
95+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
96+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
97+
$this->assertEquals('no translation', $translator->trans('no translation'));
98+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
99+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
100+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
101+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
102+
}
103+
104+
public function testTransWithCachingWithInvalidLocale()
105+
{
106+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
107+
$translator = $this->getTranslator($loader, $this->tmpDir, 'Symfony\Component\Translation\Tests\TranslatorWithInvalidLocale');
108+
109+
$translator->setLocale('invalid locale');
110+
111+
try {
112+
$translator->trans('foo');
113+
$this->fail();
114+
} catch (\InvalidArgumentException $e) {
115+
$this->assertFalse(file_exists($this->tmpDir.'/catalogue.invalid locale.php'));
116+
}
117+
}
118+
119+
public function testLoadCatalogueWithCachingWithInvalidLocale()
120+
{
121+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
122+
$translator = $this->getTranslator($loader, $this->tmpDir, 'Symfony\Component\Translation\Tests\TranslatorWithInvalidLocale');
123+
124+
try {
125+
$translator->proxyLoadCatalogue('invalid locale');
126+
$this->fail();
127+
} catch (\InvalidArgumentException $e) {
128+
$this->assertFalse(file_exists($this->tmpDir.'/catalogue.invalid locale.php'));
129+
}
130+
}
131+
132+
protected function getCatalogue($locale, $messages)
133+
{
134+
$catalogue = new MessageCatalogue($locale);
135+
foreach ($messages as $key => $translation) {
136+
$catalogue->set($key, $translation);
137+
}
138+
139+
return $catalogue;
140+
}
141+
142+
protected function getLoader()
143+
{
144+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
145+
$loader
146+
->expects($this->at(0))
147+
->method('load')
148+
->will($this->returnValue($this->getCatalogue('fr', array(
149+
'foo' => 'foo (FR)',
150+
))))
151+
;
152+
$loader
153+
->expects($this->at(1))
154+
->method('load')
155+
->will($this->returnValue($this->getCatalogue('en', array(
156+
'foo' => 'foo (EN)',
157+
'bar' => 'bar (EN)',
158+
'choice' => '{0} choice 0 (EN)|{1} choice 1 (EN)|]1,Inf] choice inf (EN)',
159+
))))
160+
;
161+
$loader
162+
->expects($this->at(2))
163+
->method('load')
164+
->will($this->returnValue($this->getCatalogue('es', array(
165+
'foobar' => 'foobar (ES)',
166+
))))
167+
;
168+
$loader
169+
->expects($this->at(3))
170+
->method('load')
171+
->will($this->returnValue($this->getCatalogue('pt-PT', array(
172+
'foobarfoo' => 'foobarfoo (PT-PT)',
173+
))))
174+
;
175+
$loader
176+
->expects($this->at(4))
177+
->method('load')
178+
->will($this->returnValue($this->getCatalogue('pt_BR', array(
179+
'other choice' => '{0} other choice 0 (PT-BR)|{1} other choice 1 (PT-BR)|]1,Inf] other choice inf (PT-BR)',
180+
))))
181+
;
182+
$loader
183+
->expects($this->at(5))
184+
->method('load')
185+
->will($this->returnValue($this->getCatalogue('fr.UTF-8', array(
186+
'foobarbaz' => 'foobarbaz (fr.UTF-8)',
187+
))))
188+
;
189+
$loader
190+
->expects($this->at(6))
191+
->method('load')
192+
->will($this->returnValue($this->getCatalogue('sr@latin', array(
193+
'foobarbax' => 'foobarbax (sr@latin)',
194+
))))
195+
;
196+
197+
return $loader;
198+
}
199+
200+
public function getTranslator($loader, $cacheDir = null, $translatorClass = '\Symfony\Component\Translation\Translator')
201+
{
202+
$translator = new $translatorClass('fr', new MessageSelector(), $cacheDir);
203+
204+
$translator->addLoader('loader', $loader);
205+
$translator->addResource('loader', 'foo', 'fr');
206+
$translator->addResource('loader', 'foo', 'en');
207+
$translator->addResource('loader', 'foo', 'es');
208+
$translator->addResource('loader', 'foo', 'pt-PT'); // European Portuguese
209+
$translator->addResource('loader', 'foo', 'pt_BR'); // Brazilian Portuguese
210+
$translator->addResource('loader', 'foo', 'fr.UTF-8');
211+
$translator->addResource('loader', 'foo', 'sr@latin'); // Latin Serbian
212+
213+
return $translator;
214+
}
215+
}
216+
217+
class TranslatorWithInvalidLocale extends Translator
218+
{
219+
/**
220+
* {@inheritdoc}
221+
*/
222+
public function setLocale($locale)
223+
{
224+
$this->locale = $locale;
225+
}
226+
227+
public function proxyLoadCatalogue($locale)
228+
{
229+
$this->loadCatalogue($locale);
230+
}
231+
}

0 commit comments

Comments
 (0)
0