10000 [Translation] added message cache + doctrine cache. · symfony/symfony@cbd6c79 · GitHub
[go: up one dir, main page]

Skip to content

Commit cbd6c79

Browse files
committed
[Translation] added message cache + doctrine cache.
1 parent ce3b8fd commit cbd6c79

File tree

14 files changed

+856
-71
lines changed

14 files changed

+856
-71
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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\Bridge\Doctrine\Tests\Translation;
13+
14+
use Symfony\Bridge\Doctrine\Translation\DoctrineMessageCatalogue;
15+
use Doctrine\Common\Cache\ArrayCache;
16+
17+
class DoctrineMessageCatalogueTest extends \PHPUnit_Framework_TestCase
18+
{
19+
protected function setUp()
20+
{
21+
if (!interface_exists('Doctrine\Common\Cache\Cache')) {
22+
$this->markTestSkipped('The "Doctrine Cache" is not available');
23+
}
24+
}
25+
26+
public function testGetLocale()
27+
{
28+
$catalogue = $this->getCatalogue('en');
29+
30+
$this->assertEquals('en', $catalogue->getLocale());
31+
}
32+
33+
public function testGetDomains()
34+
{
35+
$catalogue = $this->getCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
36+
37+
$this->assertEquals(array('domain1', 'domain2'), $catalogue->getDomains());
38+
}
39+
40+
public function testAll()
41+
{
42+
if (!interface_exists('Doctrine\Common\Cache\MultiGetCache')) {
43+
$this->markTestSkipped('The "Doctrine MultiGetCache" is not available');
44+
}
45+
46+
$catalogue = $this->getCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
47+
48+
$this->assertEquals(array('foo' => 'foo'), $catalogue->all('domain1'));
49+
$this->assertEquals(array(), $catalogue->all('domain88'));
50+
$this->assertEquals(array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')), $catalogue->all());
51+
}
52+
53+
public function testHas()
54+
{
55+
$catalogue = $this->getCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
56+
57+
$this->assertTrue($catalogue->has('foo', 'domain1'));
58+
$this->assertFalse($catalogue->has('bar', 'domain1'));
59+
$this->assertFalse($catalogue->has('foo', 'domain88'));
60+
}
61+
62+
public function testGetSet()
63+
{
64+
$catalogue = $this->getCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
65+
66+
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
67+
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
68+
}
69+
70+
public function testAdd()
71+
{
72+
$catalogue = $this->getCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
73+
$catalogue->add(array('foo1' => 'foo1'), 'domain1');
74+
75+
$this->assertEquals('foo', $catalogue->get('foo', 'domain1'));
76+
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
77+
78+
$catalogue->add(array('foo' => 'bar'), 'domain1');
79+
$this->assertEquals('bar', $catalogue->get('foo', 'domain1'));
80+
$this->assertEquals('foo1', $catalogue->get('foo1', 'domain1'));
81+
82+
$catalogue->add(array('foo' => 'bar'), 'domain88');
83+
$this->assertEquals('bar', $catalogue->get('foo', 'domain88'));
84+
}
85+
86+
public function testReplace()
87+
{
88+
$catalogue = $this->getCatalogue('en', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar')));
89+
$catalogue->replace($messages = array('foo1' => 'foo1_trans'), 'domain1');
90+
91+
$this->assertEquals($messages['foo1'], $catalogue->get('foo1', 'domain1'));
92+
}
93+
94+
private function getCatalogue($locale, $messages = array())
95+
{
96+
$catalogue = new DoctrineMessageCatalogue($locale, new ArrayCache());
97+
foreach ($messages as $domain => $domainMessages) {
98+
$catalogue->add($domainMessages, $domain);
99+
}
100+
101+
return $catalogue;
102+
}
103+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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\Bridge\Doctrine\Tests\Translation;
13+
14+
use Symfony\Component\Translation\Translator;
15+
use Symfony\Component\Translation\MessageCatalogue;
16+
use Symfony\Component\Translation\MessageSelector;
17+
use Symfony\Bridge\Doctrine\Translation\DoctrineMessageCache;
18+
use Doctrine\Common\Cache\ArrayCache;
19+
20+
class TranslatorDoctrineCacheTest extends \PHPUnit_Framework_TestCase
21+
{
22+
protected function setUp()
23+
{
24+
if (!interface_exists('Doctrine\Common\Cache\Cache')) {
25+
$this->markTestSkipped('The "Doctrine Cache" is not available');
26+
}
27+
}
28+
29+
public function testTrans()
30+
{
31+
$cache = new DoctrineMessageCache(new ArrayCache());
32+
33+
// prime the cache
34+
$translator = $this->getTranslator($this->getLoader(), $cache);
35+
$translator->setLocale('fr');
36+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
37+
38+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
39+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
40+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
41+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
42+
$this->assertEquals('no translation', $translator->trans('no translation'));
43+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
44+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
45+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
46+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
47+
48+
// do it another time as the cache is primed now
49+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
50+
$translator = $this->getTranslator($loader, $cache);
51+
$translator->setLocale('fr');
52+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
53+
54+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
55+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
56+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
57+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
58+
$this->assertEquals('no translation', $translator->trans('no translation'));
59+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
60+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
61+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
62+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
63+
}
64+
65+
public function testRefreshCacheWhenResourcesChange()
66+
{
67+
// prime the cache
68+
$cache = new DoctrineMessageCache(new ArrayCache(), true);
69+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
70+
$loader
71+
->method('load')
72+
->will($this->returnValue($this->getCatalogue('fr', array(
73+
'foo' => 'foo A',
74+
))))
75+
;
76+
77+
$translator = new Translator('fr', new MessageSelector(), $cache);
78+
$translator->setLocale('fr');
79+
$translator->addLoader('loader', $loader);
80+
$translator->addResource('loader', 'foo', 'fr');
81+
82+
$this->assertEquals('foo A', $translator->trans('foo'));
83+
84+
// add a new resource to refresh the cache
85+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
86+
$loader
87+
->method('load')
88+
->will($this->returnValue($this->getCatalogue('fr', array(
89+
'foo' => 'foo B',
90+
))))
91+
;
92+
93+
$tra 10000 nslator = new Translator('fr', new MessageSelector(), $cache);
94+
$translator->setLocale('fr');
95+
$translator->addLoader('loader', $loader);
96+
$translator->addResource('loader', 'bar', 'fr');
97+
98+
$this->assertEquals('foo B', $translator->trans('foo'));
99+
}
100+
101+
protected function getLoader()
102+
{
103+
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
104+
$loader
105+
->expects($this->at(0))
106+
->method('load')
107+
->will($this->returnValue($this->getCatalogue('fr', array(
108+
'foo' => 'foo (FR)',
109+
))))
110+
;
111+
$loader
112+
->expects($this->at(1))
113+
->method('load')
114+
->will($this->returnValue($this->getCatalogue('en', array(
115+
'foo' => 'foo (EN)',
116+
'bar' => 'bar (EN)',
117+
'choice' => '{0} choice 0 (EN)|{1} choice 1 (EN)|]1,Inf] choice inf (EN)',
118+
))))
119+
;
120+
$loader
121+
->expects($this->at(2))
122+
->method('load')
123+
->will($this->returnValue($this->getCatalogue('es', array(
124+
'foobar' => 'foobar (ES)',
125+
))))
126+
;
127+
$loader
128+
->expects($this->at(3))
129+
->method('load')
130+
->will($this->returnValue($this->getCatalogue('pt-PT', array(
131+
'foobarfoo' => 'foobarfoo (PT-PT)',
132+
))))
133+
;
134+
$loader
135+
->expects($this->at(4))
136+
->method('load')
137+
->will($this->returnValue($this->getCatalogue('pt_BR', array(
138+
'other choice' => '{0} other choice 0 (PT-BR)|{1} other choice 1 (PT-BR)|]1,Inf] other choice inf (PT-BR)',
139+
))))
140+
;
141+
$loader
142+
->expects($this->at(5))
143+
->method('load')
144+
->will($this->returnValue($this->getCatalogue('fr.UTF-8', array(
145+
'foobarbaz' => 'foobarbaz (fr.UTF-8)',
146+
))))
147+
;
148+
$loader
149+
->expects($this->at(6))
150+
->method('load')
151+
->will($this->returnValue($this->getCatalogue('sr@latin', array(
152+
'foobarbax' => 'foobarbax (sr@latin)',
153+
))))
154+
;
155+
156+
return $loader;
157+
}
158+
159+
protected function getCatalogue($locale, $messages)
160+
{
161+
$catalogue = new MessageCatalogue($locale);
162+
foreach ($messages as $key => $translation) {
163+
$catalogue->set($key, $translation);
164+
}< D7AE /div>
165+
166+
return $catalogue;
167+
}
168+
169+
public function getTranslator($loader, $cache)
170+
{
171+
$translator = new Translator('fr', new MessageSelector(), $cache);
172+
173+
$translator->addLoader('loader', $loader);
174+
$translator->addResource('loader', 'foo', 'fr');
175+
$translator->addResource('loader', 'foo', 'en');
176+
$translator->addResource('loader', 'foo', 'es');
177+
$translator->addResource('loader', 'foo', 'pt-PT'); // European Portuguese
178+
$translator->addResource('loader', 'foo', 'pt_BR'); // Brazilian Portuguese
179+
$translator->addResource('loader', 'foo', 'fr.UTF-8');
180+
$translator->addResource('loader', 'foo', 'sr@latin'); // Latin Serbian
181+
182+
return $translator;
183+
}
184+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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\Bridge\Doctrine\Translation;
13+
14+
use Doctrine\Common\Cache\Cache;
15+
use Symfony\Component\Translation\MessageCacheInterface;
16+
use Symfony\Component\Translation\MessageCatalogueInterface;
17+
18+
/**
19+
* @author Abdellatif Ait Boudad <a.aitboudad@gmail.com>
20+
*/
21+
class DoctrineMessageCache implements MessageCacheInterface
22+
{
23+
const CACHE_RESOURCE_HASH = 'resources_hash';
24+
const CATALOGUE_FALLBACK_LOCALE = 'fallback_locale';
25+
26+
/**
27+
* @var bool
28+
*/
29+
private $debug;
30+
31+
/**
32+
* @var Cache
33+
*/
34+
private $cache;
35+
36+
/**
37+
* @param Cache $cache
38+
* @param bool $debug
39+
*/
40+
public function __construct(Cache $cache, $debug = false)
41+
{
42+
$this->debug = $debug;
43+
$this->cache = $cache;
44+
}
45+
46+
/**
47+
* {@inheritdoc}
48+
*/
49+
public function isFresh($locale, array $options = array())
50+
{
51+
$currentResourcesHash = isset($options['resources_hash']) ? $options['resources_hash'] : '';
52+
$resourcesHash = $this->cache->fetch($this->getResourceHashKey($locale));
53+
if (false === $resourcesHash || ($this->debug && $resourcesHash !== $currentResourcesHash)) {
54+
return false;
55+
}
56+
57+
return true;
58+
}
59+
60+
/**
61+
* {@inheritdoc}
62+
*/
63+
public function load($locale)
64+
{
65+
$messages = new DoctrineMessageCatalogue($locale, $this->cache);
66+
$catalogue = $messages;
67+
while ($fallbackLocale = $this->cache->fetch($this->getFallbackLocaleKey($catalogue->getLocale()))) {
68+
$fallback = new DoctrineMessageCatalogue($fallbackLocale, $this->cache);
69+
$catalogue->addFallbackCatalogue($fallback);
70+
$catalogue = $fallback;
71+
}
72+
73+
return $messages;
74+
}
75+
76+
/**
77+
* {@inheritdoc}
78+
*/
79+
public function dump(MessageCatalogueInterface $messages, array $options = array())
80+
{
81+
$resourcesHash = isset($options['resources_hash']) ? $options['resources_hash'] : '';
82+
while ($messages) {
83+
$catalogue = new DoctrineMessageCatalogue($messages->getLocale(), $this->cache);
84+
$catalogue->addCatalogue($messages);
85+
86+
$this->cache->save($this->getResourceHashKey($messages->getLocale()), $resourcesHash);
87+
if ($fallback = $messages->getFallbackCatalogue()) {
88+
$this->cache->save($this->getFallbackLocaleKey($messages->getLocale()), $fallback->getLocale());
89+
}
90+
91+
$messages = $messages->getFallbackCatalogue();
92+
}
93+
}
94+
95+
private function getResourceHashKey($locale)
96+
{
97+
return self::CACHE_RESOURCE_HASH.'_'.$locale;
98+
}
99+
100+
private function getFallbackLocaleKey($locale)
101+
{
102+
return self::CATALOGUE_FALLBACK_LOCALE.'_'.$locale;
103+
}
104+
}

0 commit comments

Comments
 (0)
0