直接改config/app.php的locale值不能实现运行时切换——它仅启动时读取一次;必须在startsession之后的中间件中调用app::setlocale(),并校验白名单、清理缓存,语言文件须严格按resources/lang/{locale}/小写路径存放且返回无bom数组。

直接改 config/app.php 里的 locale 值不能实现运行时语言切换——它只在应用启动时读取一次,后续所有请求都沿用这个静态值。
Lang 文件必须放在 resources/lang/{locale}/ 目录下,且文件名大小写敏感
比如设了 'locale' => 'zh_CN',Laravel 就只会去找 resources/lang/zh_CN/messages.php;写成 zh-cn、zh_cn 或 ZH_CN 都加载失败。文件本身必须是 PHP 脚本,返回纯数组,不能有 BOM、不能含 echo、不能是 JSON 文件(除非你额外配了 JSON 加载器)。
-
resources/lang/en/messages.php和resources/lang/zh_CN/messages.php是最简可行结构 - 嵌套路径如
resources/lang/zh_CN/auth/login.php也合法,引用时用__('auth/login.failed') - 目录名和文件名全小写最稳妥,
Auth.php或MESSAGES.PHP都不会被识别
App::setLocale() 必须在中间件里调用,且要在 StartSession 之后
翻译器(translator)是单例,在容器初始化时就绑定了当前 locale。如果在控制器或 Blade 中调用 App::setLocale('ja'),视图里已执行的 __('welcome') 仍用旧 locale,验证错误也不会变。
- 中间件应注册在
StartSession::class之后、ShareErrorsFromSession::class之前 - 从
$request->input('lang')、session('locale')或$request->route('locale')取值,别硬编码 - 务必校验值是否在白名单内:
in_array($locale, config('app.available_locales', ['en', 'zh_CN']))
__(), trans() 和带参数的占位符只认 :key 格式
写成 {name}、$name 或 {{ name }} 都不会被替换。语言文件里必须用冒号前缀,传参键名也要完全一致。
- 正确:
'welcome' => '欢迎 :name'+__('welcome', ['name' => '张三']) - 错误:
'welcome' => '欢迎 {name}'→ 输出原样欢迎 {name} - 参数值本身若含格式化(如日期),应在传入前处理好:
__('post.published', ['date' => now()->translatedFormat('Y年m月d日')])
缓存不清理,改了 lang 文件也没用
Laravel 会缓存编译后的视图和语言文件,尤其在 APP_ENV=production 下。改完 messages.php 后,不跑命令就看不到效果。
- 必清缓存:
php artisan config:clear+php artisan view:clear - 开发阶段可临时设
APP_ENV=local关闭部分缓存,但别在生产环境依赖它 - 第三方包的语言文件需先执行
php artisan vendor:publish --tag=laravel-lang才能覆盖
最容易被忽略的是 translator 单例的缓存绑定时机——它发生在中间件链开始前,所以 locale 设置晚于这个点,就等于没设。











