Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7faf677

Browse filesBrowse files
committed
[FrameworkBundle] Make Translator works with any PSR-11 container
1 parent 2a99e16 commit 7faf677
Copy full SHA for 7faf677

File tree

8 files changed

+204
-17
lines changed
Filter options

8 files changed

+204
-17
lines changed

‎UPGRADE-3.3.md

Copy file name to clipboardExpand all lines: UPGRADE-3.3.md
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ FrameworkBundle
172172
class has been deprecated and will be removed in 4.0. Use the
173173
`Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` class instead.
174174

175+
* The `Translator` now takes a `default_locale` option. Not
176+
passing it will throw an exception in 4.0.
177+
175178
HttpKernel
176179
-----------
177180

‎UPGRADE-4.0.md

Copy file name to clipboardExpand all lines: UPGRADE-4.0.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ FrameworkBundle
271271
class has been removed. Use the
272272
`Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` class instead.
273273

274+
* The `Translator` now takes a `default_locale` mandatory option.
275+
274276
HttpFoundation
275277
---------------
276278

‎src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ CHANGELOG
3030
* Deprecated `ControllerArgumentValueResolverPass`. Use
3131
`Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass` instead
3232
* Deprecated `RoutingResolverPass`, use `Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` instead
33+
* The `Translator` now takes a `default_locale` mandatory option
34+
and accepts any PSR-11 container.
3335

3436
3.2.0
3537
-----

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php
+9-2Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1415
use Symfony\Component\DependencyInjection\Reference;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
@@ -24,7 +25,9 @@ public function process(ContainerBuilder $container)
2425
}
2526

2627
$loaders = array();
28+
$loaderRefs = array();
2729
foreach ($container->findTaggedServiceIds('translation.loader') as $id => $attributes) {
30+
$loaderRefs[$id] = new Reference($id);
2831
$loaders[$id][] = $attributes[0]['alias'];
2932
if (isset($attributes[0]['legacy-alias'])) {
3033
$loaders[$id][] = $attributes[0]['legacy-alias'];
@@ -35,11 +38,15 @@ public function process(ContainerBuilder $container)
3538
$definition = $container->getDefinition('translation.loader');
3639
foreach ($loaders as $id => $formats) {
3740
foreach ($formats as $format) {
38-
$definition->addMethodCall('addLoader', array($format, new Reference($id)));
41+
$definition->addMethodCall('addLoader', array($format, $loaderRefs[$id]));
3942
}
4043
}
4144
}
4245

43-
$container->findDefinition('translator.default')->replaceArgument(2, $loaders);
46+
$container
47+
->findDefinition('translator.default')
48+
->replaceArgument(0, new ServiceLocatorArgument($loaderRefs))
49+
->replaceArgument(2, $loaders)
50+
;
4451
}
4552
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
<services>
88
<service id="translator.default" class="Symfony\Bundle\FrameworkBundle\Translation\Translator">
9-
<argument type="service" id="service_container" />
9+
<argument type="service-locator" /> <!-- translation loaders -->
1010
<argument type="service" id="translator.selector" />
11-
<argument type="collection" /> <!-- translation loaders -->
11+
<argument type="collection" /> <!-- translation loaders ids -->
1212
<argument type="collection">
1313
<argument key="cache_dir">%kernel.cache_dir%/translations</argument>
1414
<argument key="debug">%kernel.debug%</argument>
15+
<argument key="default_locale">%kernel.default_locale%</argument>
1516
</argument>
16-
<argument type="collection" /> <!-- translation resources -->
1717
<call method="setConfigCacheFactory">
1818
<argument type="service" id="config_cache_factory" />
1919
</call>

‎src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php
+10-1Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1516
use Symfony\Component\DependencyInjection\Reference;
1617
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
1718

@@ -39,7 +40,15 @@ public function testValidCollector()
3940
->will($this->returnValue(array('xliff' => array(array('alias' => 'xliff', 'legacy-alias' => 'xlf')))));
4041
$container->expects($this->once())
4142
->method('findDefinition')
42-
->will($this->returnValue($this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock()));
43+
->will($this->returnValue($translator = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock()));
44+
$translator->expects($this->at(0))
45+
->method('replaceArgument')
46+
->with(0, $this->equalTo(new ServiceLocatorArgument(array('xliff' => new Reference('xliff')))))
47+
->willReturn($translator);
48+
$translator->expects($this->at(1))
49+
->method('replaceArgument')
50+
->with(2, array('xliff' => array('xliff', 'xlf')))
51+
->willReturn($translator);
4352
$pass = new TranslatorPass();
4453
$pass->process($container);
4554
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php
+160-9Lines changed: 160 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,159 @@ protected function deleteTmpDir()
4242
$fs->remove($dir);
4343
}
4444

