У меня есть полное решение, которое я обнаружил после некоторых исследований.Мое решение предполагает, что вы хотите, чтобы у каждого маршрута была локаль перед ним, даже вход в систему.Это модифицировано для поддержки Symfony 3, но я полагаю, что оно все еще будет работать в 2.
В этой версии также предполагается, что вы хотите использовать локаль браузера в качестве локали по умолчанию, если они идут по маршруту, например / admin,если они пойдут в / en / admin, он будет знать, что нужно использовать en locale.Это относится к примеру №2 ниже.
Так, например:
1. User Navigates To -> "/" -> (redirects) -> "/en/"
2. User Navigates To -> "/admin" -> (redirects) -> "/en/admin"
3. User Navigates To -> "/en/admin" -> (no redirects) -> "/en/admin"
Во всех сценариях языковой стандарт будет настроен правильно, как вы хотите, чтобы он использовался в вашей программе.
Вы можете просмотреть полное решение ниже, которое включает в себя, как заставить его работать с логином и безопасностью, иначе короткая версия, вероятно, будет работать для вас:
Полная версия
Symfony 3 перенаправляет все маршруты в текущую версию локали
Короткая версия
Чтобы сделать так, чтобы случай № 2 в моих примерах былвозможно, вам нужно сделать это с помощью httpKernal listner
LocaleRewriteListener.php
<?php
//src/AppBundle/EventListener/LocaleRewriteListener.php
namespace AppBundle\EventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\RouteCollection;
class LocaleRewriteListener implements EventSubscriberInterface
{
/**
* @var Symfony\Component\Routing\RouterInterface
*/
private $router;
/**
* @var routeCollection \Symfony\Component\Routing\RouteCollection
*/
private $routeCollection;
/**
* @var string
*/
private $defaultLocale;
/**
* @var array
*/
private $supportedLocales;
/**
* @var string
*/
private $localeRouteParam;
public function __construct(RouterInterface $router, $defaultLocale = 'en', array $supportedLocales = array('en'), $localeRouteParam = '_locale')
{
$this->router = $router;
$this->routeCollection = $router->getRouteCollection();
$this->defaultLocale = $defaultLocale;
$this->supportedLocales = $supportedLocales;
$this->localeRouteParam = $localeRouteParam;
}
public function isLocaleSupported($locale)
{
return in_array($locale, $this->supportedLocales);
}
public function onKernelRequest(GetResponseEvent $event)
{
//GOAL:
// Redirect all incoming requests to their /locale/route equivlent as long as the route will exists when we do so.
// Do nothing if it already has /locale/ in the route to prevent redirect loops
$request = $event->getRequest();
$path = $request->getPathInfo();
$route_exists = false; //by default assume route does not exist.
foreach($this->routeCollection as $routeObject){
$routePath = $routeObject->getPath();
if($routePath == "/{_locale}".$path){
$route_exists = true;
break;
}
}
//If the route does indeed exist then lets redirect there.
if($route_exists == true){
//Get the locale from the users browser.
$locale = $request->getPreferredLanguage();
//If no locale from browser or locale not in list of known locales supported then set to defaultLocale set in config.yml
if($locale=="" || $this->isLocaleSupported($locale)==false){
$locale = $request->getDefaultLocale();
}
$event->setResponse(new RedirectResponse("/".$locale.$path));
}
//Otherwise do nothing and continue on~
}
public static function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
Чтобы понять, как это работает, посмотрите интерфейс подписчика событий в документации Symfony.
Чтобы активировать список, вам необходимо настроить его в services.yml
services.yml
# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/book/service_container.html
parameters:
# parameter_name: value
services:
# service_name:
# class: AppBundle\Directory\ClassName
# arguments: ["@another_service_name", "plain_value", "%parameter_name%"]
appBundle.eventListeners.localeRewriteListener:
class: AppBundle\EventListener\LocaleRewriteListener
arguments: ["@router", "%kernel.default_locale%", "%locale_supported%"]
tags:
- { name: kernel.event_subscriber }
Наконец, это относится к переменнымкоторые должны быть определены в вашем config.yml
config.yml
# Put parameters here that don't need to change on each machine where the app is deployed
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: en
app.locales: en|es|zh
locale_supported: ['en','es','zh']
Наконец, на данный момент вам нужно убедиться, что все ваши маршруты начинаются с / {locale}.Пример этого приведен ниже в моем файле по умолчанию controller.php
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
/**
* @Route("/{_locale}", requirements={"_locale" = "%app.locales%"})
*/
class DefaultController extends Controller
{
/**
* @Route("/", name="home")
*/
public function indexAction(Request $request)
{
$translated = $this->get('translator')->trans('Symfony is great');
// replace this example code with whatever you need
return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'),
'translated' => $translated
]);
}
/**
* @Route("/admin", name="admin")
*/
public function adminAction(Request $request)
{
$translated = $this->get('translator')->trans('Symfony is great');
// replace this example code with whatever you need
return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'),
'translated' => $translated
]);
}
}
?>
Обратите внимание на требования requirements={"_locale" = "%app.locales%"}
, это ссылка на файл config.yml, поэтому вы должны определить эти требования только в одном месте для всех маршрутов..
Надеюсь, это кому-нибудь поможет:)