laravel多语站点关键在三点:语言目录结构规范、setlocale()须早期生效、carbon等组件需手动同步locale;否则日期、验证、路由仍为英文。

直接上结论:Laravel 多语站点不是靠装个包就自动跑起来的,关键在三点——语言文件结构必须规范、app()->setLocale() 必须在请求生命周期早期生效、所有依赖 locale 的组件(Carbon、Validator、URL 生成)得同步对齐,否则会出现中文页面里日期是英文、验证错误还是英文、路由生成带错 locale 前缀等问题。
resources/lang 目录结构怎么组织才不踩坑
必须严格按 resources/lang/{locale} 形式建目录,比如 resources/lang/en、resources/lang/zh_CN、resources/lang/zh-Hans。BCP 47 格式(如 zh-Hans)可被 Laravel 原生识别,但别混用下划线和短横线——zh_CN 和 zh-CN 是两个不同 locale,不能共用翻译。
- 文件支持 PHP 数组(如
messages.php)和 JSON(如auth.json),但不要混用同一语言下的两种格式;JSON 更适合前后端共享,PHP 数组支持动态逻辑(如条件返回) - 模块化拆分推荐用文件名区分,例如
resources/lang/en/auth.php、resources/lang/en/validation.php,调用时用__('auth.login')或__('validation.required') - 别把语言文件放在
lang/根目录或app/Lang下——除非你手动注册了命名空间,否则__()根本找不到
为什么 app()->setLocale() 放中间件里还失效
常见现象:中间件里写了 app()->setLocale(session('locale')),但 Carbon::now()->diffForHumans() 还是英文,或者 route('home') 生成的 URL 没带当前 locale 前缀。根本原因是 locale 设置太晚,或没覆盖全链路。
-
app()->setLocale()只影响 Translator,默认不触碰 Carbon、Validator、URL 生成器 - 必须显式同步:
Carbon::setLocale(app()->getLocale())(建议放AppServiceProvider::boot()) - 验证器需重设属性名:
$validator->setAttributeNames(trans('validation.attributes')),否则__('attributes.name')不生效 - 如果用了路由前缀(如
/en/home),route('home')默认不带 locale 参数,得写成route('home', ['locale' => app()->getLocale()]),或改用LaravelLocalization::getLocalizedURL()
session 切语言 vs 路由前缀:后台该选哪个
后台管理界面强烈建议用 session(或 cookie)存语言偏好,而不是路由前缀。原因很实际:权限控制、菜单 URL 生成、API 调用、甚至前端 JS 的 axios.get('/api/user') 都不该被 locale 干扰。
- 路由前缀(
Route::prefix('{locale}'))会让所有后台路由变成/admin/zh/dashboard,但route('admin.dashboard')会报错,除非每个地方都传['locale' => 'zh'],极易漏 - session 方案只需一个简单切换接口:
GET /admin/locale/{locale},里面做session(['locale' => $locale])+redirect()->back() - 确保该路由在
web中间件组内,且中间件执行顺序在StartSession之后,否则 session 写不进去 - 别忘了在
config/app.php里设好fallback_locale => 'en',避免某条翻译缺失时整个页面崩出 key 名
最易被忽略的一点:翻译缓存。开发时改了 resources/lang/zh/messages.php,但页面没更新?运行 php artisan view:clear 和 php artisan config:clear 不够,还得清翻译缓存:php artisan lang:clear(Laravel 10+ 自带)或删 storage/framework/cache/data/ 下相关文件。否则你改半天,浏览器看到的还是旧翻译。











