Create an interface for TranslationReader and moved TranslationLoader to Translation component

This commit is contained in:
Tobias Nyholm 2017-07-25 20:07:39 +02:00
parent 660feccb20
commit 5bc50da677
No known key found for this signature in database
GPG Key ID: B14C3A029D1831F6
17 changed files with 232 additions and 77 deletions

View File

@ -114,6 +114,12 @@ FrameworkBundle
class has been deprecated and will be removed in 4.0. Use the
`Symfony\Component\Translation\DependencyInjection\TranslatorPass` class instead.
* The `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`
class has been deprecated and will be removed in 4.0. Use the
`Symfony\Component\Translation\Reader\TranslationReader` class instead.
* The `translation.loader` service has been deprecated and will be removed in 4.0. Use the `translation.reader` service instead.
HttpKernel
----------

View File

@ -414,7 +414,13 @@ FrameworkBundle
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass`
class has been removed. Use the
`Symfony\Component\Translation\DependencyInjection\TranslatorPass` class instead.
* The `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`
class has been deprecated and will be removed in 4.0. Use the
`Symfony\Component\Translation\Reader\TranslationReader` class instead.
* The `translation.loader` service has been deprecated and will be removed in 4.0. Use the `translation.reader` service instead.
HttpFoundation
--------------
@ -581,6 +587,8 @@ Translation
* Removed the backup feature from the file dumper classes.
* The default value of the `$readerServiceId` argument of `TranslatorPass::__construct()` has been changed to `"translation.reader"`.
* Removed `Symfony\Component\Translation\Writer\TranslationWriter::writeTranslations`,
use `Symfony\Component\Translation\Writer\TranslationWriter::write` instead.

View File

@ -23,6 +23,9 @@ CHANGELOG
name as value, using it makes the command lazy
* Added `cache:pool:prune` command to allow manual stale cache item pruning of supported PSR-6 and PSR-16 cache pool
implementations
* Deprecated `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`, use
`Symfony\Component\Translation\Reader\TranslationReader` instead
* Deprecated `translation.loader` service, use `translation.reader` instead
3.3.0
-----

View File

@ -11,7 +11,6 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
@ -21,6 +20,7 @@ use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Translation\Catalogue\MergeOperation;
use Symfony\Component\Translation\Extractor\ExtractorInterface;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\DataCollectorTranslator;
use Symfony\Component\Translation\LoggingTranslator;
@ -43,15 +43,15 @@ class TranslationDebugCommand extends ContainerAwareCommand
protected static $defaultName = 'debug:translation';
private $translator;
private $loader;
private $reader;
private $extractor;
/**
* @param TranslatorInterface $translator
* @param TranslationLoader $loader
* @param ExtractorInterface $extractor
* @param TranslatorInterface $translator
* @param TranslationReaderInterface $reader
* @param ExtractorInterface $extractor
*/
public function __construct($translator = null, TranslationLoader $loader = null, ExtractorInterface $extractor = null)
public function __construct($translator = null, TranslationReaderInterface $reader = null, ExtractorInterface $extractor = null)
{
if (!$translator instanceof TranslatorInterface) {
@trigger_error(sprintf('Passing a command name as the first argument of "%s" is deprecated since version 3.4 and will be removed in 4.0. If the command was registered by convention, make it a service instead.', __METHOD__), E_USER_DEPRECATED);
@ -64,7 +64,7 @@ class TranslationDebugCommand extends ContainerAwareCommand
parent::__construct();
$this->translator = $translator;
$this->loader = $loader;
$this->reader = $reader;
$this->extractor = $extractor;
}
@ -142,7 +142,7 @@ EOF
// BC to be removed in 4.0
if (null === $this->translator) {
$this->translator = $this->getContainer()->get('translator');
$this->loader = $this->getContainer()->get('translation.loader');
$this->reader = $this->getContainer()->get('translation.reader');
$this->extractor = $this->getContainer()->get('translation.extractor');
}
@ -331,7 +331,7 @@ EOF
foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$this->loader->loadMessages($path, $currentCatalogue);
$this->reader->read($path, $currentCatalogue);
}
}
@ -357,7 +357,7 @@ EOF
foreach ($transPaths as $path) {
$path = $path.'translations';
if (is_dir($path)) {
$this->loader->loadMessages($path, $fallbackCatalogue);
$this->reader->read($path, $fallbackCatalogue);
}
}
$fallbackCatalogues[] = $fallbackCatalogue;

View File

@ -11,7 +11,6 @@
namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Translation\Catalogue\TargetOperation;
use Symfony\Component\Translation\Catalogue\MergeOperation;
@ -21,6 +20,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Translation\Extractor\ExtractorInterface;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
use Symfony\Component\Translation\Writer\TranslationWriterInterface;
/**
@ -36,17 +36,17 @@ class TranslationUpdateCommand extends ContainerAwareCommand
protected static $defaultName = 'translation:update';
private $writer;
private $loader;
private $reader;
private $extractor;
private $defaultLocale;
/**
* @param TranslationWriterInterface $writer
* @param TranslationLoader $loader
* @param TranslationReaderInterface $reader
* @param ExtractorInterface $extractor
* @param string $defaultLocale
*/
public function __construct($writer = null, TranslationLoader $loader = null, ExtractorInterface $extractor = null, $defaultLocale = null)
public function __construct($writer = null, TranslationReaderInterface $reader = null, ExtractorInterface $extractor = null, $defaultLocale = null)
{
if (!$writer instanceof TranslationWriterInterface) {
@trigger_error(sprintf('Passing a command name as the first argument of "%s" is deprecated since version 3.4 and will be removed in 4.0. If the command was registered by convention, make it a service instead.', __METHOD__), E_USER_DEPRECATED);
@ -59,7 +59,7 @@ class TranslationUpdateCommand extends ContainerAwareCommand
parent::__construct();
$this->writer = $writer;
$this->loader = $loader;
$this->reader = $reader;
$this->extractor = $extractor;
$this->defaultLocale = $defaultLocale;
}
@ -127,7 +127,7 @@ EOF
// BC to be removed in 4.0
if (null === $this->writer) {
$this->writer = $this->getContainer()->get('translation.writer');
$this->loader = $this->getContainer()->get('translation.loader');
$this->reader = $this->getContainer()->get('translation.reader');
$this->extractor = $this->getContainer()->get('translation.extractor');
$this->defaultLocale = $this->getContainer()->getParameter('kernel.default_locale');
}
@ -201,7 +201,7 @@ EOF
foreach ($transPaths as $path) {
$path .= 'translations';
if (is_dir($path)) {
$this->loader->loadMessages($path, $currentCatalogue);
$this->reader->read($path, $currentCatalogue);
}
}

View File

@ -96,7 +96,10 @@ class FrameworkBundle extends Bundle
$container->addCompilerPass(new AddAnnotationsCachedReaderPass(), PassConfig::TYPE_BEFORE_REMOVING);
$this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class);
$this->addCompilerPassIfExists($container, AddConsoleCommandPass::class);
$this->addCompilerPassIfExists($container, TranslatorPass::class);
if (class_exists(TranslatorPass::class)) {
// Arguments to be removed in 4.0, relying on the default values
$container->addCompilerPass(new TranslatorPass('translator.default', 'translation.loader'));
}
$container->addCompilerPass(new LoggingTranslatorPass());
$container->addCompilerPass(new AddCacheWarmerPass());
$container->addCompilerPass(new AddCacheClearerPass());

View File

@ -121,7 +121,10 @@
<tag name="translation.extractor" alias="php" />
</service>
<service id="translation.loader" class="Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader" public="true" />
<service id="translation.loader" class="Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader" public="true">
<deprecated>The "%service_id%" service is deprecated since Symfony 3.4 and will be removed in 4.0. Use "translation.reader" instead.</deprecated>
</service>
<service id="translation.reader" class="Symfony\Component\Translation\Reader\TranslationReader" public="true" />
<service id="translation.extractor" class="Symfony\Component\Translation\Extractor\ChainExtractor" public="true" />

View File

@ -130,10 +130,10 @@ class TranslationDebugCommandTest extends TestCase
})
);
$loader = $this->getMockBuilder('Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader')->getMock();
$loader = $this->getMockBuilder('Symfony\Component\Translation\Reader\TranslationReader')->getMock();
$loader
->expects($this->any())
->method('loadMessages')
->method('read')
->will(
$this->returnCallback(function ($path, $catalogue) use ($loadedMessages) {
$catalogue->add($loadedMessages);
@ -197,7 +197,7 @@ class TranslationDebugCommandTest extends TestCase
->method('get')
->will($this->returnValueMap(array(
array('translation.extractor', 1, $extractor),
array('translation.loader', 1, $loader),
array('translation.reader', 1, $loader),
array('translator', 1, $translator),
array('kernel', 1, $kernel),
)));

View File

@ -101,10 +101,10 @@ class TranslationUpdateCommandTest extends TestCase
})
);
$loader = $this->getMockBuilder('Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader')->getMock();
$loader = $this->getMockBuilder('Symfony\Component\Translation\Reader\TranslationReader')->getMock();
$loader
->expects($this->any())
->method('loadMessages')
->method('read')
->will(
$this->returnCallback(function ($path, $catalogue) use ($loadedMessages) {
$catalogue->add($loadedMessages);
@ -177,7 +177,7 @@ class TranslationUpdateCommandTest extends TestCase
->method('get')
->will($this->returnValueMap(array(
array('translation.extractor', 1, $extractor),
array('translation.loader', 1, $loader),
array('translation.reader', 1, $loader),
array('translation.writer', 1, $writer),
array('translator', 1, $translator),
array('kernel', 1, $kernel),

View File

@ -1000,7 +1000,7 @@ abstract class FrameworkExtensionTest extends TestCase
$container->getCompilerPassConfig()->setOptimizationPasses(array());
$container->getCompilerPassConfig()->setRemovingPasses(array());
}
$container->getCompilerPassConfig()->setBeforeRemovingPasses(array(new AddAnnotationsCachedReaderPass(), new AddConstraintValidatorsPass(), new TranslatorPass()));
$container->getCompilerPassConfig()->setBeforeRemovingPasses(array(new AddAnnotationsCachedReaderPass(), new AddConstraintValidatorsPass(), new TranslatorPass('translator.default', 'translation.reader')));
$container->compile();
return self::$containerCache[$cacheKey] = $container;

View File

@ -11,35 +11,16 @@
namespace Symfony\Bundle\FrameworkBundle\Translation;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Translation\Reader\TranslationReader;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Loader\LoaderInterface;
@trigger_error(sprintf('The class "%s" is deprecated since version 3.4 and will be removed in 4.0. Use "%s" instead. ', TranslationLoader::class, TranslationReader::class), E_USER_DEPRECATED);
/**
* TranslationLoader loads translation messages from translation files.
*
* @author Michel Salib <michelsalib@hotmail.com>
* @deprecated since version 3.4 and will be removed in 4.0. Use Symfony\Component\Translation\Reader\TranslationReader instead
*/
class TranslationLoader
class TranslationLoader extends TranslationReader
{
/**
* Loaders used for import.
*
* @var array
*/
private $loaders = array();
/**
* Adds a loader to the translation extractor.
*
* @param string $format The format of the loader
* @param LoaderInterface $loader
*/
public function addLoader($format, LoaderInterface $loader)
{
$this->loaders[$format] = $loader;
}
/**
* Loads translation messages from a directory to the catalogue.
*
@ -48,19 +29,6 @@ class TranslationLoader
*/
public function loadMessages($directory, MessageCatalogue $catalogue)
{
if (!is_dir($directory)) {
return;
}
foreach ($this->loaders as $format => $loader) {
// load any existing translation files
$finder = new Finder();
$extension = $catalogue->getLocale().'.'.$format;
$files = $finder->files()->name('*.'.$extension)->in($directory);
foreach ($files as $file) {
$domain = substr($file->getFilename(), 0, -1 * strlen($extension) - 1);
$catalogue->addCatalogue($loader->load($file->getPathname(), $catalogue->getLocale(), $domain));
}
}
$this->read($directory, $catalogue);
}
}

View File

@ -7,6 +7,7 @@ CHANGELOG
* Added `TranslationDumperPass`
* Added `TranslationExtractorPass`
* Added `TranslatorPass`
* Added `TranslationReader` and `TranslationReaderInterface`
* Added `<notes>` section to the Xliff 2.0 dumper.
* Improved Xliff 2.0 loader to load `<notes>` section.
* Added `TranslationWriterInterface`

View File

@ -19,13 +19,17 @@ use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
class TranslatorPass implements CompilerPassInterface
{
private $translatorServiceId;
private $loaderServiceId;
private $readerServiceId;
private $loaderTag;
public function __construct($translatorServiceId = 'translator.default', $loaderServiceId = 'translation.loader', $loaderTag = 'translation.loader')
public function __construct($translatorServiceId = 'translator.default', $readerServiceId = 'translation.loader', $loaderTag = 'translation.loader')
{
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);
}
$this->translatorServiceId = $translatorServiceId;
$this->loaderServiceId = $loaderServiceId;
$this->readerServiceId = $readerServiceId;
$this->loaderTag = $loaderTag;
}
@ -45,8 +49,8 @@ class TranslatorPass implements CompilerPassInterface
}
}
if ($container->hasDefinition($this->loaderServiceId)) {
$definition = $container->getDefinition($this->loaderServiceId);
if ($container->hasDefinition($this->readerServiceId)) {
$definition = $container->getDefinition($this->readerServiceId);
foreach ($loaders as $id => $formats) {
foreach ($formats as $format) {
$definition->addMethodCall('addLoader', array($format, $loaderRefs[$id]));
@ -54,6 +58,18 @@ class TranslatorPass implements CompilerPassInterface
}
}
// Duplicated code to support "translation.reader", to be removed in 4.0
if ('translation.reader' !== $this->readerServiceId) {
if ($container->hasDefinition('translation.reader')) {
$definition = $container->getDefinition('translation.reader');
foreach ($loaders as $id => $formats) {
foreach ($formats as $format) {
$definition->addMethodCall('addLoader', array($format, $loaderRefs[$id]));
}
}
}
}
$container
->findDefinition($this->translatorServiceId)
->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))

View File

@ -0,0 +1,63 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Reader;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Translation\Loader\LoaderInterface;
use Symfony\Component\Translation\MessageCatalogue;
/**
* TranslationReader reads translation messages from translation files.
*
* @author Michel Salib <michelsalib@hotmail.com>
*/
class TranslationReader implements TranslationReaderInterface
{
/**
* Loaders used for import.
*
* @var array
*/
private $loaders = array();
/**
* Adds a loader to the translation extractor.
*
* @param string $format The format of the loader
* @param LoaderInterface $loader
*/
public function addLoader($format, LoaderInterface $loader)
{
$this->loaders[$format] = $loader;
}
/**
* {@inheritdoc}
*/
public function read($directory, MessageCatalogue $catalogue)
{
if (!is_dir($directory)) {
return;
}
foreach ($this->loaders as $format => $loader) {
// load any existing translation files
$finder = new Finder();
$extension = $catalogue->getLocale().'.'.$format;
$files = $finder->files()->name('*.'.$extension)->in($directory);
foreach ($files as $file) {
$domain = substr($file->getFilename(), 0, -1 * strlen($extension) - 1);
$catalogue->addCatalogue($loader->load($file->getPathname(), $catalogue->getLocale(), $domain));
}
}
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Reader;
use Symfony\Component\Translation\MessageCatalogue;
/**
* TranslationReader reads translation messages from translation files.
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
interface TranslationReaderInterface
{
/**
* Reads translation messages from a directory to the catalogue.
*
* @param string $directory
* @param MessageCatalogue $catalogue
*/
public function read($directory, MessageCatalogue $catalogue);
}

View File

@ -25,26 +25,79 @@ class TranslationPassTest extends TestCase
$loader = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'));
$reader = new Definition();
$translator = (new Definition())
->setArguments(array(null, null, null, null));
$container = new ContainerBuilder();
$container->setDefinition('translator.default', $translator);
$container->setDefinition('translation.loader', $loader);
$container->setDefinition('translation.reader', $reader);
$container->setDefinition('translation.xliff_loader', $loader);
$pass = new TranslatorPass('translator.default', 'translation.reader');
$pass->process($container);
$expectedReader = (new Definition())
->addMethodCall('addLoader', array('xliff', new Reference('translation.xliff_loader')))
->addMethodCall('addLoader', array('xlf', new Reference('translation.xliff_loader')))
;
$this->assertEquals($expectedReader, $reader);
$expectedLoader = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'))
;
$this->assertEquals($expectedLoader, $loader);
$this->assertSame(array('translation.xliff_loader' => array('xliff', 'xlf')), $translator->getArgument(3));
$expected = array('translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader')));
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
}
/**
* @group legacy
* @expectedDeprecation The default value for $readerServiceId will change in 4.0 to "translation.reader".
*
* A test that verifies the deprecated "translation.loader" gets the LoaderInterfaces added.
*
* This test should be removed in 4.0.
*/
public function testValidCollectorWithDeprecatedTranslationLoader()
{
$loader = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'));
$legacyReader = new Definition();
$reader = new Definition();
$translator = (new Definition())
->setArguments(array(null, null, null, null));
$container = new ContainerBuilder();
$container->setDefinition('translator.default', $translator);
$container->setDefinition('translation.loader', $legacyReader);
$container->setDefinition('translation.reader', $reader);
$container->setDefinition('translation.xliff_loader', $loader);
$pass = new TranslatorPass();
$pass->process($container);
$expected = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'))
->addMethodCall('addLoader', array('xliff', new Reference('translation.loader')))
->addMethodCall('addLoader', array('xlf', new Reference('translation.loader')))
$expectedReader = (new Definition())
->addMethodCall('addLoader', array('xliff', new Reference('translation.xliff_loader')))
->addMethodCall('addLoader', array('xlf', new Reference('translation.xliff_loader')))
;
$this->assertEquals($expected, $loader);
$this->assertEquals($expectedReader, $legacyReader);
$this->assertEquals($expectedReader, $reader);
$this->assertSame(array('translation.loader' => array('xliff', 'xlf')), $translator->getArgument(3));
$expectedLoader = (new Definition())
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'))
;
$this->assertEquals($expectedLoader, $loader);
$expected = array('translation.loader' => new ServiceClosureArgument(new Reference('translation.loader')));
$this->assertSame(array('translation.xliff_loader' => array('xliff', 'xlf')), $translator->getArgument(3));
$expected = array('translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader')));
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
}
}

View File

@ -24,6 +24,7 @@
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/intl": "^2.8.18|^3.2.5|~4.0",
"symfony/yaml": "~3.3|~4.0",
"symfony/finder": "~2.8|~3.0|~4.0",
"psr/log": "~1.0"
},
"conflict": {