symfony 6.2 国际化需显式启用translator、严格配置paths和fallbacks、规范命名翻译文件(如messages.en.xlf)、手动清理缓存,否则trans()静默返回原键名。

Symfony 6.2 的国际化不是“开了就能用”的功能,它默认只加载 messages 域、只认 translations/ 目录下的文件,且不自动提取或热更新翻译——你得手动配路径、选 loader、设 fallback,漏一步就返回原始键名或抛 MissingTranslationException。
translator 配置必须显式启用并指定 paths
Symfony 6.2 默认禁用 translator 组件(即使装了 symfony/translation),光靠 composer require symfony/translation 不会自动激活。常见错误是调用 $translator->trans('hello') 报 ServiceNotFoundException 或直接返回原字符串。
- 确认
config/packages/translation.yaml存在且内容非空(不能只注释掉) -
paths必须显式列出目录,例如:['%kernel.project_dir%/translations'];若用 bundle 内的src/MyBundle/Resources/translations/,需额外加进该数组 - 删除
framework.translator.enabled: false这类显式关闭配置(旧项目迁移时容易残留) - 运行
php bin/console debug:config framework | grep translator确认输出中包含enabled: true和实际生效的paths
翻译文件命名和格式必须严格匹配 domain.locale.loader
文件名写错一个字符,Symfony 就静默跳过——不报错、不警告、不加载,trans() 直接回退到源字符串。最常踩的坑是 locale 格式和 loader 后缀不一致。
- 正确命名示例:
messages.en.xlf、admin.fr.yaml、validation.zh_CN.json - locale 必须是 IETF 语言标签(如
zh_CN,不是zh-CN或zhcn),否则Translator找不到对应 catalogue - loader 由后缀决定:
.xlf→XliffFileLoader,.yaml→YamlFileLoader;若用.yml,需在 config 中显式注册ymlloader(默认只注册yaml) - domain 默认是
messages;若用自定义 domain(如admin),trans()必须传第二个参数:$translator->trans('key', [], 'admin')
fallbacks 和 default_locale 不是同一回事,别混用
很多人以为设了 default_locale: 'zh' 就能自动 fallback 到中文,结果英文没翻完的页面全显示英文键名。其实 fallback 是兜底链,和当前请求 locale 无关。
-
default_locale只影响未显式指定 locale 时的初始值(比如 Twig 中{{ 'hello'|trans }}没带 locale 参数时用哪个) -
fallbacks是 fallback 链:例如设为['zh_CN', 'en'],当查zh_TW里没有的 key 时,会依次查zh_CN→en→ 最终空 catalogue - fallbacks 必须是数组格式(哪怕只有一个),写成
fallbacks: 'en'会解析失败,静默降级为无 fallback - 开发期建议设
fallbacks: ['en'],避免漏翻导致页面崩坏;生产环境可按需精简
缓存失效和开发调试必须手动清理
Symfony 6.2 默认开启翻译缓存(%kernel.cache_dir%/translations/),改了 .xlf 文件不会自动重载——你看到的还是旧翻译,甚至改对了都以为配置错了。
- 开发时务必加
--no-cache启动服务器:php -S localhost:8000 -t public/或用symfony server:start --no-cache - 每次修改翻译文件后,手动删缓存:
rm -rf var/cache/dev/translations/(dev 环境)或php bin/console cache:clear - 若用 OPcache,还需执行
opcache_reset()或重启 PHP-FPM,否则 loader 读的仍是内存里旧的 parsed array - 验证是否生效:在控制器里 dump
$translator->getCatalogue('zh_CN')->all('messages'),看输出数组里有没有你刚加的 key
真正麻烦的从来不是加几行配置,而是当 trans() 返回空字符串或原 key 时,你得一层层确认:locale 是否被中间件覆盖、domain 是否拼错、loader 是否支持该后缀、缓存是否 stale、fallback 链是否断裂——这些环节任何一个断开,都不会报错,只会沉默地交给你一个“没翻译”的假象。











