我的路由问题以及使用Symfony2构建的网站的国际化 如果我在routing.yml文件中定义路由,如下所示:
example:
pattern: /{_locale}/example
defaults: { _controller: ExampleBundle:Example:index, _locale: fr }
它适用于以下网址:
mysite.com/en/example
mysite.com/fr/example
但不适用于
mysite.com/example
是否只允许在URL结尾处使用可选占位符? 如果是,那么可能是显示网址的可能解决方案:
mysite.com/example
使用默认语言或将用户重定向到:
mysite.com/defaultlanguage/example
他访问时:
mysite.com/example. ?
我想弄清楚但到目前为止还没有成功。
感谢。
答案 0 :(得分:20)
如果有人对此感兴趣,我成功地在我的routing.yml
上添加了一个前缀,而没有使用其他捆绑包。
现在,这些URL工作正常:
www.example.com/
www.example.com//home/
www.example.com/fr/home/
www.example.com/en/home/
修改您的app/config/routing.yml
:
ex_example:
resource: "@ExExampleBundle/Resources/config/routing.yml"
prefix: /{_locale}
requirements:
_locale: |fr|en # put a pipe "|" first
然后,在您app/config/parameters.yml
中,您必须设置区域设置
parameters:
locale: en
有了这个,人们可以访问您的网站而无需输入特定的区域设置。
答案 1 :(得分:12)
您可以定义多个这样的模式:
example_default:
pattern: /example
defaults: { _controller: ExampleBundle:Example:index, _locale: fr }
example:
pattern: /{_locale}/example
defaults: { _controller: ExampleBundle:Example:index}
requirements:
_locale: fr|en
你应该能够通过注释实现同样的目标:
/**
* @Route("/example", defaults={"_locale"="fr"})
* @Route("/{_locale}/example", requirements={"_locale" = "fr|en"})
*/
希望有所帮助!
答案 2 :(得分:7)
这是我用于自动区域设置检测和重定向的方法,它运行良好,不需要冗长的路由注释:
<强>的routing.yml 强>
locale
路由处理网站的根目录,然后每个其他控制器操作都附加在语言环境中。
locale:
path: /
defaults: { _controller: AppCoreBundle:Core:locale }
main:
resource: "@AppCoreBundle/Controller"
prefix: /{_locale}
type: annotation
requirements:
_locale: en|fr
<强> CoreController.php 强>
这会检测用户的语言并重定向到您选择的路线。我使用home作为默认值,因为它是最常见的情况。
public function localeAction($route = 'home', $parameters = array())
{
$this->getRequest()->setLocale($this->getRequest()->getPreferredLanguage(array('en', 'fr')));
return $this->redirect($this->generateUrl($route, $parameters));
}
然后,路线注释可以简单地为:
/**
* @Route("/", name="home")
*/
public function indexAction(Request $request)
{
// Do stuff
}
<强>枝条强>
localeAction可用于允许用户更改语言环境而无需导航离开当前页面:
<a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': targetLocale })) }}">{{ targetLanguage }}</a>
清洁&amp;简单!
答案 3 :(得分:3)
由于$routePath == "/{_locale}".$path)
例如:$routePath = "/{_locale}/my/route/{foo}"
与$path = "/{_locale}/my/route/bar"
我必须使用UrlMatcher(链接到Symfony 2.7 api doc)来匹配实际路由和网址。
我更改 isLocaleSupported 以使用浏览器本地代码(例如:fr - &gt; fr_FR)。我使用浏览器区域设置作为键,将路径区域设置用作值。我有一个像array(['fr_FR'] => ['fr'], ['en_GB'] => 'en'...)
这样的数组(有关更多信息,请参阅下面的参数文件)
变化:
这是我的代码。适用于有或没有参数的任何路线。只有在路径中设置{_local}时才会添加区域设置。
路由文件(在我的情况下,是app / config中的文件)
app:
resource: "@AppBundle/Resources/config/routing.yml"
prefix: /{_locale}/
requirements:
_locale: '%app.locales%'
defaults: { _locale: %locale%}
app / config / parameters.yml文件中的参数
locale: fr
app.locales: fr|gb|it|es
locale_supported:
fr_FR: fr
en_GB: gb
it_IT: it
es_ES: es
<强> services.yml 强>
app.eventListeners.localeRewriteListener:
class: AppBundle\EventListener\LocaleRewriteListener
arguments: ["@router", "%kernel.default_locale%", "%locale_supported%"]
tags:
- { name: kernel.event_subscriber }
<强> LocaleRewriteListener.php 强>
<?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;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
class LocaleRewriteListener implements EventSubscriberInterface
{
/**
* @var Symfony\Component\Routing\RouterInterface
*/
private $router;
/**
* @var routeCollection \Symfony\Component\Routing\RouteCollection
*/
private $routeCollection;
/**
* @var urlMatcher \Symfony\Component\Routing\Matcher\UrlMatcher;
*/
private $urlMatcher;
/**
* @var string
*/
private $defaultLocale;
/**
* @var array
*/
private $supportedLocales;
/**
* @var string
*/
private $localeRouteParam;
public function __construct(RouterInterface $router, $defaultLocale = 'fr', array $supportedLocales, $localeRouteParam = '_locale')
{
$this->router = $router;
$this->routeCollection = $router->getRouteCollection();
$this->defaultLocale = $defaultLocale;
$this->supportedLocales = $supportedLocales;
$this->localeRouteParam = $localeRouteParam;
$context = new RequestContext("/");
$this->matcher = new UrlMatcher($this->routeCollection, $context);
}
public function isLocaleSupported($locale)
{
return array_key_exists($locale, $this->supportedLocales);
}
public function onKernelRequest(GetResponseEvent $event)
{
//GOAL:
// Redirect all incoming requests to their /locale/route equivalent when exists.
// Do nothing if it already has /locale/ in the route to prevent redirect loops
// Do nothing if the route requested has no locale param
$request = $event->getRequest();
$baseUrl = $request->getBaseUrl();
$path = $request->getPathInfo();
//Get the locale from the users browser.
$locale = $request->getPreferredLanguage();
if ($this->isLocaleSupported($locale)) {
$locale = $this->supportedLocales[$locale];
} else if ($locale == ""){
$locale = $request->getDefaultLocale();
}
$pathLocale = "/".$locale.$path;
//We have to catch the ResourceNotFoundException
try {
//Try to match the path with the local prefix
$this->matcher->match($pathLocale);
$event->setResponse(new RedirectResponse($baseUrl.$pathLocale));
} catch (\Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
} catch (\Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
}
}
public static function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
);
}
}
答案 4 :(得分:2)
有我的解决方案,它使这个过程更快!
控制器:
/**
* @Route("/change/locale/{current}/{locale}/", name="locale_change")
*/
public function setLocaleAction($current, $locale)
{
$this->get('request')->setLocale($locale);
$referer = str_replace($current,$locale,$this->getRequest()->headers->get('referer'));
return $this->redirect($referer);
}
嫩枝:
<li {% if app.request.locale == language.locale %} class="selected" {% endif %}>
<a href="{{ path('locale_change', { 'current' : app.request.locale, 'locale' : language.locale } ) }}"> {{ language.locale }}</a>
</li>
答案 5 :(得分:2)
Symfony3
app:
resource: "@AppBundle/Controller/"
type: annotation
prefix: /{_locale}
requirements:
_locale: en|bg| # put a pipe "|" last
答案 6 :(得分:1)
我有一个完整的解决方案,我在一些研究后发现。我的解决方案假设您希望每个路由都有一个区域设置,甚至登录。这被修改为支持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 Redirect All Routes To Current Locale Version
短版
为了使我的例子中的案例#2成为可能你需要使用httpKernal列表器
<强> 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文件,因此您只需在一个地方为所有路由定义这些要求。
希望这有助于某人:)
答案 7 :(得分:0)
我使用注释,我会做
/**
* @Route("/{_locale}/example", defaults={"_locale"=""})
* @Route("/example", defaults={"_locale"="en"}, , requirements = {"_locale" = "fr|en|uk"})
*/
但是对于yml方式,请尝试一些等效的...
答案 8 :(得分:0)
也许我以一种相当简单的方式解决了这个问题:
1
对评论家的判断感到好奇...... 最好的祝愿, 格雷格
答案 9 :(得分:0)
root:
pattern: /
defaults:
_controller: FrameworkBundle:Redirect:urlRedirect
path: /en
permanent: true
How to configure a redirect to another route without a custom controller
答案 10 :(得分:0)
我们创建了一个自定义的RoutingLoader,它向所有路由添加了本地化版本。您注入了一个附加语言环境['de', 'fr']
的数组,并且Loader为每个附加语言环境添加了一条路由。主要优点是,对于您的默认语言环境,路由保持不变,并且不需要重定向。另一个优点是,注入了附加路由,因此可以针对多个客户端/环境等对它们进行不同的配置。而且配置要少得多。
partial_data GET ANY ANY /partial/{code}
partial_data.de GET ANY ANY /de/partial/{code}
partial_data.fr GET ANY ANY /fr/partial/{code}
这是装载机:
<?php
namespace App\Routing;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class I18nRoutingLoader extends Loader
{
const NAME = 'i18n_annotation';
private $projectDir;
private $additionalLocales = [];
public function __construct(string $projectDir, array $additionalLocales)
{
$this->projectDir = $projectDir;
$this->additionalLocales = $additionalLocales;
}
public function load($resource, $type = null)
{
$collection = new RouteCollection();
$originalCollection = $this->getOriginalRouteCollection($resource);
$collection->addCollection($originalCollection);
foreach ($this->additionalLocales as $locale) {
$this->addI18nRouteCollection($collection, $originalCollection, $locale);
}
return $collection;
}
public function supports($resource, $type = null)
{
return self::NAME === $type;
}
private function getOriginalRouteCollection(string $resource): RouteCollection
{
$resource = realpath(sprintf('%s/src/Controller/%s', $this->projectDir, $resource));
$type = 'annotation';
return $this->import($resource, $type);
}
private function addI18nRouteCollection(RouteCollection $collection, RouteCollection $definedRoutes, string $locale): void
{
foreach ($definedRoutes as $name => $route) {
$collection->add(
$this->getI18nRouteName($name, $locale),
$this->getI18nRoute($route, $name, $locale)
);
}
}
private function getI18nRoute(Route $route, string $name, string $locale): Route
{
$i18nRoute = clone $route;
return $i18nRoute
->setDefault('_locale', $locale)
->setDefault('_canonical_route', $name)
->setPath(sprintf('/%s%s', $locale, $i18nRoute->getPath()));
}
private function getI18nRouteName(string $name, string $locale): string
{
return sprintf('%s.%s', $name, $locale);
}
}
服务定义(SF4)
App\Routing\I18nRoutingLoader:
arguments:
$additionalLocales: "%additional_locales%"
tags: ['routing.loader']
路由定义
frontend:
resource: ../../src/Controller/Frontend/
type: i18n_annotation #localized routes are added
api:
resource: ../../src/Controller/Api/
type: annotation #default loader, no routes are added
答案 11 :(得分:-3)
我认为您可以简单地添加这样的路线:
example:
pattern: /example
defaults: { _controller: ExampleBundle:Example:index }
这样,语言环境将是用户选择的最后一个语言环境,或者如果尚未设置用户语言环境,则为默认语言环境。如果要为/ example设置特定的语言环境,也可以在路由配置中将“_locale”参数添加到“defaults”:
example:
pattern: /example
defaults: { _controller: ExampleBundle:Example:index, _locale: fr }
我不知道是否有更好的方法来做到这一点。