diff --git a/UPGRADE-3.3.md b/UPGRADE-3.3.md index 7caf4a7e14edd..beeeea4c7ffab 100644 --- a/UPGRADE-3.3.md +++ b/UPGRADE-3.3.md @@ -180,6 +180,9 @@ FrameworkBundle Require `symfony/web-server-bundle` in your composer.json and register `Symfony\Bundle\WebServerBundle\WebServerBundle` in your AppKernel to use them. + * The `Symfony\Bundle\FrameworkBundle\Translation\Translator` constructor now takes the + default locale as 3rd argument. Not passing it will trigger an error in 4.0. + HttpKernel ----------- diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index b4fafca01bdc6..7c9d0a29ff5eb 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -274,6 +274,9 @@ FrameworkBundle class has been removed. Use the `Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` class instead. + * The `Symfony\Bundle\FrameworkBundle\Translation\Translator` constructor now takes the + default locale as mandatory 3rd argument. + HttpFoundation --------------- diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index da650439d6601..1dcc2f42f1e05 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -35,6 +35,8 @@ CHANGELOG `server:status` console commands have been moved to a dedicated bundle. Require `symfony/web-server-bundle` in your composer.json and register `Symfony\Bundle\WebServerBundle\WebServerBundle` in your AppKernel to use them. + * Added `$defaultLocale` as 3rd argument of `Translator::__construct()` + making `Translator` works with any PSR-11 container 3.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php index 4e450166afa44..2bdd9d8055e98 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslatorPass.php @@ -11,9 +11,11 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ServiceLocator; class TranslatorPass implements CompilerPassInterface { @@ -24,7 +26,9 @@ public function process(ContainerBuilder $container) } $loaders = array(); + $loaderRefs = array(); foreach ($container->findTaggedServiceIds('translation.loader') as $id => $attributes) { + $loaderRefs[$id] = new Reference($id); $loaders[$id][] = $attributes[0]['alias']; if (isset($attributes[0]['legacy-alias'])) { $loaders[$id][] = $attributes[0]['legacy-alias']; @@ -35,11 +39,15 @@ public function process(ContainerBuilder $container) $definition = $container->getDefinition('translation.loader'); foreach ($loaders as $id => $formats) { foreach ($formats as $format) { - $definition->addMethodCall('addLoader', array($format, new Reference($id))); + $definition->addMethodCall('addLoader', array($format, $loaderRefs[$id])); } } } - $container->findDefinition('translator.default')->replaceArgument(2, $loaders); + $container + ->findDefinition('translator.default') + ->replaceArgument(0, (new Definition(ServiceLocator::class, array($loaderRefs)))->addTag('container.service_locator')) + ->replaceArgument(3, $loaders) + ; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 17a613b70c1bc..637d2b88c6fd4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -954,11 +954,11 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder } $options = array_merge( - $translator->getArgument(3), + $translator->getArgument(4), array('resource_files' => $files) ); - $translator->replaceArgument(3, $options); + $translator->replaceArgument(4, $options); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml index 6cd41fb882f3e..2fa53885b9d8f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml @@ -6,14 +6,14 @@ - + - + %kernel.default_locale% + %kernel.cache_dir%/translations %kernel.debug% - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php index 10a38aabdb402..cfb5beeb550f4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/TranslatorPassTest.php @@ -12,8 +12,10 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass; +use Symfony\Component\DependencyInjection\ServiceLocator; class TranslatorPassTest extends TestCase { @@ -39,7 +41,15 @@ public function testValidCollector() ->will($this->returnValue(array('xliff' => array(array('alias' => 'xliff', 'legacy-alias' => 'xlf'))))); $container->expects($this->once()) ->method('findDefinition') - ->will($this->returnValue($this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock())); + ->will($this->returnValue($translator = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock())); + $translator->expects($this->at(0)) + ->method('replaceArgument') + ->with(0, $this->equalTo((new Definition(ServiceLocator::class, array(array('xliff' => new Reference('xliff')))))->addTag('container.service_locator'))) + ->willReturn($translator); + $translator->expects($this->at(1)) + ->method('replaceArgument') + ->with(3, array('xliff' => array('xliff', 'xlf'))) + ->willReturn($translator); $pass = new TranslatorPass(); $pass->process($container); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 64423bda88702..a04a213aeaa48 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection; use Doctrine\Common\Annotations\Annotation; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass; use Symfony\Bundle\FullStack; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass; @@ -417,7 +418,7 @@ public function testTranslator() $container = $this->createContainerFromFile('full'); $this->assertTrue($container->hasDefinition('translator.default'), '->registerTranslatorConfiguration() loads translation.xml'); $this->assertEquals('translator.default', (string) $container->getAlias('translator'), '->registerTranslatorConfiguration() redefines translator service from identity to real translator'); - $options = $container->getDefinition('translator.default')->getArgument(3); + $options = $container->getDefinition('translator.default')->getArgument(4); $files = array_map('realpath', $options['resource_files']['en']); $ref = new \ReflectionClass('Symfony\Component\Validator\Validation'); @@ -922,7 +923,7 @@ protected function createContainerFromFile($file, $data = array(), $resetCompile $container->getCompilerPassConfig()->setOptimizationPasses(array()); $container->getCompilerPassConfig()->setRemovingPasses(array()); } - $container->getCompilerPassConfig()->setBeforeRemovingPasses(array(new AddAnnotationsCachedReaderPass(), new AddConstraintValidatorsPass())); + $container->getCompilerPassConfig()->setBeforeRemovingPasses(array(new AddAnnotationsCachedReaderPass(), new AddConstraintValidatorsPass(), new TranslatorPass())); $container->compile(); return self::$containerCache[$cacheKey] = $container; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index d9efdfe6e94d5..ef6fa9330b0d8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Translation; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Translation\Translator; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Filesystem\Filesystem; @@ -42,6 +43,157 @@ protected function deleteTmpDir() $fs->remove($dir); } + /** + * @group legacy + * @expectedDeprecation Method Symfony\Bundle\FrameworkBundle\Translation\Translator::__construct() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0. + */ + public function testTransWithoutCachingOmittingLocale() + { + $translator = $this->getTranslator($this->getLoader(), array(), 'loader', '\Symfony\Bundle\FrameworkBundle\Translation\Translator', null); + $translator->setLocale('fr'); + $translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin')); + + $this->assertEquals('foo (FR)', $translator->trans('foo')); + $this->assertEquals('bar (EN)', $translator->trans('bar')); + $this->assertEquals('foobar (ES)', $translator->trans('foobar')); + $this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0)); + $this->assertEquals('no translation', $translator->trans('no translation')); + $this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo')); + $this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1)); + $this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz')); + $this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax')); + } + + /** + * @group legacy + * @expectedDeprecation Method Symfony\Bundle\FrameworkBundle\Translation\Translator::__construct() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0. + */ + public function testTransWithCachingOmittingLocale() + { + // prime the cache + $translator = $this->getTranslator($this->getLoader(), array('cache_dir' => $this->tmpDir), 'loader', '\Symfony\Bundle\FrameworkBundle\Translation\Translator', null); + $translator->setLocale('fr'); + $translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin')); + + $this->assertEquals('foo (FR)', $translator->trans('foo')); + $this->assertEquals('bar (EN)', $translator->trans('bar')); + $this->assertEquals('foobar (ES)', $translator->trans('foobar')); + $this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0)); + $this->assertEquals('no translation', $translator->trans('no translation')); + $this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo')); + $this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1)); + $this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz')); + $this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax')); + + // do it another time as the cache is primed now + $loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock(); + $loader->expects($this->never())->method('load'); + + $translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), 'loader', '\Symfony\Bundle\FrameworkBundle\Translation\Translator', null); + $translator->setLocale('fr'); + $translator->setFallbackLocales(array('en', 'es', 'pt-PT', 'pt_BR', 'fr.UTF-8', 'sr@latin')); + + $this->assertEquals('foo (FR)', $translator->trans('foo')); + $this->assertEquals('bar (EN)', $translator->trans('bar')); + $this->assertEquals('foobar (ES)', $translator->trans('foobar')); + $this->assertEquals('choice 0 (EN)', $translator->transChoice('choice', 0)); + $this->assertEquals('no translation', $translator->trans('no translation')); + $this->assertEquals('foobarfoo (PT-PT)', $translator->trans('foobarfoo')); + $this->assertEquals('other choice 1 (PT-BR)', $translator->transChoice('other choice', 1)); + $this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz')); + $this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax')); + } + + /** + * @group legacy + * @expectedDeprecation Method Symfony\Bundle\FrameworkBundle\Translation\Translator::__construct() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0. + * @expectedException \InvalidArgumentException + */ + public function testTransWithCachingWithInvalidLocaleOmittingLocale() + { + $loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock(); + $translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir), 'loader', '\Symfony\Bundle\FrameworkBundle\Tests\Translation\TranslatorWithInvalidLocale', null); + + $translator->trans('foo'); + } + + /** + * @group legacy + * @expectedDeprecation Method Symfony\Bundle\FrameworkBundle\Translation\Translator::__construct() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0. + */ + public function testLoadResourcesWithoutCachingOmittingLocale() + { + $loader = new \Symfony\Component\Translation\Loader\YamlFileLoader(); + $resourceFiles = array( + 'fr' => array( + __DIR__.'/../Fixtures/Resources/translations/messages.fr.yml', + ), + ); + + $translator = $this->getTranslator($loader, array('resource_files' => $resourceFiles), 'yml', '\Symfony\Bundle\FrameworkBundle\Translation\Translator', null); + $translator->setLocale('fr'); + + $this->assertEquals('répertoire', $translator->trans('folder')); + } + + /** + * @group legacy + * @expectedDeprecation Method Symfony\Bundle\FrameworkBundle\Translation\Translator::__construct() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0. + */ + public function testGetDefaultLocaleOmittingLocale() + { + $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); + $container + ->expects($this->once()) + ->method('getParameter') + ->with('kernel.default_locale') + ->will($this->returnValue('en')) + ; + $translator = new Translator($container, new MessageSelector()); + + $this->assertSame('en', $translator->getLocale()); + } + + /** + * @group legacy + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Missing third $defaultLocale argument. + */ + public function testGetDefaultLocaleOmittingLocaleWithPsrContainer() + { + $container = $this->getMockBuilder(ContainerInterface::class)->getMock(); + $translator = new Translator($container, new MessageSelector()); + } + + /** + * @group legacy + * @expectedDeprecation Method Symfony\Bundle\FrameworkBundle\Translation\Translator::__construct() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0. + */ + public function testWarmupOmittingLocale() + { + $loader = new \Symfony\Component\Translation\Loader\YamlFileLoader(); + $resourceFiles = array( + 'fr' => array( + __DIR__.'/../Fixtures/Resources/translations/messages.fr.yml', + ), + ); + + // prime the cache + $translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml', '\Symfony\Bundle\FrameworkBundle\Translation\Translator', null); + $translator->setFallbackLocales(array('fr')); + $translator->warmup($this->tmpDir); + + $loader = $this->getMockBuilder('Symfony\Component\Translation\Loader\LoaderInterface')->getMock(); + $loader + ->expects($this->never()) + ->method('load'); + + $translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml', '\Symfony\Bundle\FrameworkBundle\Translation\Translator', null); + $translator->setLocale('fr'); + $translator->setFallbackLocales(array('fr')); + $this->assertEquals('répertoire', $translator->trans('folder')); + } + public function testTransWithoutCaching() { $translator = $this->getTranslator($this->getLoader()); @@ -97,6 +249,7 @@ public function testTransWithCaching() /** * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid "invalid locale" locale. */ public function testTransWithCachingWithInvalidLocale() { @@ -123,15 +276,8 @@ public function testLoadResourcesWithoutCaching() public function testGetDefaultLocale() { - $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); - $container - ->expects($this->once()) - ->method('getParameter') - ->with('kernel.default_locale') - ->will($this->returnValue('en')) - ; - - $translator = new Translator($container, new MessageSelector()); + $container = $this->getMockBuilder(ContainerInterface::class)->getMock(); + $translator = new Translator($container, new MessageSelector(), 'en'); $this->assertSame('en', $translator->getLocale()); } @@ -144,7 +290,7 @@ public function testInvalidOptions() { $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); - (new Translator($container, new MessageSelector(), array(), array('foo' => 'bar'))); + (new Translator($container, new MessageSelector(), 'en', array(), array('foo' => 'bar'))); } protected function getCatalogue($locale, $messages, $resources = array()) @@ -230,9 +376,9 @@ protected function getContainer($loader) return $container; } - public function getTranslator($loader, $options = array(), $loaderFomat = 'loader', $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator') + public function getTranslator($loader, $options = array(), $loaderFomat = 'loader', $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator', $defaultLocale = 'en') { - $translator = $this->createTranslator($loader, $options, $translatorClass, $loaderFomat); + $translator = $this->createTranslator($loader, $options, $translatorClass, $loaderFomat, $defaultLocale); if ('loader' === $loaderFomat) { $translator->addResource('loader', 'foo', 'fr'); @@ -272,11 +418,21 @@ public function testWarmup() $this->assertEquals('répertoire', $translator->trans('folder')); } - private function createTranslator($loader, $options, $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator', $loaderFomat = 'loader') + private function createTranslator($loader, $options, $translatorClass = '\Symfony\Bundle\FrameworkBundle\Translation\Translator', $loaderFomat = 'loader', $defaultLocale = 'en') { + if (null === $defaultLocale) { + return new $translatorClass( + $this->getContainer($loader), + new MessageSelector(), + array($loaderFomat => array($loaderFomat)), + $options + ); + } + return new $translatorClass( $this->getContainer($loader), new MessageSelector(), + $defaultLocale, array($loaderFomat => array($loaderFomat)), $options ); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index fedc425a11a07..6bcbaa8e97416 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -11,10 +11,11 @@ namespace Symfony\Bundle\FrameworkBundle\Translation; +use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\Translation\Translator as BaseTranslator; use Symfony\Component\Translation\MessageSelector; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; /** @@ -54,8 +55,20 @@ class Translator extends BaseTranslator implements WarmableInterface * * @throws InvalidArgumentException */ - public function __construct(ContainerInterface $container, MessageSelector $selector, $loaderIds = array(), array $options = array()) + public function __construct(ContainerInterface $container, MessageSelector $selector, $defaultLocale = null, array $loaderIds = array(), array $options = array()) { + // BC 3.x, to be removed in 4.0 along with the $defaultLocale default value + if (is_array($defaultLocale) || 3 > func_num_args()) { + if (!$container instanceof SymfonyContainerInterface) { + throw new \InvalidArgumentException('Missing third $defaultLocale argument.'); + } + + $options = $loaderIds; + $loaderIds = $defaultLocale; + $defaultLocale = $container->getParameter('kernel.default_locale'); + @trigger_error(sprintf('Method %s() takes the default locale as 3rd argument since version 3.3. Not passing it is deprecated and will trigger an error in 4.0.', __METHOD__), E_USER_DEPRECATED); + } + $this->container = $container; $this->loaderIds = $loaderIds; @@ -70,7 +83,7 @@ public function __construct(ContainerInterface $container, MessageSelector $sele $this->loadResources(); } - parent::__construct($container->getParameter('kernel.default_locale'), $selector, $this->options['cache_dir'], $this->options['debug']); + parent::__construct($defaultLocale, $selector, $this->options['cache_dir'], $this->options['debug']); } /** pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy