在 Laravel 中,用中间件设置多语言 locale 是最推荐方式,需按路由参数→session→cookie→Accept-Language 顺序读取并立即调用 App::setLocale() 生效,且须校验白名单、确保中间件注册位置正确。

在 Laravel 中,用中间件设置多语言 locale 是最推荐、最稳定的方式。关键不是“存语言”,而是**在视图渲染前,让 App::setLocale() 生效**——只有这时,__('welcome')、@lang、验证消息、Carbon 格式等才会真正按目标语言加载。
中间件里怎么读取 locale
优先级建议:路由参数 → session → cookie → Accept-Language(仅兜底)。顺序很重要,因为越早拿到越可靠:
-
路由参数:比如访问
/zh/home,中间件中用$request->segment(1)直接取zh。它在路由解析后就确定,不依赖 session 启动,最及时 -
session:如
session('locale'),需确保中间件排在StartSession::class之后,否则读不到 -
cookie:用
$request->cookie('locale'),比 session 更轻量,适合游客场景 -
Accept-Language:用
substr($request->header('Accept-Language'), 0, 2)截取主语言码(如zh),别直接信完整 header 值
中间件里怎么设置 locale
拿到值后必须立刻调用 App::setLocale($locale),且不能只改配置或写 session:
- ✅ 正确:
App::setLocale('zh_CN')—— 它会同步更新 Translator 和 Carbon 的运行时状态 - ❌ 错误:
config(['app.locale' => 'zh_CN'])—— 这只改配置数组,不影响已初始化的翻译器 - ⚠️ 注意:如果用了翻译缓存(如
php artisan lang:publish),切换 locale 后要清缓存,否则新语言文件不加载
中间件注册和顺序要点
这个中间件必须放在正确位置,否则会失效:
- 注册到
$middlewareGroups['web'],不要放全局$middleware - 顺序必须在
\Illuminate\Session\Middleware\StartSession::class之后 - 最好也在
\Illuminate\Routing\Middleware\SubstituteBindings::class(路由绑定)之前,避免控制器已执行部分逻辑 - 如果是路由前缀方式(
Route::prefix('{locale}')),中间件应直接挂到该路由组上:->middleware(SetLocale::class)
白名单校验和安全处理
所有外部输入都必须校验,防止非法 locale 导致错误或安全风险:
- 在
config/app.php中定义白名单:'locales' => ['en', 'zh_CN', 'ja'] - 中间件中检查:
if (!in_array($locale, config('app.locales'))) { abort(404); } - 不建议把用户传入的 locale 直接拼进路径或文件名,避免目录遍历
- 如果用 session 或 cookie 存储,切换接口里校验通过后再写入,不要在中间件里反向写 session


















