diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index 3914faa754..434305545c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -15,6 +15,7 @@ CHANGELOG
* Added information about deprecated aliases in `debug:autowiring`
* Added php ini session options `sid_length` and `sid_bits_per_character`
to the `session` section of the configuration
+ * Added support for Translator paths, Twig paths in translation commands.
4.2.0
-----
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
index 0b284e61c0..57e364d8ff 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
@@ -50,11 +50,13 @@ class TranslationDebugCommand extends Command
private $extractor;
private $defaultTransPath;
private $defaultViewsPath;
+ private $transPaths;
+ private $viewsPaths;
/**
* @param TranslatorInterface $translator
*/
- public function __construct($translator, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultTransPath = null, string $defaultViewsPath = null)
+ public function __construct($translator, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultTransPath = null, string $defaultViewsPath = null, array $transPaths = [], array $viewsPaths = [])
{
if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
@@ -66,6 +68,8 @@ class TranslationDebugCommand extends Command
$this->extractor = $extractor;
$this->defaultTransPath = $defaultTransPath;
$this->defaultViewsPath = $defaultViewsPath;
+ $this->transPaths = $transPaths;
+ $this->viewsPaths = $viewsPaths;
}
/**
@@ -131,7 +135,7 @@ EOF
$rootDir = $kernel->getContainer()->getParameter('kernel.root_dir');
// Define Root Paths
- $transPaths = [];
+ $transPaths = $this->transPaths;
if (is_dir($dir = $rootDir.'/Resources/translations')) {
if ($dir !== $this->defaultTransPath) {
$notice = sprintf('Storing translations in the "%s" directory is deprecated since Symfony 4.2, ', $dir);
@@ -142,7 +146,7 @@ EOF
if ($this->defaultTransPath) {
$transPaths[] = $this->defaultTransPath;
}
- $viewsPaths = [];
+ $viewsPaths = $this->viewsPaths;
if (is_dir($dir = $rootDir.'/Resources/views')) {
if ($dir !== $this->defaultViewsPath) {
$notice = sprintf('Storing templates in the "%s" directory is deprecated since Symfony 4.2, ', $dir);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
index 2e1f5f0694..8045176fcc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
@@ -44,8 +44,10 @@ class TranslationUpdateCommand extends Command
private $defaultLocale;
private $defaultTransPath;
private $defaultViewsPath;
+ private $transPaths;
+ private $viewsPaths;
- public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale, string $defaultTransPath = null, string $defaultViewsPath = null)
+ public function __construct(TranslationWriterInterface $writer, TranslationReaderInterface $reader, ExtractorInterface $extractor, string $defaultLocale, string $defaultTransPath = null, string $defaultViewsPath = null, array $transPaths = [], array $viewsPaths = [])
{
parent::__construct();
@@ -55,6 +57,8 @@ class TranslationUpdateCommand extends Command
$this->defaultLocale = $defaultLocale;
$this->defaultTransPath = $defaultTransPath;
$this->defaultViewsPath = $defaultViewsPath;
+ $this->transPaths = $transPaths;
+ $this->viewsPaths = $viewsPaths;
}
/**
@@ -122,7 +126,7 @@ EOF
$rootDir = $kernel->getContainer()->getParameter('kernel.root_dir');
// Define Root Paths
- $transPaths = [];
+ $transPaths = $this->transPaths;
if (is_dir($dir = $rootDir.'/Resources/translations')) {
if ($dir !== $this->defaultTransPath) {
$notice = sprintf('Storing translations in the "%s" directory is deprecated since Symfony 4.2, ', $dir);
@@ -133,7 +137,7 @@ EOF
if ($this->defaultTransPath) {
$transPaths[] = $this->defaultTransPath;
}
- $viewsPaths = [];
+ $viewsPaths = $this->viewsPaths;
if (is_dir($dir = $rootDir.'/Resources/views')) {
if ($dir !== $this->defaultViewsPath) {
$notice = sprintf('Storing templates in the "%s" directory is deprecated since Symfony 4.2, ', $dir);
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index d022e02c4b..13d263ea62 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -1023,20 +1023,21 @@ class FrameworkExtension extends Extension
// Discover translation directories
$dirs = [];
+ $transPaths = [];
if (class_exists('Symfony\Component\Validator\Validation')) {
$r = new \ReflectionClass('Symfony\Component\Validator\Validation');
- $dirs[] = \dirname($r->getFileName()).'/Resources/translations';
+ $dirs[] = $transPaths[] = \dirname($r->getFileName()).'/Resources/translations';
}
if (class_exists('Symfony\Component\Form\Form')) {
$r = new \ReflectionClass('Symfony\Component\Form\Form');
- $dirs[] = \dirname($r->getFileName()).'/Resources/translations';
+ $dirs[] = $transPaths[] = \dirname($r->getFileName()).'/Resources/translations';
}
if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) {
$r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException');
- $dirs[] = \dirname(\dirname($r->getFileName())).'/Resources/translations';
+ $dirs[] = $transPaths[] = \dirname(\dirname($r->getFileName())).'/Resources/translations';
}
$defaultDir = $container->getParameterBag()->resolveValue($config['default_path']);
$rootDir = $container->getParameter('kernel.root_dir');
@@ -1053,11 +1054,13 @@ class FrameworkExtension extends Extension
foreach ($config['paths'] as $dir) {
if ($container->fileExists($dir)) {
- $dirs[] = $dir;
+ $dirs[] = $transPaths[] = $dir;
} else {
throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir));
}
}
+ $container->getDefinition('console.command.translation_debug')->replaceArgument(5, $transPaths);
+ $container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths);
if ($container->fileExists($defaultDir)) {
$dirs[] = $defaultDir;
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index c3977c399d..ef6013a323 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -105,7 +105,9 @@ class FrameworkBundle extends Bundle
$container->addCompilerPass(new AddAnnotationsCachedReaderPass(), PassConfig::TYPE_AFTER_REMOVING, -255);
$this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class);
$this->addCompilerPassIfExists($container, AddConsoleCommandPass::class, PassConfig::TYPE_BEFORE_REMOVING);
- $this->addCompilerPassIfExists($container, TranslatorPass::class);
+ // must be registered as late as possible to get access to all Twig paths registered in
+ // twig.template_iterator definition
+ $this->addCompilerPassIfExists($container, TranslatorPass::class, PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
$container->addCompilerPass(new LoggingTranslatorPass());
$container->addCompilerPass(new AddExpressionLanguageProvidersPass(false));
$this->addCompilerPassIfExists($container, TranslationExtractorPass::class);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml
index 9c5da8e177..3d9f3a8188 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml
@@ -101,6 +101,8 @@
%translator.default_path%
+
+
@@ -111,6 +113,8 @@
%kernel.default_locale%
%translator.default_path%
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php
index 400f994d2f..ba11f53f3a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php
@@ -90,7 +90,7 @@ class TranslationDebugCommandTest extends TestCase
$this->fs->mkdir($this->translationDir.'/translations');
$this->fs->mkdir($this->translationDir.'/templates');
- $tester = $this->createCommandTester(['foo' => 'foo'], ['bar' => 'bar']);
+ $tester = $this->createCommandTester(['foo' => 'foo'], ['bar' => 'bar'], null, [$this->translationDir.'/trans'], [$this->translationDir.'/views']);
$tester->execute(['locale' => 'en']);
$this->assertRegExp('/missing/', $tester->getDisplay());
@@ -145,7 +145,7 @@ class TranslationDebugCommandTest extends TestCase
/**
* @return CommandTester
*/
- private function createCommandTester($extractedMessages = [], $loadedMessages = [], $kernel = null)
+ private function createCommandTester($extractedMessages = [], $loadedMessages = [], $kernel = null, array $transPaths = [], array $viewsPaths = [])
{
$translator = $this->getMockBuilder('Symfony\Component\Translation\Translator')
->disableOriginalConstructor()
@@ -207,7 +207,7 @@ class TranslationDebugCommandTest extends TestCase
->method('getContainer')
->will($this->returnValue($container));
- $command = new TranslationDebugCommand($translator, $loader, $extractor, $this->translationDir.'/translations', $this->translationDir.'/templates');
+ $command = new TranslationDebugCommand($translator, $loader, $extractor, $this->translationDir.'/translations', $this->translationDir.'/templates', $transPaths, $viewsPaths);
$application = new Application($kernel);
$application->add($command);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
index b1a957201f..c1bfd0004e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
@@ -39,7 +39,7 @@ class TranslationUpdateCommandTest extends TestCase
$this->fs->mkdir($this->translationDir.'/translations');
$this->fs->mkdir($this->translationDir.'/templates');
- $tester = $this->createCommandTester(['messages' => ['foo' => 'foo']]);
+ $tester = $this->createCommandTester(['messages' => ['foo' => 'foo']], [], null, [$this->translationDir.'/trans'], [$this->translationDir.'/views']);
$tester->execute(['command' => 'translation:update', 'locale' => 'en', '--dump-messages' => true, '--clean' => true]);
$this->assertRegExp('/foo/', $tester->getDisplay());
$this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay());
@@ -121,7 +121,7 @@ class TranslationUpdateCommandTest extends TestCase
/**
* @return CommandTester
*/
- private function createCommandTester($extractedMessages = [], $loadedMessages = [], HttpKernel\KernelInterface $kernel = null)
+ private function createCommandTester($extractedMessages = [], $loadedMessages = [], HttpKernel\KernelInterface $kernel = null, array $transPaths = [], array $viewsPaths = [])
{
$translator = $this->getMockBuilder('Symfony\Component\Translation\Translator')
->disableOriginalConstructor()
@@ -197,7 +197,7 @@ class TranslationUpdateCommandTest extends TestCase
->method('getContainer')
->will($this->returnValue($container));
- $command = new TranslationUpdateCommand($writer, $loader, $extractor, 'en', $this->translationDir.'/translations', $this->translationDir.'/templates');
+ $command = new TranslationUpdateCommand($writer, $loader, $extractor, 'en', $this->translationDir.'/translations', $this->translationDir.'/templates', $transPaths, $viewsPaths);
$application = new Application($kernel);
$application->add($command);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TranslationDebugPass.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TranslationDebugPass.php
new file mode 100644
index 0000000000..b8b53c2504
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TranslationDebugPass.php
@@ -0,0 +1,21 @@
+hasDefinition('console.command.translation_debug')) {
+ // skipping the /Resources/views path deprecation
+ $container->getDefinition('console.command.translation_debug')
+ ->setArgument(4, '%kernel.project_dir%/Resources/views');
+ }
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php
index 83dd4dc781..d90041213c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php
@@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle;
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\AnnotationReaderPass;
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\Config\CustomConfig;
+use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\TranslationDebugPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -29,5 +30,6 @@ class TestBundle extends Bundle
$extension->setCustomConfig(new CustomConfig());
$container->addCompilerPass(new AnnotationReaderPass(), PassConfig::TYPE_AFTER_REMOVING);
+ $container->addCompilerPass(new TranslationDebugPass());
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php
new file mode 100644
index 0000000000..ebc485fa3a
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
+
+use Symfony\Bundle\FrameworkBundle\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+
+/**
+ * @group functional
+ */
+class TranslationDebugCommandTest extends WebTestCase
+{
+ private $application;
+
+ protected function setUp()
+ {
+ $kernel = static::createKernel(['test_case' => 'TransDebug', 'root_config' => 'config.yml']);
+ $this->application = new Application($kernel);
+ }
+
+ public function testDumpAllTrans()
+ {
+ $tester = $this->createCommandTester();
+ $ret = $tester->execute(['locale' => 'en']);
+
+ $this->assertSame(0, $ret, 'Returns 0 in case of success');
+ $this->assertContains('unused validators This value should be blank.', $tester->getDisplay());
+ $this->assertContains('unused security Invalid CSRF token.', $tester->getDisplay());
+ }
+
+ private function createCommandTester(): CommandTester
+ {
+ $command = $this->application->find('debug:translation');
+
+ return new CommandTester($command);
+ }
+}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/bundles.php
new file mode 100644
index 0000000000..15ff182c6f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/bundles.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
+
+return [
+ new FrameworkBundle(),
+ new TestBundle(),
+];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml
new file mode 100644
index 0000000000..6f52f7404f
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml
@@ -0,0 +1,13 @@
+imports:
+ - { resource: ../config/default.yml }
+
+framework:
+ secret: '%secret%'
+ default_locale: '%env(LOCALE)%'
+ translator:
+ fallbacks:
+ - '%env(LOCALE)%'
+
+parameters:
+ env(LOCALE): en
+ secret: test
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 273788a925..5ed9bc5cc5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -74,7 +74,7 @@
"symfony/property-info": "<3.4",
"symfony/serializer": "<4.2",
"symfony/stopwatch": "<3.4",
- "symfony/translation": "<4.2",
+ "symfony/translation": "<4.3",
"symfony/twig-bridge": "<4.1.1",
"symfony/validator": "<4.1",
"symfony/workflow": "<4.1"
diff --git a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php
index fc1c08fc32..655e7ae988 100644
--- a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php
+++ b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php
@@ -68,12 +68,16 @@ class TranslatorPass implements CompilerPassInterface
return;
}
+ $paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(2));
if ($container->hasDefinition($this->debugCommandServiceId)) {
- $container->getDefinition($this->debugCommandServiceId)->replaceArgument(4, $container->getParameter('twig.default_path'));
+ $definition = $container->getDefinition($this->debugCommandServiceId);
+ $definition->replaceArgument(4, $container->getParameter('twig.default_path'));
+ $definition->replaceArgument(6, $paths);
}
-
if ($container->hasDefinition($this->updateCommandServiceId)) {
- $container->getDefinition($this->updateCommandServiceId)->replaceArgument(5, $container->getParameter('twig.default_path'));
+ $definition = $container->getDefinition($this->updateCommandServiceId);
+ $definition->replaceArgument(5, $container->getParameter('twig.default_path'));
+ $definition->replaceArgument(7, $paths);
}
}
}
diff --git a/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php b/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php
index 8b9c03d991..d054152ce6 100644
--- a/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php
+++ b/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php
@@ -54,4 +54,32 @@ class TranslationPassTest extends TestCase
$expected = ['translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader'))];
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
}
+
+ public function testValidCommandsViewPathsArgument()
+ {
+ $container = new ContainerBuilder();
+ $container->register('translator.default')
+ ->setArguments([null, null, null, null])
+ ;
+ $debugCommand = $container->register('console.command.translation_debug')
+ ->setArguments([null, null, null, null, null, [], []])
+ ;
+ $updateCommand = $container->register('console.command.translation_update')
+ ->setArguments([null, null, null, null, null, null, [], []])
+ ;
+ $container->register('twig.template_iterator')
+ ->setArguments([null, null, ['other/templates' => null, 'tpl' => 'App']])
+ ;
+ $container->setParameter('twig.default_path', 'templates');
+
+ $pass = new TranslatorPass('translator.default');
+ $pass->process($container);
+
+ $expectedViewPaths = ['other/templates', 'tpl'];
+
+ $this->assertSame('templates', $debugCommand->getArgument(4));
+ $this->assertSame('templates', $updateCommand->getArgument(5));
+ $this->assertSame($expectedViewPaths, $debugCommand->getArgument(6));
+ $this->assertSame($expectedViewPaths, $updateCommand->getArgument(7));
+ }
}