diff --git a/UPGRADE-3.4.md b/UPGRADE-3.4.md index 20114937efc2..9a3a74dd6165 100644 --- a/UPGRADE-3.4.md +++ b/UPGRADE-3.4.md @@ -234,6 +234,27 @@ Translation and will be removed in 4.0, use `Symfony\Component\Translation\Writer\TranslationWriter::write` instead. + * Passing a `Symfony\Component\Translation\MessageSelector` to `Translator` has been + deprecated. You should pass a message formatter instead + + Before: + + ```php + use Symfony\Component\Translation\Translator; + use Symfony\Component\Translation\MessageSelector; + + $translator = new Translator('fr_FR', new MessageSelector()); + ``` + + After: + + ```php + use Symfony\Component\Translation\Translator; + use Symfony\Component\Translation\Formatter\MessageFormatter; + + $translator = new Translator('fr_FR', new MessageFormatter()); + ``` + TwigBridge ---------- diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 5d404598f7ec..9dffe96789b9 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -643,6 +643,9 @@ Translation * Removed `Symfony\Component\Translation\Writer\TranslationWriter::writeTranslations`, use `Symfony\Component\Translation\Writer\TranslationWriter::write` instead. + * Removed support for passing `Symfony\Component\Translation\MessageSelector` as a second argument to the + `Translator::__construct()`. You should pass an instance of `Symfony\Component\Translation\Formatter\MessageFormatterInterface` instead. + TwigBundle ---------- diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index 36016d7f49bc..b20e0c3905a3 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -14,7 +14,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Twig\Extension\TranslationExtension; use Symfony\Component\Translation\Translator; -use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\Loader\ArrayLoader; use Twig\Environment; use Twig\Loader\ArrayLoader as TwigArrayLoader; @@ -37,7 +36,7 @@ public function testTrans($template, $expected, array $variables = array()) echo $template."\n"; $loader = new TwigArrayLoader(array('index' => $template)); $twig = new Environment($loader, array('debug' => true, 'cache' => false)); - $twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector()))); + $twig->addExtension(new TranslationExtension(new Translator('en'))); echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSourceContext('index'))))."\n\n"; $this->assertEquals($expected, $this->getTemplate($template)->render($variables)); @@ -139,7 +138,7 @@ public function testDefaultTranslationDomain() ', ); - $translator = new Translator('en', new MessageSelector()); + $translator = new Translator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foo (messages)'), 'en'); $translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom'); @@ -172,7 +171,7 @@ public function testDefaultTranslationDomainWithNamedArguments() ', ); - $translator = new Translator('en', new MessageSelector()); + $translator = new Translator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foo (messages)'), 'en'); $translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom'); @@ -187,7 +186,7 @@ public function testDefaultTranslationDomainWithNamedArguments() protected function getTemplate($template, $translator = null) { if (null === $translator) { - $translator = new Translator('en', new MessageSelector()); + $translator = new Translator('en'); } if (is_array($template)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index a9c5ec462dcd..2fce9b2ad4ae 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -668,6 +668,7 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode) ->defaultValue(array('en')) ->end() ->booleanNode('logging')->defaultValue($this->debug)->end() + ->scalarNode('formatter')->defaultValue('translator.formatter.default')->end() ->arrayNode('paths') ->prototype('scalar')->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 72d66442c62c..9b3a071168a5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1075,6 +1075,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder // Use the "real" translator instead of the identity default $container->setAlias('translator', 'translator.default'); + $container->setAlias('translator.formatter', new Alias($config['formatter'], false)); $translator = $container->findDefinition('translator.default'); $translator->addMethodCall('setFallbackLocales', array($config['fallbacks'])); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 481c469e3616..f63f93723029 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -184,6 +184,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml index cfe05f5148fd..d8c8f1e03011 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml @@ -9,7 +9,7 @@ - + %kernel.default_locale% @@ -28,6 +28,10 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 1835625da861..e4e6f0f2a7be 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -255,6 +255,7 @@ protected static function getBundleDefaultConfig() 'enabled' => !class_exists(FullStack::class), 'fallbacks' => array('en'), 'logging' => true, + 'formatter' => 'translator.formatter.default', 'paths' => array(), ), 'validation' => array( diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index 6d710a76e881..d2d0f878f642 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -14,9 +14,9 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Translation\Translator; +use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Translation\MessageSelector; class TranslatorTest extends TestCase { @@ -149,7 +149,7 @@ public function testGetDefaultLocaleOmittingLocale() ->with('kernel.default_locale') ->will($this->returnValue('en')) ; - $translator = new Translator($container, new MessageSelector()); + $translator = new Translator($container, new MessageFormatter()); $this->assertSame('en', $translator->getLocale()); } @@ -162,7 +162,7 @@ public function testGetDefaultLocaleOmittingLocale() public function testGetDefaultLocaleOmittingLocaleWithPsrContainer() { $container = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $translator = new Translator($container, new MessageSelector()); + $translator = new Translator($container, new MessageFormatter()); } /** @@ -277,7 +277,7 @@ public function testLoadResourcesWithoutCaching() public function testGetDefaultLocale() { $container = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $translator = new Translator($container, new MessageSelector(), 'en'); + $translator = new Translator($container, new MessageFormatter(), 'en'); $this->assertSame('en', $translator->getLocale()); } @@ -290,7 +290,7 @@ public function testInvalidOptions() { $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); - (new Translator($container, new MessageSelector(), 'en', array(), array('foo' => 'bar'))); + (new Translator($container, new MessageFormatter(), 'en', array(), array('foo' => 'bar'))); } /** @dataProvider getDebugModeAndCacheDirCombinations */ @@ -468,7 +468,7 @@ private function createTranslator($loader, $options, $translatorClass = '\Symfon if (null === $defaultLocale) { return new $translatorClass( $this->getContainer($loader), - new MessageSelector(), + new MessageFormatter(), array($loaderFomat => array($loaderFomat)), $options ); @@ -476,7 +476,7 @@ private function createTranslator($loader, $options, $translatorClass = '\Symfon return new $translatorClass( $this->getContainer($loader), - new MessageSelector(), + new MessageFormatter(), $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 d18a3b81f04e..2b41d5af61db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -15,8 +15,8 @@ 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\Translation\Exception\InvalidArgumentException; +use Symfony\Component\Translation\Formatter\MessageFormatterInterface; /** * Translator. @@ -56,15 +56,15 @@ class Translator extends BaseTranslator implements WarmableInterface * * debug: Whether to enable debugging or not (false by default) * * resource_files: List of translation resources available grouped by locale. * - * @param ContainerInterface $container A ContainerInterface instance - * @param MessageSelector $selector The message selector for pluralization - * @param string $defaultLocale - * @param array $loaderIds An array of loader Ids - * @param array $options An array of options + * @param ContainerInterface $container A ContainerInterface instance + * @param MessageFormatterInterface $formatter The message formatter + * @param string $defaultLocale + * @param array $loaderIds An array of loader Ids + * @param array $options An array of options * * @throws InvalidArgumentException */ - public function __construct(ContainerInterface $container, MessageSelector $selector, $defaultLocale = null, array $loaderIds = array(), array $options = array()) + public function __construct(ContainerInterface $container, $formatter, $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()) { @@ -90,7 +90,7 @@ public function __construct(ContainerInterface $container, MessageSelector $sele $this->resourceLocales = array_keys($this->options['resource_files']); $this->addResourceFiles($this->options['resource_files']); - parent::__construct($defaultLocale, $selector, $this->options['cache_dir'], $this->options['debug']); + parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug']); } /** diff --git a/src/Symfony/Component/Translation/CHANGELOG.md b/src/Symfony/Component/Translation/CHANGELOG.md index cdd11cb91be6..24753841cadb 100644 --- a/src/Symfony/Component/Translation/CHANGELOG.md +++ b/src/Symfony/Component/Translation/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG * Improved Xliff 2.0 loader to load `` section. * Added `TranslationWriterInterface` * Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write` + * added support for adding custom message formatter and decoupling the default one. 3.2.0 ----- diff --git a/src/Symfony/Component/Translation/Formatter/ChoiceMessageFormatterInterface.php b/src/Symfony/Component/Translation/Formatter/ChoiceMessageFormatterInterface.php new file mode 100644 index 000000000000..92acbcafe203 --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/ChoiceMessageFormatterInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Formatter; + +/** + * @author Abdellatif Ait boudad + */ +interface ChoiceMessageFormatterInterface +{ + /** + * Formats a localized message pattern with given arguments. + * + * @param string $message The message (may also be an object that can be cast to string) + * @param int $number The number to use to find the indice of the message + * @param string $locale The message locale + * @param array $parameters An array of parameters for the message + * + * @return string + */ + public function choiceFormat($message, $number, $locale, array $parameters = array()); +} diff --git a/src/Symfony/Component/Translation/Formatter/MessageFormatter.php b/src/Symfony/Component/Translation/Formatter/MessageFormatter.php new file mode 100644 index 000000000000..e174be36c3a4 --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/MessageFormatter.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Formatter; + +use Symfony\Component\Translation\MessageSelector; + +/** + * @author Abdellatif Ait boudad + */ +class MessageFormatter implements MessageFormatterInterface, ChoiceMessageFormatterInterface +{ + private $selector; + + /** + * @param MessageSelector|null $selector The message selector for pluralization + */ + public function __construct(MessageSelector $selector = null) + { + $this->selector = $selector ?: new MessageSelector(); + } + + /** + * {@inheritdoc} + */ + public function format($message, $locale, array $parameters = array()) + { + return strtr($message, $parameters); + } + + /** + * {@inheritdoc} + */ + public function choiceFormat($message, $number, $locale, array $parameters = array()) + { + $parameters = array_merge(array('%count%' => $number), $parameters); + + return $this->format($this->selector->choose($message, (int) $number, $locale), $locale, $parameters); + } +} diff --git a/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php b/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php new file mode 100644 index 000000000000..86937fb2f085 --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Formatter; + +/** + * @author Guilherme Blanco + * @author Abdellatif Ait boudad + */ +interface MessageFormatterInterface +{ + /** + * Formats a localized message pattern with given arguments. + * + * @param string $message The message (may also be an object that can be cast to string) + * @param string $locale The message locale + * @param array $parameters An array of parameters for the message + * + * @return string + */ + public function format($message, $locale, array $parameters = array()); +} diff --git a/src/Symfony/Component/Translation/Tests/Formatter/MessageFormatterTest.php b/src/Symfony/Component/Translation/Tests/Formatter/MessageFormatterTest.php new file mode 100644 index 000000000000..1fa736e7e3df --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Formatter/MessageFormatterTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Tests\Formatter; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Translation\Formatter\MessageFormatter; + +class MessageFormatterTest extends TestCase +{ + /** + * @dataProvider getTransMessages + */ + public function testFormat($expected, $message, $parameters = array()) + { + $this->assertEquals($expected, $this->getMessageFormatter()->format($message, 'en', $parameters)); + } + + /** + * @dataProvider getTransChoiceMessages + */ + public function testFormatPlural($expected, $message, $number, $parameters) + { + $this->assertEquals($expected, $this->getMessageFormatter()->choiceFormat($message, $number, 'fr', $parameters)); + } + + public function getTransMessages() + { + return array( + array( + 'There is one apple', + 'There is one apple', + ), + array( + 'There are 5 apples', + 'There are %count% apples', + array('%count%' => 5), + ), + array( + 'There are 5 apples', + 'There are {{count}} apples', + array('{{count}}' => 5), + ), + ); + } + + public function getTransChoiceMessages() + { + return array( + array('Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0)), + array('Il y a 1 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 1, array('%count%' => 1)), + array('Il y a 10 pommes', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 10, array('%count%' => 10)), + + array('Il y a 0 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 0, array('%count%' => 0)), + array('Il y a 1 pomme', 'Il y a %count% pomme|Il y a %count% pommes', 1, array('%count%' => 1)), + array('Il y a 10 pommes', 'Il y a %count% pomme|Il y a %count% pommes', 10, array('%count%' => 10)), + + array('Il y a 0 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0)), + array('Il y a 1 pomme', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1)), + array('Il y a 10 pommes', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10)), + + array('Il n\'y a aucune pomme', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 0, array('%count%' => 0)), + array('Il y a 1 pomme', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 1, array('%count%' => 1)), + array('Il y a 10 pommes', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, array('%count%' => 10)), + + array('Il y a 0 pomme', '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, array('%count%' => 0)), + ); + } + + private function getMessageFormatter() + { + return new MessageFormatter(); + } +} diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 2394fdb4320b..d2c6fd51f453 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Translation\Translator; -use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\MessageCatalogue; @@ -25,7 +24,7 @@ class TranslatorTest extends TestCase */ public function testConstructorInvalidLocale($locale) { - $translator = new Translator($locale, new MessageSelector()); + $translator = new Translator($locale); } /** @@ -33,14 +32,14 @@ public function testConstructorInvalidLocale($locale) */ public function testConstructorValidLocale($locale) { - $translator = new Translator($locale, new MessageSelector()); + $translator = new Translator($locale); $this->assertEquals($locale, $translator->getLocale()); } public function testConstructorWithoutLocale() { - $translator = new Translator(null, new MessageSelector()); + $translator = new Translator(null); $this->assertNull($translator->getLocale()); } @@ -61,7 +60,7 @@ public function testSetGetLocale() */ public function testSetInvalidLocale($locale) { - $translator = new Translator('fr', new MessageSelector()); + $translator = new Translator('fr'); $translator->setLocale($locale); } @@ -70,7 +69,7 @@ public function testSetInvalidLocale($locale) */ public function testSetValidLocale($locale) { - $translator = new Translator($locale, new MessageSelector()); + $translator = new Translator($locale); $translator->setLocale($locale); $this->assertEquals($locale, $translator->getLocale()); @@ -144,7 +143,7 @@ public function testSetFallbackLocalesMultiple() */ public function testSetFallbackInvalidLocales($locale) { - $translator = new Translator('fr', new MessageSelector()); + $translator = new Translator('fr'); $translator->setFallbackLocales(array('fr', $locale)); } @@ -153,7 +152,7 @@ public function testSetFallbackInvalidLocales($locale) */ public function testSetFallbackValidLocales($locale) { - $translator = new Translator($locale, new MessageSelector()); + $translator = new Translator($locale); $translator->setFallbackLocales(array('fr', $locale)); // no assertion. this method just asserts that no exception is thrown $this->addToAssertionCount(1); @@ -176,7 +175,7 @@ public function testTransWithFallbackLocale() */ public function testAddResourceInvalidLocales($locale) { - $translator = new Translator('fr', new MessageSelector()); + $translator = new Translator('fr'); $translator->addResource('array', array('foo' => 'foofoo'), $locale); } @@ -185,7 +184,7 @@ public function testAddResourceInvalidLocales($locale) */ public function testAddResourceValidLocales($locale) { - $translator = new Translator('fr', new MessageSelector()); + $translator = new Translator('fr'); $translator->addResource('array', array('foo' => 'foofoo'), $locale); // no assertion. this method just asserts that no exception is thrown $this->addToAssertionCount(1); @@ -288,7 +287,7 @@ public function testNestedFallbackCatalogueWhenUsingMultipleLocales() public function testFallbackCatalogueResources() { - $translator = new Translator('en_GB', new MessageSelector()); + $translator = new Translator('en_GB'); $translator->addLoader('yml', new \Symfony\Component\Translation\Loader\YamlFileLoader()); $translator->addResource('yml', __DIR__.'/fixtures/empty.yml', 'en_GB'); $translator->addResource('yml', __DIR__.'/fixtures/resources.yml', 'en'); @@ -324,7 +323,7 @@ public function testTrans($expected, $id, $translation, $parameters, $locale, $d */ public function testTransInvalidLocale($locale) { - $translator = new Translator('en', new MessageSelector()); + $translator = new Translator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); @@ -336,7 +335,7 @@ public function testTransInvalidLocale($locale) */ public function testTransValidLocale($locale) { - $translator = new Translator($locale, new MessageSelector()); + $translator = new Translator($locale); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('test' => 'OK'), $locale); @@ -374,7 +373,7 @@ public function testTransChoice($expected, $id, $translation, $number, $paramete */ public function testTransChoiceInvalidLocale($locale) { - $translator = new Translator('en', new MessageSelector()); + $translator = new Translator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); @@ -386,7 +385,7 @@ public function testTransChoiceInvalidLocale($locale) */ public function testTransChoiceValidLocale($locale) { - $translator = new Translator('en', new MessageSelector()); + $translator = new Translator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 897aced2717b..96553ec98998 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -14,10 +14,14 @@ use Symfony\Component\Translation\Loader\LoaderInterface; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\Exception\InvalidArgumentException; +use Symfony\Component\Translation\Exception\LogicException; use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Config\ConfigCacheInterface; use Symfony\Component\Config\ConfigCacheFactoryInterface; use Symfony\Component\Config\ConfigCacheFactory; +use Symfony\Component\Translation\Formatter\MessageFormatterInterface; +use Symfony\Component\Translation\Formatter\ChoiceMessageFormatterInterface; +use Symfony\Component\Translation\Formatter\MessageFormatter; /** * Translator. @@ -52,9 +56,9 @@ class Translator implements TranslatorInterface, TranslatorBagInterface private $resources = array(); /** - * @var MessageSelector + * @var MessageFormatterInterface */ - private $selector; + private $formatter; /** * @var string @@ -74,17 +78,25 @@ class Translator implements TranslatorInterface, TranslatorBagInterface /** * Constructor. * - * @param string $locale The locale - * @param MessageSelector|null $selector The message selector for pluralization - * @param string|null $cacheDir The directory to use for the cache - * @param bool $debug Use cache in debug mode ? + * @param string $locale The locale + * @param MessageFormatterInterface|null $formatter The message formatter + * @param string|null $cacheDir The directory to use for the cache + * @param bool $debug Use cache in debug mode ? * * @throws InvalidArgumentException If a locale contains invalid characters */ - public function __construct($locale, MessageSelector $selector = null, $cacheDir = null, $debug = false) + public function __construct($locale, $formatter = null, $cacheDir = null, $debug = false) { $this->setLocale($locale); - $this->selector = $selector ?: new MessageSelector(); + + if ($formatter instanceof MessageSelector) { + $formatter = new MessageFormatter($formatter); + @trigger_error(sprintf('Passing a "%s" instance into the "%s" as a second argument is deprecated since version 3.4 and will be removed in 4.0. Inject a "%s" implementation instead.', MessageSelector::class, __METHOD__, MessageFormatterInterface::class), E_USER_DEPRECATED); + } elseif (null === $formatter) { + $formatter = new MessageFormatter(); + } + + $this->formatter = $formatter; $this->cacheDir = $cacheDir; $this->debug = $debug; } @@ -192,7 +204,7 @@ public function trans($id, array $parameters = array(), $domain = null, $locale $domain = 'messages'; } - return strtr($this->getCatalogue($locale)->get((string) $id, $domain), $parameters); + return $this->formatter->format($this->getCatalogue($locale)->get((string) $id, $domain), $locale, $parameters); } /** @@ -200,9 +212,9 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { - $parameters = array_merge(array( - '%count%' => $number, - ), $parameters); + if (!$this->formatter instanceof ChoiceMessageFormatterInterface) { + throw new LogicException(sprintf('The formatter "%s" does not support plural translations.', get_class($this->formatter))); + } if (null === $domain) { $domain = 'messages'; @@ -220,7 +232,7 @@ public function transChoice($id, $number, array $parameters = array(), $domain = } } - return strtr($this->selector->choose($catalogue->get($id, $domain), (int) $number, $locale), $parameters); + return $this->formatter->choiceFormat($catalogue->get($id, $domain), $number, $locale, $parameters); } /**