Browse Source

added an IdentityTranslator to make it possible to always relies on the translator service, even if none is configured

Fabien Potencier 14 năm trước cách đây
mục cha
commit
707205410e

+ 33 - 26
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)) {

+ 10 - 1
src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml

@@ -6,14 +6,17 @@
 
     <parameters>
         <parameter key="translator.class">Symfony\Bundle\FrameworkBundle\Translation\Translator</parameter>
+        <parameter key="translator.identity.class">Symfony\Component\Translation\IdentityTranslator</parameter>
+        <parameter key="translator.selector.class">Symfony\Component\Translation\MessageSelector</parameter>
         <parameter key="translation.loader.php.class">Symfony\Component\Translation\Loader\PhpFileLoader</parameter>
         <parameter key="translation.loader.xliff.class">Symfony\Component\Translation\Loader\XliffFileLoader</parameter>
         <parameter key="translator.fallback_locale">en</parameter>
     </parameters>
 
     <services>
-        <service id="translator" class="%translator.class%">
+        <service id="translator.real" class="%translator.class%">
             <argument type="service" id="service_container" />
+            <argument type="service" id="translator.selector" />
             <argument type="collection">
                 <argument key="cache_dir">%kernel.cache_dir%/translations</argument>
                 <argument key="debug">%kernel.debug%</argument>
@@ -22,6 +25,12 @@
             <call method="setFallbackLocale"><argument>%translator.fallback_locale%</argument></call>
         </service>
 
+        <service id="translator" class="%translator.identity.class%">
+            <argument type="service" id="translator.selector" />
+        </service>
+
+        <service id="translator.selector" class="%translator.selector.class%" />
+
         <service id="translation.loader.php" class="%translation.loader.php.class%">
             <tag name="translation.loader" alias="php" />
         </service>

+ 2 - 1
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(),
         )));

+ 4 - 2
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;

+ 55 - 0
src/Symfony/Component/Translation/IdentityTranslator.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace Symfony\Component\Translation;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * 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 <fabien.potencier@symfony-project.com>
+ */
+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);
+    }
+}

+ 52 - 0
src/Symfony/Component/Translation/MessageSelector.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace Symfony\Component\Translation;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * MessageSelector.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ */
+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>'.Range::getRangeRegexp().')\s+(?<message>.+?)$/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];
+    }
+}

+ 6 - 35
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>'.Range::getRangeRegexp().')\s+(?<message>.+?)$/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)

+ 3 - 2
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);