laravel 7 多语言未生效的根本原因是环境变量、文件路径或中间件执行时机出错:需在.env中设app_locale=zh_cn和app_fallback_locale=en并运行php artisan config:clear;resources/lang/zh_cn/messages.php路径及键名必须严格匹配;且必须在web中间件中于startsession之后调用app()->setlocale()。

__('welcome') 返回键名本身,而不是“欢迎”或“Welcome”,说明本地化根本没生效。Laravel 7 的多语言不是配了文件就自动跑起来的,关键在三处:环境变量、文件路径、中间件执行时机。
APP_LOCALE 和 APP_FALLBACK_LOCALE 必须写进 .env
Laravel 7 不读 config/app.php 里的 'locale' 配置来决定运行时语言 —— 它只认 .env 中的 APP_LOCALE 和 APP_FALLBACK_LOCALE,且必须手动清缓存才生效。
-
APP_LOCALE=zh_CN(Laravel 7 严格按 IETF 标签匹配,zh或zh-CN会被忽略) -
APP_FALLBACK_LOCALE=en(缺这个,缺失翻译时返回空字符串,不是英文) - 改完必须立刻执行:
php artisan config:clear;否则所有配置都从缓存读,改了等于没改
resources/lang 下的目录和文件名不能错一个字符
Laravel 7 按 resources/lang/{locale}/{file}.php 硬路径查找,不报错、不提示,错就静默失败。
- 目录名必须小写且下划线分隔:
resources/lang/zh_CN/✅,resources/lang/zh-cn/❌,resources/lang/ZH_CN/❌ - 文件名任意但要一致:比如
messages.php,内容必须是return ['welcome' => '欢迎']; - 若用嵌套键,如
__('auth.failed'),对应文件必须是resources/lang/zh_CN/auth.php,且键为'failed' => '登录失败' - JSON 格式也支持:
resources/lang/zh_CN/messages.json,但 PHP 数组更稳妥(避免 JSON 解析失败)
切换语言必须靠中间件,且顺序不能错
控制器里调 App::setLocale('zh_CN') 是无效的 —— 视图已编译、验证器已初始化、邮件模板已生成。真正起作用的,是请求一进来就设好 locale。
- 新建中间件:
php artisan make:middleware SetUserLocale - 中间件内容:
public function handle($request, Closure $next) { $locale = $request->session()->get('locale') ?? config('app.fallback_locale'); app()->setLocale($locale); return $next($request); } - 注册位置必须在
app/Http/Kernel.php的$middlewareGroups['web']中,且排在StartSession::class之后、其他业务中间件之前 - 切语言的路由示例:
Route::get('/lang/{locale}', function ($locale) { if (in_array($locale, ['en', 'zh_CN'])) { session(['locale' => $locale]); } return redirect()->back(); })->where('locale', 'en|zh_CN');
Carbon 和验证错误消息不会自动响应 locale 切换
这是 Laravel 7 最容易被忽略的坑:即使 __('validation.required') 显示中文了,$post->created_at->diffForHumans() 还是英文,Validator 错误消息也可能回退到英文。
- Carbon 时间需手动绑定:
// 在 AppServiceProvider::boot() use Carbon\Carbon; Carbon::setLocale(app()->getLocale());
- 验证器默认不读当前 locale,得显式传:
$validator = Validator::make($data, $rules, trans('validation'));或重写Illuminate\Validation\Validator的getMessageBag() - 队列任务、Artisan 命令中没有 session,
app()->getLocale()永远等于config('app.locale'),需通过参数或 job 属性传递 locale
resources/lang/zh_CN/ 少了个下划线、config:clear 忘了跑、或者中间件插在了 StartSession 前面 —— 这些地方一错,__('xxx') 就永远只返回原始键名。











