Commit 36cfde2b authored by freepius44's avatar freepius44

A solution to resolve #983 (bad comportment of Translator)

parent 78a9a90a
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex\Provider\Translation;
use Pimple\Container;
use Symfony\Component\Translation\Translator as BaseTranslator;
use Symfony\Component\Translation\MessageSelector;
/**
* Translator that gets the current locale from the container.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Translator extends BaseTranslator
{
protected $app;
public function __construct(Container $app, MessageSelector $selector)
{
$this->app = $app;
parent::__construct(null, $selector);
}
public function getLocale()
{
return $this->app['locale'];
}
public function setLocale($locale)
{
$this->app['locale'] = $locale;
parent::setLocale($locale);
}
}
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex\Provider\Translation;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Translation\TranslatorInterface;
/**
* Initializes the Translator locale based on the Request locale.
*
* This listener works in 2 modes:
*
* * 2.3 compatibility mode where you must call setRequest whenever the Request changes.
* * 2.4+ mode where you must pass a RequestStack instance in the constructor.
*
* @author Mathieu Poisbeau <freepius44@gmail.com>
*/
class TranslatorListener implements EventSubscriberInterface
{
protected $translator;
protected $requestStack;
/**
* RequestStack will become required in 3.0.
*/
public function __construct(TranslatorInterface $translator, RequestStack $requestStack = null)
{
$this->translator = $translator;
$this->requestStack = $requestStack;
}
/**
* Sets the current Request.
*
* This method was used to synchronize the Request, but as the HttpKernel
* is doing that automatically now, you should never call it directly.
* It is kept public for BC with the 2.3 version.
*
* @param Request|null $request A Request instance
*
* @deprecated Deprecated since version 2.4, to be removed in 3.0.
*/
public function setRequest(Request $request = null)
{
if (null === $request) {
return;
}
$this->translator->setLocale($request->getLocale());
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->translator->setLocale($event->getRequest()->getLocale());
}
public function onKernelFinishRequest(FinishRequestEvent $event)
{
if (null === $this->requestStack) {
return; // removed when requestStack is required
}
if (null !== $parentRequest = $this->requestStack->getParentRequest()) {
$this->translator->setLocale($parentRequest->getLocale());
}
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(array('onKernelRequest', 0)),
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
);
}
}
......@@ -13,26 +13,29 @@ namespace Silex\Provider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Silex\Provider\Translation\Translator;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Loader\XliffFileLoader;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Silex\Api\EventListenerProviderInterface;
use Silex\Provider\Translation\TranslatorListener;
/**
* Symfony Translation component Provider.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TranslationServiceProvider implements ServiceProviderInterface
class TranslationServiceProvider implements ServiceProviderInterface, EventListenerProviderInterface
{
public function register(Container $app)
{
$app['translator'] = function ($app) {
if (!isset($app['locale'])) {
throw new \LogicException('You must register the LocaleServiceProvider to use the TranslationServiceProvider');
throw new \LogicException('You must define \'locale\' parameter or register the LocaleServiceProvider to use the TranslationServiceProvider');
}
$translator = new Translator($app, $app['translator.message_selector']);
$translator = new Translator($app['locale'], $app['translator.message_selector']);
$translator->setFallbackLocales($app['locale_fallbacks']);
$translator->addLoader('array', new ArrayLoader());
$translator->addLoader('xliff', new XliffFileLoader());
......@@ -46,6 +49,10 @@ class TranslationServiceProvider implements ServiceProviderInterface
return $translator;
};
$app['translator.listener'] = function ($app) {
return new TranslatorListener($app['translator'], $app['request_stack']);
};
$app['translator.message_selector'] = function () {
return new MessageSelector();
};
......@@ -53,4 +60,10 @@ class TranslationServiceProvider implements ServiceProviderInterface
$app['translator.domains'] = array();
$app['locale_fallbacks'] = array('en');
}
public function subscribe(Container $app, EventDispatcherInterface $dispatcher)
{
$dispatcher->addSubscriber($app['translator.listener']);
}
}
......@@ -14,6 +14,8 @@ namespace Silex\Tests\Provider;
use Silex\Application;
use Silex\Provider\TranslationServiceProvider;
use Silex\Provider\LocaleServiceProvider;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* TranslationProvider test cases.
......@@ -118,26 +120,62 @@ class TranslationServiceProviderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('The german translation', $result);
}
public function testChangingLocale()
public function testLocale()
{
$app = $this->getPreparedApp();
$app->get('/', function () use ($app) { return $app['translator']->getLocale(); });
$response = $app->handle(Request::create('/'));
$this->assertEquals('en', $response->getContent());
$this->assertEquals('The translation', $app['translator']->trans('key1'));
$app['locale'] = 'de';
$app = $this->getPreparedApp();
$app->get('/', function () use ($app) { return $app['translator']->getLocale(); });
$request = Request::create('/');
$request->setLocale('fr');
$response = $app->handle($request);
$this->assertEquals('fr', $response->getContent());
$this->assertEquals('The german translation', $app['translator']->trans('key1'));
$app = $this->getPreparedApp();
$app->get('/{_locale}', function () use ($app) { return $app['translator']->getLocale(); });
$response = $app->handle(Request::create('/es'));
$this->assertEquals('es', $response->getContent());
}
public function testChangingLocaleViaTranslator()
public function testLocaleInSubRequests()
{
$app = $this->getPreparedApp();
$app->get('/embed/{_locale}', function () use ($app) { return $app['translator']->getLocale(); });
$app->get('/{_locale}', function () use ($app) {
return $app['translator']->getLocale().
$app->handle(Request::create('/embed/es'), HttpKernelInterface::SUB_REQUEST)->getContent().
$app['translator']->getLocale();
});
$response = $app->handle(Request::create('/fr'));
$this->assertEquals('fresfr', $response->getContent());
$this->assertEquals('The translation', $app['translator']->trans('key1'));
$app['translator']->setLocale('de');
$app = $this->getPreparedApp();
$app->get('/embed', function () use ($app) { return $app['translator']->getLocale(); });
$app->get('/{_locale}', function () use ($app) {
return $app['translator']->getLocale().
$app->handle(Request::create('/embed'), HttpKernelInterface::SUB_REQUEST)->getContent().
$app['translator']->getLocale();
});
$response = $app->handle(Request::create('/fr'));
// locale in sub-request must be "en" as this is the value if the sub-request is converted to an ESI
$this->assertEquals('frenfr', $response->getContent());
}
$this->assertEquals('The german translation', $app['translator']->trans('key1'));
$this->assertEquals('de', $app['locale']);
public function testLocaleWithBefore()
{
$app = $this->getPreparedApp();
$app->before(function (Request $request) { $request->setLocale('fr'); });
$app->get('/embed', function () use ($app) { return $app['translator']->getLocale(); });
$app->get('/', function () use ($app) {
return $app['translator']->getLocale().
$app->handle(Request::create('/embed'), HttpKernelInterface::SUB_REQUEST)->getContent().
$app['translator']->getLocale();
});
$response = $app->handle(Request::create('/'));
// locale in sub-request is "en" as the before filter is only executed for the main request
$this->assertEquals('frenfr', $response->getContent());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment