Symfony 3.4如何实现默认语言URL不含语言参数且不修改path()调用?
我之前在Symfony 3.4项目里正好实现过一模一样的多语言URL需求——默认语言(en)不带前缀,其他语言(de/fr等)自动添加语言代码,而且Twig里的path()调用完全不用改,太省心了!下面一步步给你讲怎么实现:
1. 先配置基础本地化参数
打开app/config/config.yml,设置默认语言、允许的语言列表,以及翻译器的基础配置:
framework: default_locale: en allowed_locales: ['en', 'de', 'fr'] translator: fallbacks: ['en'] paths: - '%kernel.root_dir%/Resources/translations'
2. 配置带条件前缀的路由(核心部分)
这一步是实现URL格式的关键,我们要给所有路由设置一个可选的语言前缀——只有非默认语言才会显示前缀。修改app/config/routing.yml,把所有业务路由包裹在一个父路由下:
# app/config/routing.yml app: resource: '@AppBundle/Controller/' type: annotation prefix: /{_locale} requirements: _locale: ^de|fr$ # 这里只列出非默认的语言代码 defaults: _locale: en # 默认值,当URL里没有前缀时自动使用en
这样配置后:
- 访问
/path/page/1时,_locale会自动设为en - 访问
/de/path/page/1时,_locale会被设为de,完全符合你的URL格式要求
3. 配置LocaleListener自动处理语言切换
为了让系统能自动识别用户的语言偏好,我们需要写一个请求监听类,负责从Session或请求参数里获取并设置当前语言:
// src/AppBundle/EventListener/LocaleListener.php namespace AppBundle\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class LocaleListener implements EventSubscriberInterface { private $defaultLocale; public function __construct($defaultLocale = 'en') { $this->defaultLocale = $defaultLocale; } public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); if (!$request->hasPreviousSession()) { return; } // 如果请求里带了_locale参数,更新Session里的语言设置 if ($locale = $request->query->get('_locale')) { $request->getSession()->set('_locale', $locale); } // 从Session取语言,没有的话用默认值 $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale)); } public static function getSubscribedEvents() { return [ // 要在路由解析之前执行,确保路由能拿到正确的_locale KernelEvents::REQUEST => [['onKernelRequest', 17]], ]; } }
然后在app/config/services.yml里注册这个监听:
services: app.locale_listener: class: AppBundle\EventListener\LocaleListener arguments: ['%kernel.default_locale%'] tags: - { name: kernel.event_subscriber }
4. Twig里的URL生成完全不用改!
这一点最爽了!因为我们在路由里已经给_locale设置了默认值en,所以你在Twig里原来怎么写path()调用,现在还怎么写:
{# 原来的写法完全不变 #} <a href="{{ path('article_show', {id: article.id}) }}">查看文章</a>
Symfony会自动根据当前的_locale生成对应格式的URL:
- 当前语言是en时,生成
/article/1 - 当前语言是de时,生成
/de/article/1
如果你想强制生成某个语言的URL,只需要手动加_locale参数就行:
{# 强制生成法语版URL #} <a href="{{ path('article_show', {id: article.id, _locale: 'fr'}) }}">Voir l'article</a>
5. 语言切换按钮示例
如果需要做语言切换功能,直接用当前路由的参数合并_locale即可:
<div class="language-switcher"> <a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({_locale: 'en'})) }}">English</a> <a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({_locale: 'de'})) }}">Deutsch</a> <a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({_locale: 'fr'})) }}">Français</a> </div>
点击后会跳转到当前页面的对应语言版本,URL格式完全符合要求。
注意事项
- 确保所有业务路由都被包含在上述的
app父路由下,如果有独立的路由文件(比如后台路由),也要用同样的方式配置前缀 - 配置完成后记得清除缓存:
php bin/console cache:clear - 如果你用注解路由,不需要在每个控制器方法里单独设置
_locale参数,父路由的配置已经处理好了
内容的提问来源于stack exchange,提问作者sowiq
相关产品推荐
相关产品推荐

