bug #25065 [FrameworkBundle] Update translation commands to work with default paths (yceruto)
This PR was merged into the 3.4 branch.
Discussion
----------
[FrameworkBundle] Update translation commands to work with default paths
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | https://github.com/symfony/symfony/issues/25062
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/pull/8634
This should make translation commands (debug & update) work with `translator.default_path` and `twig.default_path` directories (introduced here in 3.4) and their overridden paths if available.
Would be great to include also the custom paths mapping by the user, either `translator.paths` as `twig.paths`, but I'm not sure about the right way and probably it should be implemented on another branch.
TODO
- [x] Add some tests.
Commits
-------
dc7286625b
Update translation commands to work with default paths
This commit is contained in:
commit
ec379e1541
@ -45,13 +45,17 @@ class TranslationDebugCommand extends ContainerAwareCommand
|
||||
private $translator;
|
||||
private $reader;
|
||||
private $extractor;
|
||||
private $defaultTransPath;
|
||||
private $defaultViewsPath;
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator
|
||||
* @param TranslationReaderInterface $reader
|
||||
* @param ExtractorInterface $extractor
|
||||
* @param string $defaultTransPath
|
||||
* @param string $defaultViewsPath
|
||||
*/
|
||||
public function __construct($translator = null, TranslationReaderInterface $reader = null, ExtractorInterface $extractor = null)
|
||||
public function __construct($translator = null, TranslationReaderInterface $reader = null, ExtractorInterface $extractor = null, $defaultTransPath = null, $defaultViewsPath = null)
|
||||
{
|
||||
if (!$translator instanceof TranslatorInterface) {
|
||||
@trigger_error(sprintf('%s() expects an instance of "%s" as first argument since version 3.4. Not passing it is deprecated and will throw a TypeError in 4.0.', __METHOD__, TranslatorInterface::class), E_USER_DEPRECATED);
|
||||
@ -66,6 +70,8 @@ class TranslationDebugCommand extends ContainerAwareCommand
|
||||
$this->translator = $translator;
|
||||
$this->reader = $reader;
|
||||
$this->extractor = $extractor;
|
||||
$this->defaultTransPath = $defaultTransPath;
|
||||
$this->defaultViewsPath = $defaultViewsPath;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,20 +159,34 @@ EOF
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
// Define Root Path to App folder
|
||||
$transPaths = array($kernel->getRootDir().'/Resources/');
|
||||
// Define Root Paths
|
||||
$transPaths = array($kernel->getRootDir().'/Resources/translations');
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
$viewsPaths = array($kernel->getRootDir().'/Resources/views');
|
||||
if ($this->defaultViewsPath) {
|
||||
$viewsPaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$bundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$transPaths = array(
|
||||
$bundle->getPath().'/Resources/',
|
||||
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName()),
|
||||
);
|
||||
$transPaths = array($bundle->getPath().'/Resources/translations');
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath.'/'.$bundle->getName();
|
||||
}
|
||||
$transPaths[] = sprintf('%s/Resources/%s/translations', $kernel->getRootDir(), $bundle->getName());
|
||||
$viewsPaths = array($bundle->getPath().'/Resources/views');
|
||||
if ($this->defaultViewsPath) {
|
||||
$viewsPaths[] = $this->defaultViewsPath.'/bundles/'.$bundle->getName();
|
||||
}
|
||||
$viewsPaths[] = sprintf('%s/Resources/%s/views', $kernel->getRootDir(), $bundle->getName());
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$transPaths = array($input->getArgument('bundle').'/Resources/');
|
||||
$transPaths = array($input->getArgument('bundle').'/Resources/translations');
|
||||
$viewsPaths = array($input->getArgument('bundle').'/Resources/views');
|
||||
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
|
||||
@ -174,13 +194,21 @@ EOF
|
||||
}
|
||||
} elseif ($input->getOption('all')) {
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$transPaths[] = $bundle->getPath().'/Resources/';
|
||||
$transPaths[] = sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName());
|
||||
$transPaths[] = $bundle->getPath().'/Resources/translations';
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath.'/'.$bundle->getName();
|
||||
}
|
||||
$transPaths[] = sprintf('%s/Resources/%s/translations', $kernel->getRootDir(), $bundle->getName());
|
||||
$viewsPaths[] = $bundle->getPath().'/Resources/views';
|
||||
if ($this->defaultViewsPath) {
|
||||
$viewsPaths[] = $this->defaultViewsPath.'/bundles/'.$bundle->getName();
|
||||
}
|
||||
$viewsPaths[] = sprintf('%s/Resources/%s/views', $kernel->getRootDir(), $bundle->getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Extract used messages
|
||||
$extractedCatalogue = $this->extractMessages($locale, $transPaths);
|
||||
$extractedCatalogue = $this->extractMessages($locale, $viewsPaths);
|
||||
|
||||
// Load defined messages
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $transPaths);
|
||||
@ -310,7 +338,6 @@ EOF
|
||||
{
|
||||
$extractedCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'views';
|
||||
if (is_dir($path)) {
|
||||
$this->extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
@ -329,7 +356,6 @@ EOF
|
||||
{
|
||||
$currentCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'translations';
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
}
|
||||
@ -355,7 +381,6 @@ EOF
|
||||
|
||||
$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'translations';
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $fallbackCatalogue);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Translation\Catalogue\TargetOperation;
|
||||
use Symfony\Component\Translation\Catalogue\MergeOperation;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@ -39,14 +40,18 @@ class TranslationUpdateCommand extends ContainerAwareCommand
|
||||
private $reader;
|
||||
private $extractor;
|
||||
private $defaultLocale;
|
||||
private $defaultTransPath;
|
||||
private $defaultViewsPath;
|
||||
|
||||
/**
|
||||
* @param TranslationWriterInterface $writer
|
||||
* @param TranslationReaderInterface $reader
|
||||
* @param ExtractorInterface $extractor
|
||||
* @param string $defaultLocale
|
||||
* @param string $defaultTransPath
|
||||
* @param string $defaultViewsPath
|
||||
*/
|
||||
public function __construct($writer = null, TranslationReaderInterface $reader = null, ExtractorInterface $extractor = null, $defaultLocale = null)
|
||||
public function __construct($writer = null, TranslationReaderInterface $reader = null, ExtractorInterface $extractor = null, $defaultLocale = null, $defaultTransPath = null, $defaultViewsPath = null)
|
||||
{
|
||||
if (!$writer instanceof TranslationWriterInterface) {
|
||||
@trigger_error(sprintf('%s() expects an instance of "%s" as first argument since version 3.4. Not passing it is deprecated and will throw a TypeError in 4.0.', __METHOD__, TranslationWriterInterface::class), E_USER_DEPRECATED);
|
||||
@ -62,6 +67,8 @@ class TranslationUpdateCommand extends ContainerAwareCommand
|
||||
$this->reader = $reader;
|
||||
$this->extractor = $extractor;
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
$this->defaultTransPath = $defaultTransPath;
|
||||
$this->defaultViewsPath = $defaultViewsPath;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,24 +156,39 @@ EOF
|
||||
|
||||
return 1;
|
||||
}
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
// Define Root Path to App folder
|
||||
$transPaths = array($kernel->getRootDir().'/Resources/');
|
||||
// Define Root Paths
|
||||
$transPaths = array($kernel->getRootDir().'/Resources/translations');
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
$viewsPaths = array($kernel->getRootDir().'/Resources/views');
|
||||
if ($this->defaultViewsPath) {
|
||||
$viewsPaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
$currentName = 'app folder';
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$foundBundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$transPaths = array(
|
||||
$foundBundle->getPath().'/Resources/',
|
||||
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $foundBundle->getName()),
|
||||
);
|
||||
$transPaths = array($foundBundle->getPath().'/Resources/translations');
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath.'/'.$foundBundle->getName();
|
||||
}
|
||||
$transPaths[] = sprintf('%s/Resources/%s/translations', $kernel->getRootDir(), $foundBundle->getName());
|
||||
$viewsPaths = array($foundBundle->getPath().'/Resources/views');
|
||||
if ($this->defaultViewsPath) {
|
||||
$viewsPaths[] = $this->defaultViewsPath.'/bundles/'.$foundBundle->getName();
|
||||
}
|
||||
$viewsPaths[] = sprintf('%s/Resources/%s/views', $kernel->getRootDir(), $foundBundle->getName());
|
||||
$currentName = $foundBundle->getName();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$transPaths = array($input->getArgument('bundle').'/Resources/');
|
||||
$transPaths = array($input->getArgument('bundle').'/Resources/translations');
|
||||
$viewsPaths = array($input->getArgument('bundle').'/Resources/views');
|
||||
$currentName = $transPaths[0];
|
||||
|
||||
if (!is_dir($transPaths[0])) {
|
||||
@ -188,8 +210,7 @@ EOF
|
||||
$prefix = '';
|
||||
}
|
||||
$this->extractor->setPrefix($prefix);
|
||||
foreach ($transPaths as $path) {
|
||||
$path .= 'views';
|
||||
foreach ($viewsPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
@ -199,7 +220,6 @@ EOF
|
||||
$currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
|
||||
$errorIo->comment('Loading translation files...');
|
||||
foreach ($transPaths as $path) {
|
||||
$path .= 'translations';
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
}
|
||||
@ -267,14 +287,13 @@ EOF
|
||||
|
||||
$bundleTransPath = false;
|
||||
foreach ($transPaths as $path) {
|
||||
$path .= 'translations';
|
||||
if (is_dir($path)) {
|
||||
$bundleTransPath = $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bundleTransPath) {
|
||||
$bundleTransPath = end($transPaths).'translations';
|
||||
$bundleTransPath = end($transPaths);
|
||||
}
|
||||
|
||||
$this->writer->write($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->defaultLocale));
|
||||
|
@ -78,6 +78,8 @@
|
||||
<argument type="service" id="translator" />
|
||||
<argument type="service" id="translation.reader" />
|
||||
<argument type="service" id="translation.extractor" />
|
||||
<argument>%translator.default_path%</argument>
|
||||
<argument /> <!-- %twig.default_path% -->
|
||||
<tag name="console.command" command="debug:translation" />
|
||||
</service>
|
||||
|
||||
@ -86,6 +88,8 @@
|
||||
<argument type="service" id="translation.reader" />
|
||||
<argument type="service" id="translation.extractor" />
|
||||
<argument>%kernel.default_locale%</argument>
|
||||
<argument>%translator.default_path%</argument>
|
||||
<argument /> <!-- %twig.default_path% -->
|
||||
<tag name="console.command" command="translation:update" />
|
||||
</service>
|
||||
|
||||
|
@ -64,6 +64,21 @@ class TranslationDebugCommandTest extends TestCase
|
||||
$this->assertRegExp('/unused/', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testDebugDefaultRootDirectory()
|
||||
{
|
||||
$this->fs->remove($this->translationDir);
|
||||
$this->fs = new Filesystem();
|
||||
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
|
||||
$this->fs->mkdir($this->translationDir.'/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/templates');
|
||||
|
||||
$tester = $this->createCommandTester(array('foo' => 'foo'), array('bar' => 'bar'));
|
||||
$tester->execute(array('locale' => 'en'));
|
||||
|
||||
$this->assertRegExp('/missing/', $tester->getDisplay());
|
||||
$this->assertRegExp('/unused/', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testDebugCustomDirectory()
|
||||
{
|
||||
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock();
|
||||
@ -100,6 +115,8 @@ class TranslationDebugCommandTest extends TestCase
|
||||
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
|
||||
$this->fs->mkdir($this->translationDir.'/Resources/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/Resources/views');
|
||||
$this->fs->mkdir($this->translationDir.'/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/templates');
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
@ -174,7 +191,7 @@ class TranslationDebugCommandTest extends TestCase
|
||||
->method('getContainer')
|
||||
->will($this->returnValue($this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock()));
|
||||
|
||||
$command = new TranslationDebugCommand($translator, $loader, $extractor);
|
||||
$command = new TranslationDebugCommand($translator, $loader, $extractor, $this->translationDir.'/translations', $this->translationDir.'/templates');
|
||||
|
||||
$application = new Application($kernel);
|
||||
$application->add($command);
|
||||
|
@ -31,6 +31,19 @@ class TranslationUpdateCommandTest extends TestCase
|
||||
$this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testDumpMessagesAndCleanInRootDirectory()
|
||||
{
|
||||
$this->fs->remove($this->translationDir);
|
||||
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
|
||||
$this->fs->mkdir($this->translationDir.'/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/templates');
|
||||
|
||||
$tester = $this->createCommandTester(array('messages' => array('foo' => 'foo')));
|
||||
$tester->execute(array('command' => 'translation:update', 'locale' => 'en', '--dump-messages' => true, '--clean' => true));
|
||||
$this->assertRegExp('/foo/', $tester->getDisplay());
|
||||
$this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testDumpTwoMessagesAndClean()
|
||||
{
|
||||
$tester = $this->createCommandTester(array('messages' => array('foo' => 'foo', 'bar' => 'bar')));
|
||||
@ -55,6 +68,18 @@ class TranslationUpdateCommandTest extends TestCase
|
||||
$this->assertRegExp('/Translation files were successfully updated./', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testWriteMessagesInRootDirectory()
|
||||
{
|
||||
$this->fs->remove($this->translationDir);
|
||||
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
|
||||
$this->fs->mkdir($this->translationDir.'/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/templates');
|
||||
|
||||
$tester = $this->createCommandTester(array('messages' => array('foo' => 'foo')));
|
||||
$tester->execute(array('command' => 'translation:update', 'locale' => 'en', '--force' => true));
|
||||
$this->assertRegExp('/Translation files were successfully updated./', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testWriteMessagesForSpecificDomain()
|
||||
{
|
||||
$tester = $this->createCommandTester(array('messages' => array('foo' => 'foo'), 'mydomain' => array('bar' => 'bar')));
|
||||
@ -68,6 +93,8 @@ class TranslationUpdateCommandTest extends TestCase
|
||||
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
|
||||
$this->fs->mkdir($this->translationDir.'/Resources/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/Resources/views');
|
||||
$this->fs->mkdir($this->translationDir.'/translations');
|
||||
$this->fs->mkdir($this->translationDir.'/templates');
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
@ -152,7 +179,7 @@ class TranslationUpdateCommandTest extends TestCase
|
||||
->method('getContainer')
|
||||
->will($this->returnValue($this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock()));
|
||||
|
||||
$command = new TranslationUpdateCommand($writer, $loader, $extractor, 'en');
|
||||
$command = new TranslationUpdateCommand($writer, $loader, $extractor, 'en', $this->translationDir.'/translations', $this->translationDir.'/templates');
|
||||
|
||||
$application = new Application($kernel);
|
||||
$application->add($command);
|
||||
|
@ -21,8 +21,10 @@ class TranslatorPass implements CompilerPassInterface
|
||||
private $translatorServiceId;
|
||||
private $readerServiceId;
|
||||
private $loaderTag;
|
||||
private $debugCommandServiceId;
|
||||
private $updateCommandServiceId;
|
||||
|
||||
public function __construct($translatorServiceId = 'translator.default', $readerServiceId = 'translation.loader', $loaderTag = 'translation.loader')
|
||||
public function __construct($translatorServiceId = 'translator.default', $readerServiceId = 'translation.loader', $loaderTag = 'translation.loader', $debugCommandServiceId = 'console.command.translation_debug', $updateCommandServiceId = 'console.command.translation_update')
|
||||
{
|
||||
if ('translation.loader' === $readerServiceId && 2 > func_num_args()) {
|
||||
@trigger_error('The default value for $readerServiceId will change in 4.0 to "translation.reader".', E_USER_DEPRECATED);
|
||||
@ -31,6 +33,8 @@ class TranslatorPass implements CompilerPassInterface
|
||||
$this->translatorServiceId = $translatorServiceId;
|
||||
$this->readerServiceId = $readerServiceId;
|
||||
$this->loaderTag = $loaderTag;
|
||||
$this->debugCommandServiceId = $debugCommandServiceId;
|
||||
$this->updateCommandServiceId = $updateCommandServiceId;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
@ -75,5 +79,10 @@ class TranslatorPass implements CompilerPassInterface
|
||||
->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))
|
||||
->replaceArgument(3, $loaders)
|
||||
;
|
||||
|
||||
if ($container->hasParameter('twig.default_path')) {
|
||||
$container->getDefinition($this->debugCommandServiceId)->replaceArgument(4, $container->getParameter('twig.default_path'));
|
||||
$container->getDefinition($this->updateCommandServiceId)->replaceArgument(5, $container->getParameter('twig.default_path'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user