45+
/**
46+
* @group legacy
47+
* @expectedDeprecation The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.
48+
*/
49+
public function testTransWithoutCachingOmittingLocale()
50+
{
51+
$translator = $this->getTranslator($this->getLoader(), array('default_locale' => null));
52+
$translator->setLocale('fr');
53+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
54+
55+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
56+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
57+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
58+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
59+
$this->assertEquals('no translation', $translator->trans('no translation'));
60+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
61+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
62+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
63+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
64+
}
65+
66+
/**
67+
* @group legacy
68+
* @expectedDeprecation The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.
69+
*/
70+
public function testTransWithCachingOmittingLocale()
71+
{
72+
// prime the cache
73+
$translator = $this->getTranslator($this->getLoader(), array('cache_dir' => $this->tmpDir, 'default_locale' => null));
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->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
89+
$loader->expects($this->never())->method('load');
90+
91+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'default_locale' => null));
92+
$translator->setLocale('fr');
93+
$translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin'));
94+
95+
$this->assertEquals('foo (FR)', $translator->trans('foo'));
96+
$this->assertEquals('bar (EN)', $translator->trans('bar'));
97+
$this->assertEquals('foobar (ES)', $translator->trans('foobar'));
98+
$this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0));
99+
$this->assertEquals('no translation', $translator->trans('no translation'));
100+
$this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo'));
101+
$this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1));
102+
$this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz'));
103+
$this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax'));
104+
}
105+
106+
/**
107+
* @group legacy
108+
* @expectedDeprecation The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.
109+
* @expectedException \InvalidArgumentException
110+
* @expectedExceptionMessage Invalid "invalid locale" locale.
111+
*/
112+
public function testTransWithCachingWithInvalidLocaleOmittingLocale()
113+
{
114+
$loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
115+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'default_locale' => null), 'loader', '\Symfony\Bundle\FrameworkBundle\Tests\Translation\TranslatorWithInvalidLocale');
116+
117+
$translator->trans('foo');
118+
}
119+
120+
/**
121+
* @group legacy
122+
* @expectedDeprecation The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.
123+
*/
124+
public function testLoadResourcesWithoutCachingOmittingLocale()
125+
{
126+
$loader = new \Symfony\Component\Translation\Loader\YamlFileLoader();
127+
$resourceFiles = array(
128+
'fr' => array(
129+
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
130+
),
131+
);
132+
133+
$translator = $this->getTranslator($loader, array('resource_files' => $resourceFiles, 'default_locale' => null), 'yml');
134+
$translator->setLocale('fr');
135+
136+
$this->assertEquals('répertoire', $translator->trans('folder'));
137+
}
138+
139+
/**
140+
* @group legacy
141+
* @expectedDeprecation The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.
142+
*/
143+
public function testGetDefaultLocaleOmittingLocale()
144+
{
145+
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock();
146+
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock();
147+
$container
148+
->expects($this->once())
149+
->method('getParameter')
150+
->with('kernel.default_locale')
151+
->will($this->returnValue('en'))
152+
;
153+
$translator = new Translator($container, new MessageSelector(), array(), array('default_locale' => null));
154+
155+
$this->assertSame('en', $translator->getLocale());
156+
}
157+
158+
/**
159+
* @group legacy
160+
* @expectedException \InvalidArgumentException
161+
* @expectedExceptionMessage The "default_locale" option must be set.
162+
*/
163+
public function testGetDefaultLocaleOmittingLocaleWithPsrContainer()
164+
{
165+
$container = $this->getMockBuilder('Psr\Container\ContainerInterface')->getMock();
166+
$translator = new Translator($container, new MessageSelector(), array(), array('default_locale' => null));
167+
}
168+
169+
/**
170+
* @group legacy
171+
* @expectedDeprecation The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.
172+
*/
173+
public function testWarmupOmittingLocale()
174+
{
175+
$loader = new \Symfony\Component\Translation\Loader\YamlFileLoader();
176+
$resourceFiles = array(
177+
'fr' => array(
178+
__DIR__.'/../Fixtures/Resources/translations/messages.fr.yml',
179+
),
180+
);
181+
182+
// prime the cache
183+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles, 'default_locale' => null), 'yml');
184+
$translator->setFallbackLocales(array('fr'));
185+
$translator->warmup($this->tmpDir);
186+
187+
$loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock();
188+
$loader
189+
->expects($this->never())
190+
->method('load');
191+
192+
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml');
193+
$translator->setLocale('fr');
194+
$translator->setFallbackLocales(array('fr'));
195+
$this->assertEquals('répertoire', $translator->trans('folder'));
196+
}
197+
45198
public function testTransWithoutCaching()
46199
{
47200
$translator = $this->getTranslator($this->getLoader());
@@ -97,6 +250,7 @@ public function testTransWithCaching()
97250

98251
/**
99252
* @expectedException \InvalidArgumentException
253+
* @expectedExceptionMessage Invalid "invalid locale" locale.
100254
*/
101255
public function testTransWithCachingWithInvalidLocale()
102256
{
@@ -123,15 +277,8 @@ public function testLoadResourcesWithoutCaching()
123277

124278
public function testGetDefaultLocale()
125279
{
126-
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock();
127-
$container
128-
->expects($this->once())
129-
->method('getParameter')
130-
->with('kernel.default_locale')
131-
->will($this->returnValue('en'))
132-
;
133-
134-
$translator = new Translator($container, new MessageSelector());
280+
$container = $this->getMockBuilder('Psr\Container\ContainerInterface')->getMock();
281+
$translator = new Translator($container, new MessageSelector(), array(), array('default_locale' => 'en'));
135282

136283
$this->assertSame('en', $translator->getLocale());
137284
}
@@ -263,6 +410,10 @@ public function testWarmup()
263410

264411
private function createTranslator($loader, $options, $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator', $loaderFomat = 'loader')
265412
{
413+
if (!array_key_exists('default_locale', $options)) {
414+
$options['default_locale'] = 'en';
415+
}
416+
266417
return new $translatorClass(
267418
$this->getContainer($loader),
268419
new MessageSelector(),

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
+15-2Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Translation;
1313

14+
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface;
1416
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
1517
use Symfony\Component\Translation\Translator as BaseTranslator;
1618
use Symfony\Component\Translation\MessageSelector;
17-
use Symfony\Component\DependencyInjection\ContainerInterface;
1819
use Symfony\Component\Translation\Exception\InvalidArgumentException;
1920

2021
/**
@@ -31,6 +32,7 @@ class Translator extends BaseTranslator implements WarmableInterface
3132
'cache_dir' => null,
3233
'debug' => false,
3334
'resource_files' => array(),
35+
'default_locale' => null,
3436
);
3537

3638
/**
@@ -46,6 +48,7 @@ class Translator extends BaseTranslator implements WarmableInterface
4648
* * cache_dir: The cache directory (or null to disable caching)
4749
* * debug: Whether to enable debugging or not (false by default)
4850
* * resource_files: List of translation resources available grouped by locale.
51+
* * default_locale: The default locale (mandatory)
4952
*
5053
* @param ContainerInterface $container A ContainerInterface instance
5154
* @param MessageSelector $selector The message selector for pluralization
@@ -70,7 +73,17 @@ public function __construct(ContainerInterface $container, MessageSelector $sele
7073
$this->loadResources();
7174
}
7275

73-
parent::__construct($container->getParameter('kernel.default_locale'), $selector, $this->options['cache_dir'], $this->options['debug']);
76+
// BC 3.X, to be removed in 4.0
77+
if (null === $this->options['default_locale']) {
78+
if ($container instanceof SymfonyContainerInterface) {
79+
$this->options['default_locale'] = $container->getParameter('kernel.default_locale');
80+
} else {
81+
throw new \InvalidArgumentException('The "default_locale" option must be set.');
82+
}
83+
@trigger_error('The Translator takes a "default_locale" option since version 3.3, not passing it is deprecated and will throw an exception in 4.0.', E_USER_DEPRECATED);
84+
}
85+
86+
parent::__construct($this->options['default_locale'], $selector, $this->options['cache_dir'], $this->options['debug']);
7487
}
7588

7689
/**

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.