diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index c6e99dea0b..d02fc13c6f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -100,9 +100,7 @@ class FrameworkExtension extends Extension $this->registerUserConfiguration($config, $container); } - if (array_key_exists('translator', $config)) { - $this->registerTranslatorConfiguration($config, $container); - } + $this->registerTranslatorConfiguration($config, $container); $this->addCompiledClasses($container, array( 'Symfony\\Component\\HttpFoundation\\ParameterBag', @@ -234,40 +232,49 @@ class FrameworkExtension extends Extension */ protected function registerTranslatorConfiguration($config, ContainerBuilder $container) { - $config = $config['translator']; + $first = false; + if (!$container->hasDefinition('translator')) { + $first = true; + $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config')); + $loader->load('translation.xml'); + } + + $config = array_key_exists('translator', $config) ? $config['translator'] : array(); if (!is_array($config)) { $config = array(); } - if (!$container->hasDefinition('translator')) { - $loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config')); - $loader->load('translation.xml'); + if (!isset($config['translator']['enabled']) || $config['translator']['enabled']) { + // use the "real" translator + $container->setDefinition('translator', $container->findDefinition('translator.real')); - // translation directories - $dirs = array(); - foreach (array_reverse($container->getParameter('kernel.bundles')) as $bundle) { - $reflection = new \ReflectionClass($bundle); - if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) { + if ($first) { + // translation directories + $dirs = array(); + foreach (array_reverse($container->getParameter('kernel.bundles')) as $bundle) { + $reflection = new \ReflectionClass($bundle); + if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) { + $dirs[] = $dir; + } + } + if (is_dir($dir = $container->getParameter('kernel.root_dir').'/translations')) { $dirs[] = $dir; } - } - if (is_dir($dir = $container->getParameter('kernel.root_dir').'/translations')) { - $dirs[] = $dir; - } - // translation resources - $resources = array(); - if ($dirs) { - $finder = new Finder(); - $finder->files()->filter(function (\SplFileInfo $file) { return 2 === substr_count($file->getBasename(), '.'); })->in($dirs); - foreach ($finder as $file) { - // filename is domain.locale.format - list($domain, $locale, $format) = explode('.', $file->getBasename()); + // translation resources + $resources = array(); + if ($dirs) { + $finder = new Finder(); + $finder->files()->filter(function (\SplFileInfo $file) { return 2 === substr_count($file->getBasename(), '.'); })->in($dirs); + foreach ($finder as $file) { + // filename is domain.locale.format + list($domain, $locale, $format) = explode('.', $file->getBasename()); - $resources[] = array($format, (string) $file, $locale, $domain); + $resources[] = array($format, (string) $file, $locale, $domain); + } } + $container->setParameter('translation.resources', $resources); } - $container->setParameter('translation.resources', $resources); } if (array_key_exists('fallback', $config)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml index 2a914004c1..ed9021fc45 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml @@ -6,14 +6,17 @@ Symfony\Bundle\FrameworkBundle\Translation\Translator + Symfony\Component\Translation\IdentityTranslator + Symfony\Component\Translation\MessageSelector Symfony\Component\Translation\Loader\PhpFileLoader Symfony\Component\Translation\Loader\XliffFileLoader en - + + %kernel.cache_dir%/translations %kernel.debug% @@ -22,6 +25,12 @@ %translator.fallback_locale% + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index b97a7f8074..e07ee431e2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -53,8 +53,9 @@ class FrameworkExtensionTest extends TestCase 'Symfony\\Framework' => __DIR__ . '/../../../Framework', ), 'kernel.bundles' => array( - 'FrameworkBundle', + 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle', ), + 'kernel.root_dir' => __DIR__, 'kernel.debug' => false, 'kernel.compiled_classes' => array(), ))); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index acdbc33485..454ad26576 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -4,6 +4,7 @@ namespace Symfony\Bundle\FrameworkBundle\Translation; use Symfony\Component\Translation\Translator as BaseTranslator; use Symfony\Component\Translation\Loader\LoaderInterface; +use Symfony\Component\Translation\MessageSelector; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Session; @@ -35,13 +36,14 @@ class Translator extends BaseTranslator * * debug: Whether to enable debugging or not (false by default) * * @param ContainerInterface $container A ContainerInterface instance + * @param MessageSelector $selector The message selector for pluralization * @param array $options An array of options * @param Session $session A Session instance */ - public function __construct(ContainerInterface $container, array $options = array(), Session $session = null) + public function __construct(ContainerInterface $container, MessageSelector $selector, array $options = array(), Session $session = null) { if (null !== $session) { - parent::__construct($session->getLocale()); + parent::__construct($session->getLocale(), $selector); } $this->container = $container; diff --git a/src/Symfony/Component/Translation/IdentityTranslator.php b/src/Symfony/Component/Translation/IdentityTranslator.php new file mode 100644 index 0000000000..6dc41afc2c --- /dev/null +++ b/src/Symfony/Component/Translation/IdentityTranslator.php @@ -0,0 +1,55 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * IdentityTranslator does not translate anything. + * + * @author Fabien Potencier + */ +class IdentityTranslator implements TranslatorInterface +{ + protected $selector; + + /** + * Constructor. + * + * @param MessageSelector $selector The message selector for pluralization + */ + public function __construct(MessageSelector $selector) + { + $this->selector = $selector; + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + } + + /** + * {@inheritdoc} + */ + public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null) + { + return strtr($id, $parameters); + } + + /** + * {@inheritdoc} + */ + public function transChoice($id, $number, array $parameters = array(), $domain = 'messages', $locale = null) + { + return strtr($this->selector->choose($id, (int) $number, $locale), $parameters); + } +} diff --git a/src/Symfony/Component/Translation/MessageSelector.php b/src/Symfony/Component/Translation/MessageSelector.php new file mode 100644 index 0000000000..f5cc34ae26 --- /dev/null +++ b/src/Symfony/Component/Translation/MessageSelector.php @@ -0,0 +1,52 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * MessageSelector. + * + * @author Fabien Potencier + */ +class MessageSelector +{ + public function choose($message, $number, $locale) + { + $parts = explode('|', $message); + $explicitRules = array(); + $standardRules = array(); + foreach ($parts as $part) { + $part = trim($part); + + if (preg_match('/^(?'.Range::getRangeRegexp().')\s+(?.+?)$/x', $part, $matches)) { + $explicitRules[$matches['range']] = $matches['message']; + } elseif (preg_match('/^\w+\: +(.+)$/', $part, $matches)) { + $standardRules[] = $matches[1]; + } else { + $standardRules[] = $part; + } + } + + // try to match an explicit rule, then fallback to the standard ones + foreach ($explicitRules as $range => $m) { + if (Range::test($number, $range)) { + return $m; + } + } + + $position = PluralizationRules::get($number, $locale); + if (!isset($standardRules[$position])) { + throw new \InvalidArgumentException('Unable to choose a translation.'); + } + + return $standardRules[$position]; + } +} diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 583a949d67..b85a332ef8 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -25,15 +25,18 @@ class Translator implements TranslatorInterface protected $fallbackLocale; protected $loaders; protected $resources; + protected $selector; /** * Constructor. * - * @param string $locale The locale + * @param string $locale The locale + * @param MessageSelector $selector The message selector for pluralization */ - public function __construct($locale = null) + public function __construct($locale = null, MessageSelector $selector) { $this->locale = $locale; + $this->selector = $selector; $this->loaders = array(); $this->resources = array(); $this->catalogues = array(); @@ -119,39 +122,7 @@ class Translator implements TranslatorInterface $this->loadCatalogue($locale); } - return strtr($this->chooseMessage($this->catalogues[$locale]->getMessage($id, $domain), (int) $number, $locale), $parameters); - } - - protected function chooseMessage($message, $number, $locale) - { - $parts = explode('|', $message); - $explicitRules = array(); - $standardRules = array(); - foreach ($parts as $part) { - $part = trim($part); - - if (preg_match('/^(?'.Range::getRangeRegexp().')\s+(?.+?)$/x', $part, $matches)) { - $explicitRules[$matches['range']] = $matches['message']; - } elseif (preg_match('/^\w+\: +(.+)$/', $part, $matches)) { - $standardRules[] = $matches[1]; - } else { - $standardRules[] = $part; - } - } - - // try to match an explicit rule, then fallback to the standard ones - foreach ($explicitRules as $range => $m) { - if (Range::test($number, $range)) { - return $m; - } - } - - $position = PluralizationRules::get($number, $locale); - if (!isset($standardRules[$position])) { - throw new \InvalidArgumentException('Unable to choose a translation.'); - } - - return $standardRules[$position]; + return strtr($this->selector->choose($this->catalogues[$locale]->getMessage($id, $domain), (int) $number, $locale), $parameters); } protected function loadCatalogue($locale) diff --git a/tests/Symfony/Tests/Component/Translation/TranslatorTest.php b/tests/Symfony/Tests/Component/Translation/TranslatorTest.php index 185626085e..950da78647 100644 --- a/tests/Symfony/Tests/Component/Translation/TranslatorTest.php +++ b/tests/Symfony/Tests/Component/Translation/TranslatorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Tests\Component\Translation; use Symfony\Component\Translation\Translator; +use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\Loader\ArrayLoader; class TranslatorTest extends \PHPUnit_Framework_TestCase @@ -21,7 +22,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase */ public function testTrans($expected, $id, $translation, $parameters, $locale, $domain) { - $translator = new Translator(); + $translator = new Translator('en', new MessageSelector()); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array($id => $translation), $locale, $domain); @@ -33,7 +34,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase */ public function testTransChoice($expected, $id, $translation, $number, $parameters, $locale, $domain) { - $translator = new Translator(); + $translator = new Translator('en', new MessageSelector()); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', array($id => $translation), $locale, $domain);