From 60ad3a235a88a0627a8f410bb659435855e28567 Mon Sep 17 00:00:00 2001 From: Guilherme Blanco Date: Mon, 22 Jun 2015 17:57:50 +0000 Subject: [PATCH 1/2] [Translator] Adding support for intl message formatter and decoupling default formatter. --- .../Extension/TranslationExtensionTest.php | 9 +- .../DependencyInjection/Configuration.php | 1 + .../FrameworkExtension.php | 1 + .../Resources/config/schema/symfony-1.0.xsd | 1 + .../Resources/config/translation.xml | 9 +- .../DependencyInjection/ConfigurationTest.php | 1 + .../Tests/Translation/TranslatorTest.php | 6 +- .../Translation/Translator.php | 12 +-- .../Formatter/DefaultMessageFormatter.php | 26 ++++++ .../Formatter/IntlMessageFormatter.php | 38 ++++++++ .../Formatter/MessageFormatterInterface.php | 33 +++++++ .../Translation/IdentityTranslator.php | 35 ++++++-- .../Formatter/DefaultMessageFormatterTest.php | 54 ++++++++++++ .../Formatter/IntlMessageFormatterTest.php | 88 +++++++++++++++++++ .../Translation/Tests/TranslatorTest.php | 29 +++--- .../Component/Translation/Translator.php | 36 ++++++-- 16 files changed, 334 insertions(+), 45 deletions(-) create mode 100644 src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php create mode 100644 src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php create mode 100644 src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php create mode 100644 src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php create mode 100644 src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index dc06c73dba03e..d3c777d08dbd2 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -13,7 +13,6 @@ use Symfony\Bridge\Twig\Extension\TranslationExtension; use Symfony\Component\Translation\Translator; -use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\Loader\ArrayLoader; class TranslationExtensionTest extends \PHPUnit_Framework_TestCase @@ -34,7 +33,7 @@ public function testTrans($template, $expected, array $variables = array()) print $template."\n"; $loader = new \Twig_Loader_Array(array('index' => $template)); $twig = new \Twig_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()->getSource('index'), 'index')))."\n\n"; $this->assertEquals($expected, $this->getTemplate($template)->render($variables)); @@ -136,7 +135,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'); @@ -169,7 +168,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'); @@ -184,7 +183,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 023276e476b9e..8b259217aa166 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -584,6 +584,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 1ccb2188d757a..06b0a7ac71e35 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -663,6 +663,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', $config['formatter']); $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 4190dad7cb787..aafabf67137ef 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 @@ -189,6 +189,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml index 0007a360c6e46..1d3361122beab 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml @@ -38,7 +38,7 @@ - + %kernel.cache_dir%/translations @@ -54,6 +54,13 @@ + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 04b6c95b46dae..f9bf8aa5b00d0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -155,6 +155,7 @@ protected static function getBundleDefaultConfig() ), 'translator' => array( 'enabled' => false, + 'formatter' => 'translator.formatter.default', 'fallbacks' => array('en'), 'logging' => true, 'paths' => array(), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index c7b61cb88170e..458749a259b56 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -14,7 +14,7 @@ use Symfony\Bundle\FrameworkBundle\Translation\Translator; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Translation\MessageSelector; +use Symfony\Component\Translation\Formatter\DefaultMessageFormatter; class TranslatorTest extends \PHPUnit_Framework_TestCase { @@ -157,7 +157,7 @@ public function testGetDefaultLocale() ->will($this->returnValue('en')) ; - $translator = new Translator($container, new MessageSelector()); + $translator = new Translator($container, new DefaultMessageFormatter()); $this->assertSame('en', $translator->getLocale()); } @@ -290,7 +290,7 @@ private function createTranslator($loader, $options, $translatorClass = '\Symfon { return new $translatorClass( $this->getContainer($loader), - new MessageSelector(), + new DefaultMessageFormatter(), array($loaderFomat => array($loaderFomat)), $options ); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index 9cc92f9c2d616..bb9aac854e8ba 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -46,14 +46,14 @@ 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 array $loaderIds An array of loader Ids - * @param array $options An array of options + * @param ContainerInterface $container A ContainerInterface instance + * @param MessageFormatterInterface|MessageSelector $formatter The message formatter + * @param array $loaderIds An array of loader Ids + * @param array $options An array of options * * @throws \InvalidArgumentException */ - public function __construct(ContainerInterface $container, MessageSelector $selector, $loaderIds = array(), array $options = array()) + public function __construct(ContainerInterface $container, $formatter, $loaderIds = array(), array $options = array()) { $this->container = $container; $this->loaderIds = $loaderIds; @@ -69,7 +69,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($container->getParameter('kernel.default_locale'), $formatter, $this->options['cache_dir'], $this->options['debug']); } /** diff --git a/src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php b/src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php new file mode 100644 index 0000000000000..76ec92754a14c --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php @@ -0,0 +1,26 @@ + + * + * 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 + */ +class DefaultMessageFormatter implements MessageFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function format($locale, $id, array $arguments = array()) + { + return strtr($id, $arguments); + } +} diff --git a/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php b/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php new file mode 100644 index 0000000000000..b56da59d82ad8 --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php @@ -0,0 +1,38 @@ + + * + * 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 + */ +class IntlMessageFormatter implements MessageFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function format($locale, $id, array $arguments = array()) + { + $formatter = new \MessageFormatter($locale, $id); + + if (null === $formatter) { + throw new \InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code())); + } + + $message = $formatter->format($arguments); + + if ($formatter->getErrorCode() !== U_ZERO_ERROR) { + throw new \InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode())); + } + + return $message; + } +} diff --git a/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php b/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php new file mode 100644 index 0000000000000..9a2f0aec47f99 --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Formatter; + +/** + * MessageFormatterInterface. + * + * @author Guilherme Blanco + */ +interface MessageFormatterInterface +{ + /** + * Formats a lozalized message pattern with given arguments. + * + * @param string $locale The message locale + * @param string $id The message id (may also be an object that can be cast to string) + * @param array $arguments An array of parameters for the message + * + * @return string + * + * @throws \InvalidArgumentException + */ + public function format($locale, $id, array $arguments = array()); +} diff --git a/src/Symfony/Component/Translation/IdentityTranslator.php b/src/Symfony/Component/Translation/IdentityTranslator.php index 9c9212e803050..f37f110a7ef1d 100644 --- a/src/Symfony/Component/Translation/IdentityTranslator.php +++ b/src/Symfony/Component/Translation/IdentityTranslator.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Translation; +use Symfony\Component\Translation\Formatter\MessageFormatterInterface; +use Symfony\Component\Translation\Formatter\DefaultMessageFormatter; + /** * IdentityTranslator does not translate anything. * @@ -21,18 +24,28 @@ class IdentityTranslator implements TranslatorInterface { private $selector; + private $formatter; private $locale; /** - * Constructor. - * - * @param MessageSelector|null $selector The message selector for pluralization + * @param MessageFormatterInterface|MessageSelector $formatter The message formatter * * @api */ - public function __construct(MessageSelector $selector = null) + public function __construct($formatter = null) { - $this->selector = $selector ?: new MessageSelector(); + if ($formatter instanceof MessageSelector) { + @trigger_error('Passing a MessageSelector instance into the '.__METHOD__.' is deprecated since version 2.8 and will be removed in 3.0. Inject a MessageFormatterInterface instance instead.', E_USER_DEPRECATED); + $this->selector = $formatter; + $formatter = new DefaultMessageFormatter(); + } else { + $this->selector = new MessageSelector(); + } + + $this->formatter = $formatter ?: new DefaultMessageFormatter(); + if (!$this->formatter instanceof MessageFormatterInterface) { + throw new \InvalidArgumentException(sprintf('The message formatter "%s" must implement MessageFormatterInterface.', get_class($this->formatter))); + } } /** @@ -62,7 +75,11 @@ public function getLocale() */ public function trans($id, array $parameters = array(), $domain = null, $locale = null) { - return strtr((string) $id, $parameters); + if (!$locale) { + $locale = $this->getLocale(); + } + + return $this->formatter->format($locale, (string) $id, $parameters); } /** @@ -72,6 +89,10 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { - return strtr($this->selector->choose((string) $id, (int) $number, $locale ?: $this->getLocale()), $parameters); + if (!$locale) { + $locale = $this->getLocale(); + } + + return $this->formatter->format($locale, $this->selector->choose((string) $id, (int) $number, $locale ?: $this->getLocale()), $parameters); } } diff --git a/src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php b/src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php new file mode 100644 index 0000000000000..e0319aa22acdd --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php @@ -0,0 +1,54 @@ + + * + * 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 Symfony\Component\Translation\Formatter\DefaultMessageFormatter; + +class DefaultMessageFormatterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideDataForFormat + */ + public function testFormat($expected, $message, $arguments) + { + $formatter = new DefaultMessageFormatter(); + + $this->assertEquals($expected, $formatter->format('en', $message, $arguments)); + } + + public function provideDataForFormat() + { + return array( + array( + 'There is one apple', + 'There is one apple', + array(), + ), + array( + 'There are 5 apples', + 'There are %count% apples', + array('%count%' => 5), + ), + ); + } + + private function mockMessageSelector($willCallChoose) + { + $mock = $this->getMock('Symfony\Component\Translation\MessageSelector'); + + $mock->expects($willCallChoose ? $this->once() : $this->never()) + ->method('choose') + ->will($this->returnValue('Message')); + + return $mock; + } +} diff --git a/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php b/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php new file mode 100644 index 0000000000000..869597efaeda8 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php @@ -0,0 +1,88 @@ + + * + * 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 Symfony\Component\Translation\Formatter\IntlMessageFormatter; + +class IntlMessageFormatterTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!extension_loaded('intl')) { + $this->markTestSkipped( + 'The Intl extension is not available.' + ); + } + } + + /** + * @dataProvider provideDataForFormat + */ + public function testFormat($expected, $message, $arguments) + { + $formatter = new IntlMessageFormatter(); + + $this->assertEquals($expected, trim($formatter->format('en', $message, $arguments))); + } + + public function testFormatWithNamedArguments() + { + if (PHP_VERSION_ID < 50500 || version_compare(INTL_ICU_VERSION, '4.8', '<')) { + $this->markTestSkipped('Format with named arguments can only be run with ICU 4.8 or higher and PHP >= 5.5'); + } + + $chooseMessage = <<<_MSG_ +{gender_of_host, select, + female {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to her party.} + =2 {{host} invites {guest} and one other person to her party.} + other {{host} invites {guest} as one of the # people invited to her party.}}} + male {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to his party.} + =2 {{host} invites {guest} and one other person to his party.} + other {{host} invites {guest} as one of the # people invited to his party.}}} + other {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to their party.} + =2 {{host} invites {guest} and one other person to their party.} + other {{host} invites {guest} as one of the # people invited to their party.}}}} +_MSG_; + + $formatter = new IntlMessageFormatter(); + $message = $formatter->format('en', $chooseMessage, array( + 'gender_of_host' => 'male', + 'num_guests' => 10, + 'host' => 'Fabien', + 'guest' => 'Guilherme', + )); + + $this->assertEquals('Fabien invites Guilherme as one of the 9 people invited to his party.', $message); + } + + public function provideDataForFormat() + { + return array( + array( + 'There is one apple', + 'There is one apple', + array(), + ), + array( + '4,560 monkeys on 123 trees make 37.073 monkeys per tree', + '{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree', + array(4560, 123, 4560 / 123), + ), + ); + } +} diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index e8e967139dac2..74d111b58f594 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Translation\Tests; use Symfony\Component\Translation\Translator; -use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\MessageCatalogue; @@ -24,7 +23,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase */ public function testConstructorInvalidLocale($locale) { - $translator = new Translator($locale, new MessageSelector()); + $translator = new Translator($locale); } /** @@ -32,14 +31,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()); } @@ -60,7 +59,7 @@ public function testSetGetLocale() */ public function testSetInvalidLocale($locale) { - $translator = new Translator('fr', new MessageSelector()); + $translator = new Translator('fr'); $translator->setLocale($locale); } @@ -69,7 +68,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()); @@ -143,7 +142,7 @@ public function testSetFallbackLocalesMultiple() */ public function testSetFallbackInvalidLocales($locale) { - $translator = new Translator('fr', new MessageSelector()); + $translator = new Translator('fr'); $translator->setFallbackLocales(array('fr', $locale)); } @@ -152,7 +151,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 } @@ -174,7 +173,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); } @@ -183,7 +182,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 } @@ -291,7 +290,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'); @@ -303,7 +302,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); @@ -341,7 +340,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'); @@ -353,7 +352,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'); @@ -506,7 +505,7 @@ public function testLegacyGetMessages($resources, $locale, $expected) $_locale = null !== $locale ? $locale : reset($locales); $locales = array_slice($locales, 0, array_search($_locale, $locales)); - $translator = new Translator($_locale, new MessageSelector()); + $translator = new Translator($_locale); $translator->setFallbackLocales(array_reverse($locales)); $translator->addLoader('array', new ArrayLoader()); foreach ($resources as $_locale => $domainMessages) { diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 58dbc8a1a811a..4e652fa84f93f 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -16,11 +16,14 @@ 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\DefaultMessageFormatter; /** * Translator. * * @author Fabien Potencier + * @author Guilherme Blanco * * @api */ @@ -51,6 +54,11 @@ class Translator implements TranslatorInterface, TranslatorBagInterface */ private $resources = array(); + /** + * @var MessageFormatterInterface + */ + private $formatter; + /** * @var MessageSelector */ @@ -74,19 +82,31 @@ 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|MessageSelector $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 * * @api */ - 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) { + @trigger_error('Passing a MessageSelector instance into the '.__METHOD__.' as a second argument is deprecated since version 2.8 and will be removed in 3.0. Inject a MessageFormatterInterface instance instead.', E_USER_DEPRECATED); + $this->selector = $formatter; + $formatter = new DefaultMessageFormatter(); + } else { + $this->selector = new MessageSelector(); + } + + $this->formatter = $formatter ?: new DefaultMessageFormatter(); + if (!$this->formatter instanceof MessageFormatterInterface) { + throw new \InvalidArgumentException(sprintf('The message formatter "%s" must implement MessageFormatterInterface.', get_class($this->formatter))); + } + $this->cacheDir = $cacheDir; $this->debug = $debug; } @@ -226,7 +246,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($locale, $this->getCatalogue($locale)->get((string) $id, $domain), $parameters); } /** @@ -252,7 +272,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->format($locale, $this->selector->choose($catalogue->get($id, $domain), (int) $number, $locale), $parameters); } /** From 49dbc6a934f11fbdf211615fd00973b84cbd4c58 Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Thu, 27 Aug 2015 10:39:15 +0000 Subject: [PATCH 2/2] deprecate transChoice method + [IntlFormater] fallback the lagacy massages --- .../Twig/Extension/TranslationExtension.php | 5 + .../Extension/TranslationExtensionTest.php | 103 ++++++++++++++---- .../DependencyInjection/Configuration.php | 2 +- .../Resources/config/translation.xml | 4 +- .../DependencyInjection/ConfigurationTest.php | 2 +- .../Tests/Translation/TranslatorTest.php | 22 ++-- .../Translation/DataCollectorTranslator.php | 1 + .../Formatter/DefaultMessageFormatter.php | 26 ----- .../Formatter/IntlMessageFormatter.php | 16 ++- .../Formatter/LegacyIntlMessageFormatter.php | 49 +++++++++ .../Formatter/MessageFormatterInterface.php | 8 +- .../Translation/IdentityTranslator.php | 7 +- .../Translation/LoggingTranslator.php | 1 + .../Tests/DataCollectorTranslatorTest.php | 64 ++++++----- .../Formatter/IntlMessageFormatterTest.php | 9 +- ...php => LegacyIntlMessageFormatterTest.php} | 27 +++-- .../Tests/IdentityTranslatorTest.php | 2 + .../Tests/LoggingTranslatorTest.php | 6 +- .../Translation/Tests/TranslatorTest.php | 98 +++++++++++------ .../Component/Translation/Translator.php | 7 +- .../Translation/TranslatorInterface.php | 3 + .../Tests/Validator/Abstract2Dot5ApiTest.php | 3 +- 22 files changed, 309 insertions(+), 156 deletions(-) delete mode 100644 src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php create mode 100644 src/Symfony/Component/Translation/Formatter/LegacyIntlMessageFormatter.php rename src/Symfony/Component/Translation/Tests/Formatter/{DefaultMessageFormatterTest.php => LegacyIntlMessageFormatterTest.php} (53%) diff --git a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php index f1f2fbd20b82e..d2fc5d746f857 100644 --- a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php @@ -93,8 +93,13 @@ public function trans($message, array $arguments = array(), $domain = null, $loc return $this->translator->trans($message, $arguments, $domain, $locale); } + /** + * @deprecated since version 2.8, to be removed in 3.0. Use the {@link trans} method instead. + */ public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Use trans() method instead.', E_USER_DEPRECATED); + return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale); } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index d3c777d08dbd2..09400dfbe4b7f 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -42,6 +42,15 @@ public function testTrans($template, $expected, array $variables = array()) $this->assertEquals($expected, $this->getTemplate($template)->render($variables)); } + /** + * @dataProvider getTranschoiceTests + * @group legacy + */ + public function testTranschoice($template, $expected, array $variables = array()) + { + $this->testTrans($template, $expected, $variables); + } + /** * @expectedException \Twig_Error_Syntax * @expectedExceptionMessage Unexpected token. Twig was looking for the "with", "from", or "into" keyword in "index" at line 3. @@ -84,6 +93,18 @@ public function getTransTests() array('{% trans into "fr"%}Hello{% endtrans %}', 'Hello'), + // trans filter + array('{{ "Hello"|trans }}', 'Hello'), + array('{{ name|trans }}', 'Symfony', array('name' => 'Symfony')), + array('{{ hello|trans({ \'%name%\': \'Symfony\' }) }}', 'Hello Symfony', array('hello' => 'Hello %name%')), + array('{% set vars = { \'%name%\': \'Symfony\' } %}{{ hello|trans(vars) }}', 'Hello Symfony', array('hello' => 'Hello %name%')), + array('{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'), + ); + } + + public function getTranschoiceTests() + { + return array( // transchoice array('{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', 'There is no apples', array('count' => 0),), @@ -98,13 +119,6 @@ public function getTransTests() array('{% transchoice 5 into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}', 'There is 5 apples',), - // trans filter - array('{{ "Hello"|trans }}', 'Hello'), - array('{{ name|trans }}', 'Symfony', array('name' => 'Symfony')), - array('{{ hello|trans({ \'%name%\': \'Symfony\' }) }}', 'Hello Symfony', array('hello' => 'Hello %name%')), - array('{% set vars = { \'%name%\': \'Symfony\' } %}{{ hello|trans(vars) }}', 'Hello Symfony', array('hello' => 'Hello %name%')), - array('{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'), - // transchoice filter array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count) }}', 'There is 5 apples', array('count' => 5)), array('{{ text|transchoice(5, {\'%name%\': \'Symfony\'}) }}', 'There is 5 apples (Symfony)', array('text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)')), @@ -112,7 +126,7 @@ public function getTransTests() ); } - public function testDefaultTranslationDomain() + public function testTransDefaultTranslationDomain() { $templates = array( 'index' => ' @@ -125,6 +139,31 @@ public function testDefaultTranslationDomain() {%- trans from "custom" %}foo{% endtrans %} {{- "foo"|trans }} {{- "foo"|trans({}, "custom") }} + {% endblock %} + ', + + 'base' => ' + {%- block content "" %} + ', + ); + + $template = $this->getTemplate($templates, $this->getTranslator()); + + $this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array()))); + } + + /** + * @group legacy + */ + public function testTransChoiceDefaultTranslationDomain() + { + $templates = array( + 'index' => ' + {%- extends "base" %} + + {%- trans_default_domain "foo" %} + + {%- block content %} {{- "foo"|transchoice(1) }} {{- "foo"|transchoice(1, {}, "custom") }} {% endblock %} @@ -135,15 +174,9 @@ public function testDefaultTranslationDomain() ', ); - $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'); - $translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo'); - - $template = $this->getTemplate($templates, $translator); + $template = $this->getTemplate($templates, $this->getTranslator()); - $this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array()))); + $this->assertEquals('foo (foo)foo (custom)', trim($template->render(array()))); } public function testDefaultTranslationDomainWithNamedArguments() @@ -154,10 +187,33 @@ public function testDefaultTranslationDomainWithNamedArguments() {%- block content %} {{- "foo"|trans(arguments = {}, domain = "custom") }} - {{- "foo"|transchoice(count = 1) }} - {{- "foo"|transchoice(count = 1, arguments = {}, domain = "custom") }} {{- "foo"|trans({}, domain = "custom") }} {{- "foo"|trans({}, "custom", locale = "fr") }} + {% endblock %} + ', + + 'base' => ' + {%- block content "" %} + ', + ); + + $template = $this->getTemplate($templates, $this->getTranslator()); + + $this->assertEquals('foo (custom)foo (custom)foo (fr)', trim($template->render(array()))); + } + + /** + * @group legacy + */ + public function testTransChoiceDefaultTranslationDomainWithNamedArguments() + { + $templates = array( + 'index' => ' + {%- trans_default_domain "foo" %} + + {%- block content %} + {{- "foo"|transchoice(count = 1) }} + {{- "foo"|transchoice(count = 1, arguments = {}, domain = "custom") }} {{- "foo"|transchoice(1, arguments = {}, domain = "custom") }} {{- "foo"|transchoice(1, {}, "custom", locale = "fr") }} {% endblock %} @@ -168,6 +224,13 @@ public function testDefaultTranslationDomainWithNamedArguments() ', ); + $template = $this->getTemplate($templates, $this->getTranslator()); + + $this->assertEquals('foo (foo)foo (custom)foo (custom)foo (fr)', trim($template->render(array()))); + } + + protected function getTranslator() + { $translator = new Translator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foo (messages)'), 'en'); @@ -175,9 +238,7 @@ public function testDefaultTranslationDomainWithNamedArguments() $translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo'); $translator->addResource('array', array('foo' => 'foo (fr)'), 'fr', 'custom'); - $template = $this->getTemplate($templates, $translator); - - $this->assertEquals('foo (custom)foo (foo)foo (custom)foo (custom)foo (fr)foo (custom)foo (fr)', trim($template->render(array()))); + return $translator; } protected function getTemplate($template, $translator = null) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 8b259217aa166..0c467eb2848c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -584,7 +584,7 @@ private function addTranslatorSection(ArrayNodeDefinition $rootNode) ->defaultValue(array('en')) ->end() ->booleanNode('logging')->defaultValue($this->debug)->end() - ->scalarNode('formatter')->defaultValue('translator.formatter.default')->end() + ->scalarNode('formatter')->defaultValue('translator.formatter.legacy_intl')->end() ->arrayNode('paths') ->prototype('scalar')->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml index 1d3361122beab..cbf7d213bfa93 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml @@ -57,10 +57,10 @@ - + - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index f9bf8aa5b00d0..6a029d139b724 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -155,7 +155,7 @@ protected static function getBundleDefaultConfig() ), 'translator' => array( 'enabled' => false, - 'formatter' => 'translator.formatter.default', + 'formatter' => 'translator.formatter.legacy_intl', 'fallbacks' => array('en'), 'logging' => true, 'paths' => array(), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index 458749a259b56..0f7735dca244e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -14,7 +14,7 @@ use Symfony\Bundle\FrameworkBundle\Translation\Translator; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Translation\Formatter\DefaultMessageFormatter; +use Symfony\Component\Translation\Formatter\IntlMessageFormatter; class TranslatorTest extends \PHPUnit_Framework_TestCase { @@ -50,10 +50,10 @@ public function testTransWithoutCaching() $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('choice 0 (EN)', $translator->trans('choice', array(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('other choice 1 (PT-BR)', $translator->trans('other choice', array(1))); $this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz')); $this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax')); } @@ -68,10 +68,10 @@ public function testTransWithCaching() $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('choice 0 (EN)', $translator->trans('choice', array(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('other choice 1 (PT-BR)', $translator->trans('other choice', array(1))); $this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz')); $this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax')); @@ -86,10 +86,10 @@ public function testTransWithCaching() $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('choice 0 (EN)', $translator->trans('choice', array(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('other choice 1 (PT-BR)', $translator->trans('other choice', array(1))); $this->assertEquals('foobarbaz (fr.UTF-8)', $translator->trans('foobarbaz')); $this->assertEquals('foobarbax (sr@latin)', $translator->trans('foobarbax')); } @@ -157,7 +157,7 @@ public function testGetDefaultLocale() ->will($this->returnValue('en')) ; - $translator = new Translator($container, new DefaultMessageFormatter()); + $translator = new Translator($container, new IntlMessageFormatter()); $this->assertSame('en', $translator->getLocale()); } @@ -191,7 +191,7 @@ protected function getLoader() ->will($this->returnValue($this->getCatalogue('en', array( 'foo' => 'foo (EN)', 'bar' => 'bar (EN)', - 'choice' => '{0} choice 0 (EN)|{1} choice 1 (EN)|]1,Inf] choice inf (EN)', + 'choice' => '{0, plural, =0 {choice 0 (EN)} =1 {choice 1 (EN)} other {# choice inf (EN)}}', )))) ; $loader @@ -212,7 +212,7 @@ protected function getLoader() ->expects($this->at(4)) ->method('load') ->will($this->returnValue($this->getCatalogue('pt_BR', array( - 'other choice' => '{0} other choice 0 (PT-BR)|{1} other choice 1 (PT-BR)|]1,Inf] other choice inf (PT-BR)', + 'other choice' => '{0, plural, =0 {other choice 0 (PT-BR)} =1 {other choice 1 (PT-BR)} other {# other choice inf (PT-BR)}}', )))) ; $loader @@ -290,7 +290,7 @@ private function createTranslator($loader, $options, $translatorClass = '\Symfon { return new $translatorClass( $this->getContainer($loader), - new DefaultMessageFormatter(), + new IntlMessageFormatter(), array($loaderFomat => array($loaderFomat)), $options ); diff --git a/src/Symfony/Component/Translation/DataCollectorTranslator.php b/src/Symfony/Component/Translation/DataCollectorTranslator.php index a7478da3740e9..39ca68384279a 100644 --- a/src/Symfony/Component/Translation/DataCollectorTranslator.php +++ b/src/Symfony/Component/Translation/DataCollectorTranslator.php @@ -58,6 +58,7 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Rely on the MessageFormatterInterface and TranslatorInterface::trans() method instead.', E_USER_DEPRECATED); $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale); $this->collectMessage($locale, $domain, $id, $trans, $parameters, $number); diff --git a/src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php b/src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php deleted file mode 100644 index 76ec92754a14c..0000000000000 --- a/src/Symfony/Component/Translation/Formatter/DefaultMessageFormatter.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * 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 - */ -class DefaultMessageFormatter implements MessageFormatterInterface -{ - /** - * {@inheritdoc} - */ - public function format($locale, $id, array $arguments = array()) - { - return strtr($id, $arguments); - } -} diff --git a/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php b/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php index b56da59d82ad8..7c32300140a6c 100644 --- a/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php +++ b/src/Symfony/Component/Translation/Formatter/IntlMessageFormatter.php @@ -19,20 +19,28 @@ class IntlMessageFormatter implements MessageFormatterInterface /** * {@inheritdoc} */ - public function format($locale, $id, array $arguments = array()) + public function format($locale, $id, array $parameters = array()) { - $formatter = new \MessageFormatter($locale, $id); + if (!$parameters) { + return $id; + } + $formatter = new \MessageFormatter($locale, $id); if (null === $formatter) { throw new \InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code())); } - $message = $formatter->format($arguments); - + $message = $formatter->format($parameters); if ($formatter->getErrorCode() !== U_ZERO_ERROR) { throw new \InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode())); } + if (!$formatter->parse($message) && $formatter->getErrorCode() === U_ZERO_ERROR) { + @trigger_error('Passing a MessageSelector instance into the '.__METHOD__.' as a second argument is deprecated since version 2.8 and will be removed in 3.0. Inject a MessageFormatterInterface instance instead.', E_USER_DEPRECATED); + + return strtr($message, $parameters); + } + return $message; } } diff --git a/src/Symfony/Component/Translation/Formatter/LegacyIntlMessageFormatter.php b/src/Symfony/Component/Translation/Formatter/LegacyIntlMessageFormatter.php new file mode 100644 index 0000000000000..74f5f5f2949cd --- /dev/null +++ b/src/Symfony/Component/Translation/Formatter/LegacyIntlMessageFormatter.php @@ -0,0 +1,49 @@ + + * + * 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 + */ +class LegacyIntlMessageFormatter implements MessageFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function format($locale, $id, array $parameters = array()) + { + if (!$parameters) { + return $id; + } + + $formatter = new \MessageFormatter($locale, $id); + if (null === $formatter) { + return $this->fallbackToLegacyFormatter($id, $parameters); + } + + $message = $formatter->format($parameters); + if ($formatter->getErrorCode() !== U_ZERO_ERROR) { + return $this->fallbackToLegacyFormatter($message, $parameters); + } + + if (!$formatter->parse($message) && $formatter->getErrorCode() === U_ZERO_ERROR) { + return $this->fallbackToLegacyFormatter($message, $parameters); + } + + return $message; + } + + private function fallbackToLegacyFormatter($message, $parameters) + { + return strtr($message, $parameters); + } +} diff --git a/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php b/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php index 9a2f0aec47f99..91449ce1295ac 100644 --- a/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php +++ b/src/Symfony/Component/Translation/Formatter/MessageFormatterInterface.php @@ -21,13 +21,13 @@ interface MessageFormatterInterface /** * Formats a lozalized message pattern with given arguments. * - * @param string $locale The message locale - * @param string $id The message id (may also be an object that can be cast to string) - * @param array $arguments An array of parameters for the message + * @param string $locale The message locale + * @param string $id The message id (may also be an object that can be cast to string) + * @param array $parameters An array of parameters for the message * * @return string * * @throws \InvalidArgumentException */ - public function format($locale, $id, array $arguments = array()); + public function format($locale, $id, array $parameters = array()); } diff --git a/src/Symfony/Component/Translation/IdentityTranslator.php b/src/Symfony/Component/Translation/IdentityTranslator.php index f37f110a7ef1d..dc29c1ce86cbd 100644 --- a/src/Symfony/Component/Translation/IdentityTranslator.php +++ b/src/Symfony/Component/Translation/IdentityTranslator.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Translation; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; -use Symfony\Component\Translation\Formatter\DefaultMessageFormatter; +use Symfony\Component\Translation\Formatter\LegacyIntlMessageFormatter; /** * IdentityTranslator does not translate anything. @@ -37,12 +37,12 @@ public function __construct($formatter = null) if ($formatter instanceof MessageSelector) { @trigger_error('Passing a MessageSelector instance into the '.__METHOD__.' is deprecated since version 2.8 and will be removed in 3.0. Inject a MessageFormatterInterface instance instead.', E_USER_DEPRECATED); $this->selector = $formatter; - $formatter = new DefaultMessageFormatter(); + $formatter = new LegacyIntlMessageFormatter(); } else { $this->selector = new MessageSelector(); } - $this->formatter = $formatter ?: new DefaultMessageFormatter(); + $this->formatter = $formatter ?: new LegacyIntlMessageFormatter(); if (!$this->formatter instanceof MessageFormatterInterface) { throw new \InvalidArgumentException(sprintf('The message formatter "%s" must implement MessageFormatterInterface.', get_class($this->formatter))); } @@ -89,6 +89,7 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Rely on the MessageFormatterInterface and TranslatorInterface::trans() method instead.', E_USER_DEPRECATED); if (!$locale) { $locale = $this->getLocale(); } diff --git a/src/Symfony/Component/Translation/LoggingTranslator.php b/src/Symfony/Component/Translation/LoggingTranslator.php index 4ff3531228071..80a1d94e3cec2 100644 --- a/src/Symfony/Component/Translation/LoggingTranslator.php +++ b/src/Symfony/Component/Translation/LoggingTranslator.php @@ -58,6 +58,7 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Rely on the MessageFormatterInterface and TranslatorInterface::trans() method instead.', E_USER_DEPRECATED); $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale); $this->log($id, $domain, $locale); diff --git a/src/Symfony/Component/Translation/Tests/DataCollectorTranslatorTest.php b/src/Symfony/Component/Translation/Tests/DataCollectorTranslatorTest.php index 31be3f2f15ebe..5735348f5ad62 100644 --- a/src/Symfony/Component/Translation/Tests/DataCollectorTranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/DataCollectorTranslatorTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\DataCollectorTranslator; use Symfony\Component\Translation\Loader\ArrayLoader; +use Symfony\Component\Translation\Formatter\IntlMessageFormatter; class DataCollectorTranslatorTest extends \PHPUnit_Framework_TestCase { @@ -23,15 +24,44 @@ protected function setUp() $this->markTestSkipped('The "DataCollector" is not available'); } } - public function testCollectMessages() + + /** + * @group legacy + */ + public function testCollectLegacyMessages() { $collector = $this->createCollector(); $collector->setFallbackLocales(array('fr', 'ru')); + $collector->transChoice('choice', 0); + + $expectedMessages = array( + array( + 'id' => 'choice', + 'translation' => 'choice', + 'locale' => 'en', + 'domain' => 'messages', + 'state' => DataCollectorTranslator::MESSAGE_MISSING, + 'parameters' => array(), + 'transChoiceNumber' => 0, + ), + ); + + $this->assertEquals($expectedMessages, $collector->getCollectedMessages()); + } + + public function testCollectMessages() + { + $resources = array( + array('array', array('foo' => 'foo (en)'), 'en'), + array('array', array('bar' => 'bar (fr)'), 'fr'), + array('array', array('bar_ru' => '{foo} (ru)'), 'ru'), + ); + + $collector = $this->createCollector($resources); + $collector->setFallbackLocales(array('fr', 'ru')); $collector->trans('foo'); $collector->trans('bar'); - $collector->transChoice('choice', 0); - $collector->trans('bar_ru'); $collector->trans('bar_ru', array('foo' => 'bar')); $expectedMessages = array(); @@ -53,24 +83,6 @@ public function testCollectMessages() 'parameters' => array(), 'transChoiceNumber' => null, ); - $expectedMessages[] = array( - 'id' => 'choice', - 'translation' => 'choice', - 'locale' => 'en', - 'domain' => 'messages', - 'state' => DataCollectorTranslator::MESSAGE_MISSING, - 'parameters' => array(), - 'transChoiceNumber' => 0, - ); - $expectedMessages[] = array( - 'id' => 'bar_ru', - 'translation' => 'bar (ru)', - 'locale' => 'ru', - 'domain' => 'messages', - 'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK, - 'parameters' => array(), - 'transChoiceNumber' => null, - ); $expectedMessages[] = array( 'id' => 'bar_ru', 'translation' => 'bar (ru)', @@ -84,13 +96,13 @@ public function testCollectMessages() $this->assertEquals($expectedMessages, $collector->getCollectedMessages()); } - private function createCollector() + private function createCollector($resources = array()) { - $translator = new Translator('en'); + $translator = new Translator('en', new IntlMessageFormatter()); $translator->addLoader('array', new ArrayLoader()); - $translator->addResource('array', array('foo' => 'foo (en)'), 'en'); - $translator->addResource('array', array('bar' => 'bar (fr)'), 'fr'); - $translator->addResource('array', array('bar_ru' => 'bar (ru)'), 'ru'); + foreach ($resources as $resource) { + $translator->addResource($resource[0], $resource[1], $resource[2], isset($resource[3]) ? $resource[3] : null); + } $collector = new DataCollectorTranslator($translator); diff --git a/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php b/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php index 869597efaeda8..0bc7d5f4fbe8c 100644 --- a/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php +++ b/src/Symfony/Component/Translation/Tests/Formatter/IntlMessageFormatterTest.php @@ -29,7 +29,7 @@ public function setUp() */ public function testFormat($expected, $message, $arguments) { - $formatter = new IntlMessageFormatter(); + $formatter = $this->getMessageFormatter(); $this->assertEquals($expected, trim($formatter->format('en', $message, $arguments))); } @@ -59,7 +59,7 @@ public function testFormatWithNamedArguments() other {{host} invites {guest} as one of the # people invited to their party.}}}} _MSG_; - $formatter = new IntlMessageFormatter(); + $formatter = $this->getMessageFormatter(); $message = $formatter->format('en', $chooseMessage, array( 'gender_of_host' => 'male', 'num_guests' => 10, @@ -85,4 +85,9 @@ public function provideDataForFormat() ), ); } + + protected function getMessageFormatter() + { + return new IntlMessageFormatter(); + } } diff --git a/src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php b/src/Symfony/Component/Translation/Tests/Formatter/LegacyIntlMessageFormatterTest.php similarity index 53% rename from src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php rename to src/Symfony/Component/Translation/Tests/Formatter/LegacyIntlMessageFormatterTest.php index e0319aa22acdd..76c3a61253400 100644 --- a/src/Symfony/Component/Translation/Tests/Formatter/DefaultMessageFormatterTest.php +++ b/src/Symfony/Component/Translation/Tests/Formatter/LegacyIntlMessageFormatterTest.php @@ -11,21 +11,21 @@ namespace Symfony\Component\Translation\Tests\Formatter; -use Symfony\Component\Translation\Formatter\DefaultMessageFormatter; +use Symfony\Component\Translation\Formatter\LegacyIntlMessageFormatter; -class DefaultMessageFormatterTest extends \PHPUnit_Framework_TestCase +class LegacyIntlMessageFormatterTest extends IntlMessageFormatterTest { /** - * @dataProvider provideDataForFormat + * @dataProvider legacyMessages */ - public function testFormat($expected, $message, $arguments) + public function testFormatLegacyMessages($expected, $message, $arguments) { - $formatter = new DefaultMessageFormatter(); + $formatter = $this->getMessageFormatter(); $this->assertEquals($expected, $formatter->format('en', $message, $arguments)); } - public function provideDataForFormat() + public function legacyMessages() { return array( array( @@ -38,17 +38,16 @@ public function provideDataForFormat() 'There are %count% apples', array('%count%' => 5), ), + array( + 'There are 5 apples', + 'There are {{count}} apples', + array('{{count}}' => 5), + ), ); } - private function mockMessageSelector($willCallChoose) + protected function getMessageFormatter() { - $mock = $this->getMock('Symfony\Component\Translation\MessageSelector'); - - $mock->expects($willCallChoose ? $this->once() : $this->never()) - ->method('choose') - ->will($this->returnValue('Message')); - - return $mock; + return new LegacyIntlMessageFormatter(); } } diff --git a/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php b/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php index 352dd318dc73c..188d53dd44b3f 100644 --- a/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/IdentityTranslatorTest.php @@ -28,6 +28,7 @@ public function testTrans($expected, $id, $parameters) /** * @dataProvider getTransChoiceTests + * @group legacy */ public function testTransChoiceWithExplicitLocale($expected, $id, $number, $parameters) { @@ -39,6 +40,7 @@ public function testTransChoiceWithExplicitLocale($expected, $id, $number, $para /** * @dataProvider getTransChoiceTests + * @group legacy */ public function testTransChoiceWithDefaultLocale($expected, $id, $number, $parameters) { diff --git a/src/Symfony/Component/Translation/Tests/LoggingTranslatorTest.php b/src/Symfony/Component/Translation/Tests/LoggingTranslatorTest.php index ab98d72e7425c..d1de0f69cc9c5 100644 --- a/src/Symfony/Component/Translation/Tests/LoggingTranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/LoggingTranslatorTest.php @@ -27,17 +27,19 @@ protected function setUp() public function testTransWithNoTranslationIsLogged() { $logger = $this->getMock('Psr\Log\LoggerInterface'); - $logger->expects($this->exactly(2)) + $logger->expects($this->any()) ->method('warning') ->with('Translation not found.') ; $translator = new Translator('ar'); $loggableTranslator = new LoggingTranslator($translator, $logger); - $loggableTranslator->transChoice('some_message2', 10, array('%count%' => 10)); $loggableTranslator->trans('bar'); } + /** + * @group legacy + */ public function testTransChoiceFallbackIsLogged() { $logger = $this->getMock('Psr\Log\LoggerInterface'); diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 74d111b58f594..e777e5a7cf3ec 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Component\Translation\Formatter\IntlMessageFormatter; class TranslatorTest extends \PHPUnit_Framework_TestCase { @@ -23,7 +24,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase */ public function testConstructorInvalidLocale($locale) { - $translator = new Translator($locale); + $this->getTranslator($locale); } /** @@ -31,21 +32,21 @@ public function testConstructorInvalidLocale($locale) */ public function testConstructorValidLocale($locale) { - $translator = new Translator($locale); + $translator = $this->getTranslator($locale); $this->assertEquals($locale, $translator->getLocale()); } public function testConstructorWithoutLocale() { - $translator = new Translator(null); + $translator = $this->getTranslator(null); $this->assertNull($translator->getLocale()); } public function testSetGetLocale() { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $this->assertEquals('en', $translator->getLocale()); @@ -59,7 +60,7 @@ public function testSetGetLocale() */ public function testSetInvalidLocale($locale) { - $translator = new Translator('fr'); + $translator = $this->getTranslator('fr'); $translator->setLocale($locale); } @@ -68,7 +69,7 @@ public function testSetInvalidLocale($locale) */ public function testSetValidLocale($locale) { - $translator = new Translator($locale); + $translator = $this->getTranslator($locale); $translator->setLocale($locale); $this->assertEquals($locale, $translator->getLocale()); @@ -76,7 +77,7 @@ public function testSetValidLocale($locale) public function testGetCatalogue() { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $this->assertEquals(new MessageCatalogue('en'), $translator->getCatalogue()); @@ -93,7 +94,7 @@ public function testGetCatalogueReturnsConsolidatedCatalogue() */ $locale = 'whatever'; - $translator = new Translator($locale); + $translator = $this->getTranslator($locale); $translator->addLoader('loader-a', new ArrayLoader()); $translator->addLoader('loader-b', new ArrayLoader()); $translator->addResource('loader-a', array('foo' => 'foofoo'), $locale, 'domain-a'); @@ -110,7 +111,7 @@ public function testGetCatalogueReturnsConsolidatedCatalogue() public function testSetFallbackLocales() { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); $translator->addResource('array', array('bar' => 'foobar'), 'fr'); @@ -124,7 +125,7 @@ public function testSetFallbackLocales() public function testSetFallbackLocalesMultiple() { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foo (en)'), 'en'); $translator->addResource('array', array('bar' => 'bar (fr)'), 'fr'); @@ -142,7 +143,7 @@ public function testSetFallbackLocalesMultiple() */ public function testSetFallbackInvalidLocales($locale) { - $translator = new Translator('fr'); + $translator = $this->getTranslator('fr'); $translator->setFallbackLocales(array('fr', $locale)); } @@ -151,14 +152,14 @@ public function testSetFallbackInvalidLocales($locale) */ public function testSetFallbackValidLocales($locale) { - $translator = new Translator($locale); + $translator = $this->getTranslator($locale); $translator->setFallbackLocales(array('fr', $locale)); // no assertion. this method just asserts that no exception is thrown } public function testTransWithFallbackLocale() { - $translator = new Translator('fr_FR'); + $translator = $this->getTranslator('fr_FR'); $translator->setFallbackLocales(array('en')); $translator->addLoader('array', new ArrayLoader()); @@ -173,7 +174,7 @@ public function testTransWithFallbackLocale() */ public function testAddResourceInvalidLocales($locale) { - $translator = new Translator('fr'); + $translator = $this->getTranslator('fr'); $translator->addResource('array', array('foo' => 'foofoo'), $locale); } @@ -182,14 +183,14 @@ public function testAddResourceInvalidLocales($locale) */ public function testAddResourceValidLocales($locale) { - $translator = new Translator('fr'); + $translator = $this->getTranslator('fr'); $translator->addResource('array', array('foo' => 'foofoo'), $locale); // no assertion. this method just asserts that no exception is thrown } public function testAddResourceAfterTrans() { - $translator = new Translator('fr'); + $translator = $this->getTranslator('fr'); $translator->addLoader('array', new ArrayLoader()); $translator->setFallbackLocales(array('en')); @@ -208,7 +209,7 @@ public function testAddResourceAfterTrans() public function testTransWithoutFallbackLocaleFile($format, $loader) { $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader; - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader($format, new $loaderClass()); $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en'); $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en'); @@ -223,7 +224,7 @@ public function testTransWithoutFallbackLocaleFile($format, $loader) public function testTransWithFallbackLocaleFile($format, $loader) { $loaderClass = 'Symfony\\Component\\Translation\\Loader\\'.$loader; - $translator = new Translator('en_GB'); + $translator = $this->getTranslator('en_GB'); $translator->addLoader($format, new $loaderClass()); $translator->addResource($format, __DIR__.'/fixtures/non-existing', 'en_GB'); $translator->addResource($format, __DIR__.'/fixtures/resources.'.$format, 'en', 'resources'); @@ -233,7 +234,7 @@ public function testTransWithFallbackLocaleFile($format, $loader) public function testTransWithFallbackLocaleBis() { - $translator = new Translator('en_US'); + $translator = $this->getTranslator('en_US'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en_US'); $translator->addResource('array', array('bar' => 'foobar'), 'en'); @@ -242,7 +243,7 @@ public function testTransWithFallbackLocaleBis() public function testTransWithFallbackLocaleTer() { - $translator = new Translator('fr_FR'); + $translator = $this->getTranslator('fr_FR'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foo (en_US)'), 'en_US'); $translator->addResource('array', array('bar' => 'bar (en)'), 'en'); @@ -255,7 +256,7 @@ public function testTransWithFallbackLocaleTer() public function testTransNonExistentWithFallback() { - $translator = new Translator('fr'); + $translator = $this->getTranslator('fr'); $translator->setFallbackLocales(array('en')); $translator->addLoader('array', new ArrayLoader()); $this->assertEquals('non-existent', $translator->trans('non-existent')); @@ -266,7 +267,7 @@ public function testTransNonExistentWithFallback() */ public function testWhenAResourceHasNoRegisteredLoader() { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); $translator->trans('foo'); @@ -277,20 +278,32 @@ public function testWhenAResourceHasNoRegisteredLoader() */ public function testTrans($expected, $id, $translation, $parameters, $locale, $domain) { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array((string) $id => $translation), $locale, $domain); $this->assertEquals($expected, $translator->trans($id, $parameters, $domain, $locale)); } + /** + * @group legacy + */ + public function testTransLagacyMessages() + { + $translator = $this->getTranslator('en'); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', array('Symfony is {what}!' => 'Symfony is %what%!'), 'en', 'messages'); + + $this->assertEquals('Symfony is awesome!', $translator->trans('Symfony is {what}!', array('%what%' => 'awesome'))); + } + /** * @dataProvider getInvalidLocalesTests * @expectedException \InvalidArgumentException */ public function testTransInvalidLocale($locale) { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); @@ -302,7 +315,7 @@ public function testTransInvalidLocale($locale) */ public function testTransValidLocale($locale) { - $translator = new Translator($locale); + $translator = $this->getTranslator($locale); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('test' => 'OK'), $locale); @@ -315,7 +328,7 @@ public function testTransValidLocale($locale) */ public function testFlattenedTrans($expected, $messages, $id) { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', $messages, 'fr', ''); @@ -324,10 +337,11 @@ public function testFlattenedTrans($expected, $messages, $id) /** * @dataProvider getTransChoiceTests + * @group legacy */ public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain) { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array((string) $id => $translation), $locale, $domain); @@ -337,10 +351,11 @@ public function testTransChoice($expected, $id, $translation, $number, $paramete /** * @dataProvider getInvalidLocalesTests * @expectedException \InvalidArgumentException + * @group legacy */ public function testTransChoiceInvalidLocale($locale) { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); @@ -349,10 +364,11 @@ public function testTransChoiceInvalidLocale($locale) /** * @dataProvider getValidLocalesTests + * @group legacy */ public function testTransChoiceValidLocale($locale) { - $translator = new Translator('en'); + $translator = $this->getTranslator('en'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('foo' => 'foofoo'), 'en'); @@ -379,7 +395,7 @@ public function getTransTests() { return array( array('Symfony est super !', 'Symfony is great!', 'Symfony est super !', array(), 'fr', ''), - array('Symfony est awesome !', 'Symfony is %what%!', 'Symfony est %what% !', array('%what%' => 'awesome'), 'fr', ''), + array('Symfony est awesome !', 'Symfony is {0}!', 'Symfony est {0} !', array('awesome'), 'fr', ''), array('Symfony est super !', new StringClass('Symfony is great!'), 'Symfony est super !', array(), 'fr', ''), ); } @@ -464,9 +480,12 @@ public function getValidLocalesTests() ); } + /** + * @group legacy + */ public function testTransChoiceFallback() { - $translator = new Translator('ru'); + $translator = $this->getTranslator('ru'); $translator->setFallbackLocales(array('en')); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en'); @@ -474,9 +493,12 @@ public function testTransChoiceFallback() $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10))); } + /** + * @group legacy + */ public function testTransChoiceFallbackBis() { - $translator = new Translator('ru'); + $translator = $this->getTranslator('ru'); $translator->setFallbackLocales(array('en_US', 'en')); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array('some_message2' => 'one thing|%count% things'), 'en_US'); @@ -484,9 +506,12 @@ public function testTransChoiceFallbackBis() $this->assertEquals('10 things', $translator->transChoice('some_message2', 10, array('%count%' => 10))); } + /** + * @group legacy + */ public function testTransChoiceFallbackWithNoTranslation() { - $translator = new Translator('ru'); + $translator = $this->getTranslator('ru'); $translator->setFallbackLocales(array('en')); $translator->addLoader('array', new ArrayLoader()); @@ -505,7 +530,7 @@ public function testLegacyGetMessages($resources, $locale, $expected) $_locale = null !== $locale ? $locale : reset($locales); $locales = array_slice($locales, 0, array_search($_locale, $locales)); - $translator = new Translator($_locale); + $translator = $this->getTranslator($_locale); $translator->setFallbackLocales(array_reverse($locales)); $translator->addLoader('array', new ArrayLoader()); foreach ($resources as $_locale => $domainMessages) { @@ -609,6 +634,11 @@ public function dataProviderGetMessages() ), ); } + + private function getTranslator($locale) + { + return new Translator($locale, new IntlMessageFormatter()); + } } class StringClass diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 4e652fa84f93f..697abfe9073a3 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -17,7 +17,7 @@ use Symfony\Component\Config\ConfigCacheFactoryInterface; use Symfony\Component\Config\ConfigCacheFactory; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; -use Symfony\Component\Translation\Formatter\DefaultMessageFormatter; +use Symfony\Component\Translation\Formatter\LegacyIntlMessageFormatter; /** * Translator. @@ -97,12 +97,12 @@ public function __construct($locale, $formatter = null, $cacheDir = null, $debug if ($formatter instanceof MessageSelector) { @trigger_error('Passing a MessageSelector instance into the '.__METHOD__.' as a second argument is deprecated since version 2.8 and will be removed in 3.0. Inject a MessageFormatterInterface instance instead.', E_USER_DEPRECATED); $this->selector = $formatter; - $formatter = new DefaultMessageFormatter(); + $formatter = new LegacyIntlMessageFormatter(); } else { $this->selector = new MessageSelector(); } - $this->formatter = $formatter ?: new DefaultMessageFormatter(); + $this->formatter = $formatter ?: new LegacyIntlMessageFormatter(); if (!$this->formatter instanceof MessageFormatterInterface) { throw new \InvalidArgumentException(sprintf('The message formatter "%s" must implement MessageFormatterInterface.', get_class($this->formatter))); } @@ -256,6 +256,7 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Rely on the MessageFormatterInterface and TranslatorInterface::trans() method instead.', E_USER_DEPRECATED); if (null === $domain) { $domain = 'messages'; } diff --git a/src/Symfony/Component/Translation/TranslatorInterface.php b/src/Symfony/Component/Translation/TranslatorInterface.php index fe1a8659e2c93..f76dad6de1f46 100644 --- a/src/Symfony/Component/Translation/TranslatorInterface.php +++ b/src/Symfony/Component/Translation/TranslatorInterface.php @@ -39,6 +39,9 @@ public function trans($id, array $parameters = array(), $domain = null, $locale /** * Translates the given choice message by choosing a translation according to a number. * + * @deprecated since version 2.8, to be removed in 3.0. + * Use the {@link trans} method instead. + * * @param string $id The message id (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 array $parameters An array of parameters for the message diff --git a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php index 6995d25817988..d281f47d46a63 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php @@ -521,7 +521,6 @@ public function testAddCustomizedViolation() $context->buildViolation('Message %param%') ->setParameter('%param%', 'value') ->setInvalidValue('Invalid value') - ->setPlural(2) ->setCode(42) ->addViolation(); }; @@ -538,7 +537,7 @@ public function testAddCustomizedViolation() $this->assertSame('', $violations[0]->getPropertyPath()); $this->assertSame($entity, $violations[0]->getRoot()); $this->assertSame('Invalid value', $violations[0]->getInvalidValue()); - $this->assertSame(2, $violations[0]->getPlural()); + $this->assertNull($violations[0]->getPlural()); $this->assertSame(42, $violations[0]->getCode()); } 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