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

This commit is contained in:
Fabien Potencier 2010-09-27 16:53:23 +02:00
parent 9c9edb3904
commit 707205410e
8 changed files with 165 additions and 67 deletions

View File

@ -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)) {

View File

@ -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>

View File

@ -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(),
)));

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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];
}
}

View File

@ -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)

View File

@ -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);