route() 生成的 URL 不带 /zh/ 或 /en/ 是因路由未声明 {locale} 参数,必须在定义中显式包含并调用时传参,如 route('home', ['locale' => 'zh']),否则不会自动添加语言前缀。

route() 生成的 URL 永远不带 /zh/ 或 /en/?不是 Laravel bug,是你没把 locale 当作路由必需参数声明。
为什么 route() 不自动加语言前缀
Laravel 的 route() 函数只看命名路由定义和传入参数,它不读 Session、不猜浏览器语言、也不继承中间件里设置的 app()->getLocale()。你写 route('home'),它就真按路由表里注册的路径拼——如果路由没声明 {locale} 段,结果就是 /,不是 /zh/。
- 必须在路由定义中显式包含
{locale}参数,例如Route::get('/{locale}/', ...)->name('home') - 调用时必须手动传参:
route('home', ['locale' => 'zh']),不能省略 - 别指望
app()->getLocale()会自动塞进route()——它只影响__('key')翻译,不影响 URL 生成 - 若用了
fallback_locale,注意app()->getLocale()可能已是回退值(如用户没选语言,返回了en),但你实际想生成的是用户上次选择的zh,得自己从 Session 或 Cookie 拿
如何避免 {locale} 被泛匹配路由吃掉
最常见的 404:访问 /zh/about 直接进 Route::fallback() 或 Vue 的 catch-all 路由,根本没走到你的多语言组。Laravel 匹配是顺序敏感的,{locale} 必须在所有泛匹配之前被识别。
- 把多语言路由组放在
routes/web.php最顶部,确保最先加载 - 绝对不要在它前面写
Route::any('{any}', ...)->where('any', '.*')这类通配路由 - 如果用了
Route::fallback(),务必把它移到整个文件末尾 -
->where('locale', 'en|zh|ja|ko')比'[a-z]{2}'更安全——非法值如/xx/直接 404,不会误入后续逻辑
中间件里设语言 ≠ 路由能感知 locale
你在中间件里写了 app()->setLocale($request->segment(1)),这能让 __('welcome') 正确翻译,但对 route('home') 完全无效。路由参数和语言上下文是两套独立机制。
- 中间件只负责设置当前请求的翻译环境,不修改路由参数绑定
- 要让
route()输出带前缀的 URL,唯一可靠方式是:路由定义含{locale}+ 调用时显式传参 - 如果你不想每个
route()都手写['locale' => ...],得封装一个辅助函数,比如local_route('home'),内部自动取当前 locale 并透传 - 别在控制器里用
URL::setRoot()或改APP_URL来“模拟”多语言——生成的链接仍缺前缀,SEO 和分享都会出问题
用 laravel-localization 包时的典型陷阱
这个包确实省事,但默认配置下容易踩两个坑:一是路由缓存后 LaravelLocalization::setLocale() 返回空字符串,二是 localizationRedirect 中间件在非本地化路由上抛错。
- 运行
php artisan route:clear后再试,别信缓存里的旧路由 - 确保所有需要多语言的路由都包裹在
Route::group(['prefix' => LaravelLocalization::setLocale(), ...])内,不要漏掉 API 或后台路由 - 检查
config/laravellocalization.php的supportedLocales是否包含你实际用的语言代码(如'zh'而不是'zh-CN') - 包的
localize中间件会尝试从 URL、Cookie、Session、浏览器头逐级 fallback,但如果你删了 Cookie 又没设 Session,它可能 fallback 到config('app.fallback_locale'),导致route()生成的链接语言和页面显示不一致
最易被忽略的一点:语言前缀必须和 config('app.locale') 值保持一致,否则 __('key') 找不到对应语言包——不是报错,而是静默回退到英文或空字符串。别只盯着 URL 和路由,resources/lang/ 下目录名、配置里的 default_locale、路由参数值、以及 app()->getLocale() 的实时返回值,四者必须对齐。



















