symfony 4 中可通过子域名区分语言,核心是将子域名(如 zh.example.com)映射为 locale 并全局生效:1. 用 kernel.request 监听器解析 host 并设 request locale;2. 翻译组件依赖动态 locale,禁用 %locale% 静态参数;3. 路由需配置 host 模板与 _locale 参数;4. 注意表单、验证及 vary: host 缓存控制。

子域名区分语言在 Symfony 4 中可行,但不是 Symfony 翻译组件的原生机制——它本身只管“locale”值从哪来、怎么加载翻译文件;子域名只是你传递 locale 的一种方式。关键在于:把子域名(如 zh.example.com、en.example.com)可靠地映射为对应的 locale(zh、en),再让整个请求上下文(包括路由生成、翻译器、表单等)都基于这个 locale 工作。
1. 从子域名提取 locale 并设为请求 locale
最直接的方式是在请求进入时解析 host,提取语言标识,并设置到 Request 对象的 locale 属性上。推荐使用事件监听器(kernel.request):
- 创建监听器类(例如 src/EventListener/LocaleFromSubdomainListener.php)
- 在 onKernelRequest 方法中获取
$request->getHost() - 用正则匹配子域名部分(如
/^([a-z]{2})\.example\.com$/i),提取出zh或en - 调用
$request->setLocale($locale),并同步设置$request->setDefaultLocale($locale) - 别忘了在 config/services.yaml 中注册该监听器并标记为
kernel.event_listener
2. 配置翻译组件支持动态 locale
确保翻译器能根据当前请求的 locale 加载对应文件。默认配置已足够,只需确认:
-
config/packages/translation.yaml 中启用了
translator,且fallbacks合理(例如['en']) - 翻译文件放在 translations/ 目录下,命名格式为
messages.zh.xlf、messages.en.xlf - 不依赖
%locale%参数做静态配置(如default_locale: '%locale%'),因为 locale 是动态的;应改用default_locale: 'en'作为兜底,实际以请求 locale 为准
3. 路由层适配子域名主机
要让 url() 或 path() 生成带正确子域名的链接,需在路由定义中显式支持 host:
- 在控制器方法或 YAML 路由中使用
host: "{_locale}.example.com" - 添加
requirements: {'_locale': 'en|zh|fr'}限制合法子域名 - 确保生成 URL 时传入
_locale参数,例如:$this->generateUrl('homepage', ['_locale' => 'zh'])→ 生成https://zh.example.com/ - 若需自动继承当前请求的 locale,可在 Twig 模板中用
app.request.locale透传,避免硬编码
4. 表单、验证与缓存注意事项
子域名切换 locale 后,部分组件需额外处理:
- 表单错误消息、日期/数字格式等会自动跟随
app.request.locale,无需干预 - 验证约束(如
@Assert\NotBlank的 message)若含翻译占位符,需确保翻译域(domain)和 locale 正确加载 - 注意 HTTP 缓存:不同子域名的响应不应被 CDN 或反向代理误认为同一资源,建议在响应头中加入
Vary: Host











