symfony多语言路由通过可选\_locale参数实现:用/{\_locale}/{slug}和/{\_locale}路径,配合defaults与requirements(如"en|fr|es|de"),使/en/foo、/foo(默认en)、/均匹配同一路由;需注意路由顺序,避免/{slug}干扰,并用path()传\_locale生成对应url。

要让 Symfony 路由支持多语言(比如 /、/fr、/foo、/fr/foo),关键不是给每个语言写一堆重复路由,而是用可选的 _locale 参数 + 合理的默认值与约束,让同一个路由规则同时匹配带语言和不带语言的 URL。
用注解定义可选语言路由
核心思路是:把 _locale 设为路径第一段的可选参数,允许为空,并限制其取值范围。不能只靠 defaults={"_locale": ""},还要配合正则要求和路径结构设计。
- 首页路由应同时匹配
/和/fr,所以路径写成/{_locale},但_locale必须可省略 —— 这需要把它放在单独一条路由里,且不加requirements(否则空字符串不匹配) - 内容页如
/foo和/fr/foo,需两条路径共用一个路由名:/{_locale}/{slug}和/{slug},但 Symfony 不允许两个不同路径共享 name,所以更稳妥的做法是用/{_locale}/{slug}并允许_locale为空,再通过 requirements 控制它“要么是 fr|es,要么为空” - 实际可行写法(推荐):
/**
* @Route("/{_locale}/{slug}", name="details",
* defaults={"_locale": "en"},
* requirements={"_locale": "en|fr|es|de"})
*/
public function detailsAction(string $slug, string $_locale = 'en')
{ ... }
这样 /foo 会自动被识别为 _locale=en,/fr/foo 明确走法语。首页同理:
/**
* @Route("/{_locale}", name="home",
* defaults={"_locale": "en"},
* requirements={"_locale": "en|fr|es|de"})
*/
public function indexAction(string $_locale = 'en')
{ ... }
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
注意:/ 能命中是因为 Symfony 在匹配时会尝试把空路径当作 _locale=en(由 defaults 触发),前提是该路由没有其他更具体的冲突规则。
确保路由顺序正确
Symfony 按定义顺序匹配路由,所以更通用的路由(如带 _locale 的)必须放在更具体的路由之后,否则 /fr 可能被 /{slug} 错误捕获为 slug=fr。
- 不要单独定义
/{slug}路由,它会干扰本地化逻辑 - 如果必须保留无语言版 URL,可用
condition做运行时判断(高级用法) - 执行
php bin/console debug:router查看实际注册顺序和匹配优先级
模板中生成本地化链接
用 url() 或 path() 时传入 _locale 参数,Symfony 会自动选择对应路由:
-
{{ path('details', {'slug': 'foo'}) }}→/foo(默认 en) -
{{ path('details', {'slug': 'foo', '_locale': 'fr'}) }}→/fr/foo - 只要路由定义中声明了
_locale参数并有对应 requirements,生成器就能智能选路
语言切换与请求处理
用户首次访问 / 时,_locale 是默认值(如 en)。若想根据浏览器语言或会话自动切换,需在控制器或事件监听器中读取 $request->getPreferredLanguage() 或 session 值,再重定向到带 _locale 的 URL —— 路由本身不负责检测语言,只负责解析和生成。
不复杂但容易忽略。










