added an IdentityTranslator to make it possible to always relies on the translator service, even if none is configured
This commit is contained in:
parent
9c9edb3904
commit
707205410e
@ -100,9 +100,7 @@ class FrameworkExtension extends Extension
|
|||||||
$this->registerUserConfiguration($config, $container);
|
$this->registerUserConfiguration($config, $container);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('translator', $config)) {
|
$this->registerTranslatorConfiguration($config, $container);
|
||||||
$this->registerTranslatorConfiguration($config, $container);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addCompiledClasses($container, array(
|
$this->addCompiledClasses($container, array(
|
||||||
'Symfony\\Component\\HttpFoundation\\ParameterBag',
|
'Symfony\\Component\\HttpFoundation\\ParameterBag',
|
||||||
@ -234,40 +232,49 @@ class FrameworkExtension extends Extension
|
|||||||
*/
|
*/
|
||||||
protected function registerTranslatorConfiguration($config, ContainerBuilder $container)
|
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)) {
|
if (!is_array($config)) {
|
||||||
$config = array();
|
$config = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$container->hasDefinition('translator')) {
|
if (!isset($config['translator']['enabled']) || $config['translator']['enabled']) {
|
||||||
$loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
|
// use the "real" translator
|
||||||
$loader->load('translation.xml');
|
$container->setDefinition('translator', $container->findDefinition('translator.real'));
|
||||||
|
|
||||||
// translation directories
|
if ($first) {
|
||||||
$dirs = array();
|
// translation directories
|
||||||
foreach (array_reverse($container->getParameter('kernel.bundles')) as $bundle) {
|
$dirs = array();
|
||||||
$reflection = new \ReflectionClass($bundle);
|
foreach (array_reverse($container->getParameter('kernel.bundles')) as $bundle) {
|
||||||
if (is_dir($dir = dirname($reflection->getFilename()).'/Resources/translations')) {
|
$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;
|
$dirs[] = $dir;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (is_dir($dir = $container->getParameter('kernel.root_dir').'/translations')) {
|
|
||||||
$dirs[] = $dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
// translation resources
|
// translation resources
|
||||||
$resources = array();
|
$resources = array();
|
||||||
if ($dirs) {
|
if ($dirs) {
|
||||||
$finder = new Finder();
|
$finder = new Finder();
|
||||||
$finder->files()->filter(function (\SplFileInfo $file) { return 2 === substr_count($file->getBasename(), '.'); })->in($dirs);
|
$finder->files()->filter(function (\SplFileInfo $file) { return 2 === substr_count($file->getBasename(), '.'); })->in($dirs);
|
||||||
foreach ($finder as $file) {
|
foreach ($finder as $file) {
|
||||||
// filename is domain.locale.format
|
// filename is domain.locale.format
|
||||||
list($domain, $locale, $format) = explode('.', $file->getBasename());
|
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)) {
|
if (array_key_exists('fallback', $config)) {
|
||||||
|
@ -6,14 +6,17 @@
|
|||||||
|
|
||||||
<parameters>
|
<parameters>
|
||||||
<parameter key="translator.class">Symfony\Bundle\FrameworkBundle\Translation\Translator</parameter>
|
<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.php.class">Symfony\Component\Translation\Loader\PhpFileLoader</parameter>
|
||||||
<parameter key="translation.loader.xliff.class">Symfony\Component\Translation\Loader\XliffFileLoader</parameter>
|
<parameter key="translation.loader.xliff.class">Symfony\Component\Translation\Loader\XliffFileLoader</parameter>
|
||||||
<parameter key="translator.fallback_locale">en</parameter>
|
<parameter key="translator.fallback_locale">en</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
<service id="translator" class="%translator.class%">
|
<service id="translator.real" class="%translator.class%">
|
||||||
<argument type="service" id="service_container" />
|
<argument type="service" id="service_container" />
|
||||||
|
<argument type="service" id="translator.selector" />
|
||||||
<argument type="collection">
|
<argument type="collection">
|
||||||
<argument key="cache_dir">%kernel.cache_dir%/translations</argument>
|
<argument key="cache_dir">%kernel.cache_dir%/translations</argument>
|
||||||
<argument key="debug">%kernel.debug%</argument>
|
<argument key="debug">%kernel.debug%</argument>
|
||||||
@ -22,6 +25,12 @@
|
|||||||
<call method="setFallbackLocale"><argument>%translator.fallback_locale%</argument></call>
|
<call method="setFallbackLocale"><argument>%translator.fallback_locale%</argument></call>
|
||||||
</service>
|
</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%">
|
<service id="translation.loader.php" class="%translation.loader.php.class%">
|
||||||
<tag name="translation.loader" alias="php" />
|
<tag name="translation.loader" alias="php" />
|
||||||
</service>
|
</service>
|
||||||
|
@ -53,8 +53,9 @@ class FrameworkExtensionTest extends TestCase
|
|||||||
'Symfony\\Framework' => __DIR__ . '/../../../Framework',
|
'Symfony\\Framework' => __DIR__ . '/../../../Framework',
|
||||||
),
|
),
|
||||||
'kernel.bundles' => array(
|
'kernel.bundles' => array(
|
||||||
'FrameworkBundle',
|
'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle',
|
||||||
),
|
),
|
||||||
|
'kernel.root_dir' => __DIR__,
|
||||||
'kernel.debug' => false,
|
'kernel.debug' => false,
|
||||||
'kernel.compiled_classes' => array(),
|
'kernel.compiled_classes' => array(),
|
||||||
)));
|
)));
|
||||||
|
@ -4,6 +4,7 @@ namespace Symfony\Bundle\FrameworkBundle\Translation;
|
|||||||
|
|
||||||
use Symfony\Component\Translation\Translator as BaseTranslator;
|
use Symfony\Component\Translation\Translator as BaseTranslator;
|
||||||
use Symfony\Component\Translation\Loader\LoaderInterface;
|
use Symfony\Component\Translation\Loader\LoaderInterface;
|
||||||
|
use Symfony\Component\Translation\MessageSelector;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\HttpFoundation\Session;
|
use Symfony\Component\HttpFoundation\Session;
|
||||||
|
|
||||||
@ -35,13 +36,14 @@ class Translator extends BaseTranslator
|
|||||||
* * debug: Whether to enable debugging or not (false by default)
|
* * debug: Whether to enable debugging or not (false by default)
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container A ContainerInterface instance
|
* @param ContainerInterface $container A ContainerInterface instance
|
||||||
|
* @param MessageSelector $selector The message selector for pluralization
|
||||||
* @param array $options An array of options
|
* @param array $options An array of options
|
||||||
* @param Session $session A Session instance
|
* @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) {
|
if (null !== $session) {
|
||||||
parent::__construct($session->getLocale());
|
parent::__construct($session->getLocale(), $selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
|
55
src/Symfony/Component/Translation/IdentityTranslator.php
Normal file
55
src/Symfony/Component/Translation/IdentityTranslator.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
52
src/Symfony/Component/Translation/MessageSelector.php
Normal file
52
src/Symfony/Component/Translation/MessageSelector.php
Normal 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];
|
||||||
|
}
|
||||||
|
}
|
@ -25,15 +25,18 @@ class Translator implements TranslatorInterface
|
|||||||
protected $fallbackLocale;
|
protected $fallbackLocale;
|
||||||
protected $loaders;
|
protected $loaders;
|
||||||
protected $resources;
|
protected $resources;
|
||||||
|
protected $selector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* 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->locale = $locale;
|
||||||
|
$this->selector = $selector;
|
||||||
$this->loaders = array();
|
$this->loaders = array();
|
||||||
$this->resources = array();
|
$this->resources = array();
|
||||||
$this->catalogues = array();
|
$this->catalogues = array();
|
||||||
@ -119,39 +122,7 @@ class Translator implements TranslatorInterface
|
|||||||
$this->loadCatalogue($locale);
|
$this->loadCatalogue($locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
return strtr($this->chooseMessage($this->catalogues[$locale]->getMessage($id, $domain), (int) $number, $locale), $parameters);
|
return strtr($this->selector->choose($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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadCatalogue($locale)
|
protected function loadCatalogue($locale)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Tests\Component\Translation;
|
namespace Symfony\Tests\Component\Translation;
|
||||||
|
|
||||||
use Symfony\Component\Translation\Translator;
|
use Symfony\Component\Translation\Translator;
|
||||||
|
use Symfony\Component\Translation\MessageSelector;
|
||||||
use Symfony\Component\Translation\Loader\ArrayLoader;
|
use Symfony\Component\Translation\Loader\ArrayLoader;
|
||||||
|
|
||||||
class TranslatorTest extends \PHPUnit_Framework_TestCase
|
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)
|
public function testTrans($expected, $id, $translation, $parameters, $locale, $domain)
|
||||||
{
|
{
|
||||||
$translator = new Translator();
|
$translator = new Translator('en', new MessageSelector());
|
||||||
$translator->addLoader('array', new ArrayLoader());
|
$translator->addLoader('array', new ArrayLoader());
|
||||||
$translator->addResource('array', array($id => $translation), $locale, $domain);
|
$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)
|
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->addLoader('array', new ArrayLoader());
|
||||||
$translator->addResource('array', array($id => $translation), $locale, $domain);
|
$translator->addResource('array', array($id => $translation), $locale, $domain);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user