运行时多语言切换需将语言标识存于session并在中间件中调用App::setLocale()覆盖默认值,不能仅改config/app.php的locale;文件名须小写,PHP文件须返回数组且无BOM;前端切换需通过POST接口更新session并刷新页面。

直接改 config/app.php 里的 locale 值不能实现运行时多语言切换——它只在应用启动时读取一次,后续请求不会自动更新。
如何让 Laravel 支持运行时语言切换
核心是把语言标识存在用户可控制的位置(如 session、cookie 或 URL 参数),并在每次请求开始前用它覆盖默认 App::setLocale()。Laravel 的本地化系统本身不拒绝动态设置,但需要你主动介入请求生命周期。
- 推荐将语言存于
session:稳定、无需暴露在 URL 中、支持 POST 请求 - 避免仅靠 URL 参数(如
?lang=zh)做唯一依据,否则 API 调用或重定向后容易丢失 - 务必在
app/Http/Middleware/Localization.php(需手动创建)中调用App::setLocale($locale),且该中间件必须放在StartSession之后 - 不要在控制器里临时改
App::setLocale()后就以为视图会自动刷新语言——它只影响后续的__()调用,且当前请求中已加载的翻译缓存不会重载
lang 文件结构与加载规则
Laravel 按 resources/lang/{locale}/{file}.php 查找翻译,比如 resources/lang/zh/auth.php 对应中文认证提示。注意几个关键点:
- 文件名必须小写,
Auth.php或AUTH.PHP都不会被加载 - 嵌套层级不影响加载,
resources/lang/en/admin/dashboard.php是合法路径,引用时用__('admin/dashboard.welcome') - 若使用
__()查找键'auth.failed',它会依次查找:resources/lang/{current}/auth.php→resources/lang/en/auth.php(fallback)→ 报错(如果fallback_locale也没定义该键) - PHP 文件必须返回
array,不能有 echo/print、不能含 BOM 头,否则整个语言包加载失败且无提示
前端切换语言并持久化到后端
前端点击切换语言,本质是向后端发起一次状态变更请求,而不是单纯改前端变量。常见错误是只改了 URL 参数或 localStorage,却没通知 Laravel 更新 session 中的语言标识。
- 提供一个 POST 接口,例如
POST /locale,接收locale=zh,然后执行:session(['locale' => $request->locale]);
- 确保该接口受
web中间件保护(以启用 session),且 CSRF token 正确传递 - 前端可配合
axios.post('/locale', {locale: 'ja'})+ 页面 reload,或用window.location.reload()确保新 locale 生效 - 不要依赖 JavaScript 动态替换页面文本——这绕过了 Laravel 的翻译机制,无法享受缓存、fallback、参数插值(如
__('welcome', ['name' => $user->name]))等特性
常见报错和静默失效场景
多语言出问题往往没有明显报错,而是文本始终显示英文或空字符串。排查优先看这几处:
-
config/app.php中fallback_locale设为'en',但resources/lang/en/下缺少对应文件(如缺validation.php),会导致__('validation.required')返回空字符串而非 key 本身 - 使用
trans_choice()时传入非整数(如字符串"1"),Laravel 不会报错但可能选错复数形式;务必确保第二个参数是(int) - Artisan 命令中语言默认是
en,即使 session 里有 locale —— 因为命令行无 session。需显式调用App::setLocale('zh') - Blade 中写
{{ __('messages.hello') }}没问题,但若写成{{ trans('messages.hello') }},而trans()是旧版辅助函数(Laravel 9+ 已弃用),可能在某些环境下未定义
真正麻烦的不是配置步骤,而是语言状态在 session、URL、cookie、中间件、缓存之间如何同步——稍有遗漏,就会出现「明明改了 locale,但按钮文字还是英文」这类问题。盯住 App::getLocale() 在请求不同阶段的返回值,比反复检查翻译文件更有效。










