Laravel原生即可搭建符合出海要求的多语言站点,但必须严格遵循BCP 47目录结构、路由加载顺序与locale设置时机,否则__('welcome')将始终返回英文;正确路径为resources/lang/zh-Hans等,错误写法如zh_CN会导致加载失败。

直接说结论:Laravel 原生就能搭出符合出海要求的多语言站点,不需要第三方包,但必须严格遵循目录结构、路由加载顺序和 locale 设置时机——错一步,__('welcome') 就永远返回英文字符串。
resources/lang 目录结构必须按 BCP 47 规范组织
出海项目常踩坑点:用 zh-CN 或 zh_TW 当文件夹名,结果 App::setLocale('zh-CN') 加载失败。Laravel 只认标准语言标签(BCP 47),且不自动转换下划线为连字符。
- ✅ 正确写法:
resources/lang/zh-Hans(简体中文)、resources/lang/zh-Hant(繁体中文)、resources/lang/en-US、resources/lang/ja - ❌ 错误写法:
resources/lang/zh_CN、resources/lang/zh_tw、resources/lang/Chinese - 语言文件必须是 PHP 数组或 JSON;PHP 文件推荐用
return ['welcome' => '欢迎'];,JSON 文件注意 UTF-8 无 BOM - 如果用区域变体(如
en-GB),fallback_locale仍应设为en,否则__('missing_key')不会降级到通用英文
Route::prefix('{locale}') 必须在 middleware 之前生效
很多出海项目发现切换语言后页面文字没变,根本原因是路由解析早于 App::setLocale() 执行——翻译函数在视图渲染时读的是旧 locale。
- 在
routes/web.php最顶部加:Route::prefix('{locale}')->middleware('setlocale')->group(function () { ... }); -
setlocale中间件里必须做白名单校验:if (! in_array($request->locale, config('app.supported_locales', ['en', 'zh-Hans', 'ja']))) { abort(404); } - 别把 API 路由也套进去;
api.php应独立处理语言,比如靠 headerAccept-Language或 query 参数 - 生成带 locale 的 URL 必须用
route('home', ['locale' => 'ja']),硬拼/ja/home会导致命名路由失效
__(), @lang 和验证错误消息的参数传递规则不同
出海站点大量依赖表单验证和动态文案,但 @lang 不支持插值,__('key', $params) 才支持——混用就会出现 “:attribute” 字面量没被替换。
- 语言文件中写:
'password_min' => 'The :attribute must be at least :min characters.' - Blade 里必须用:
{{ __('password_min', ['attribute' => __('attributes.password'), 'min' => 8]) }},不能用@lang('password_min') - 验证规则自定义提示(如
Rule::unique('users')->message(__('validation.unique')))要确保resources/lang/zh-Hans/validation.php存在对应 key - 避免在语言文件里写逻辑,比如
'greeting' => now()->format('Y') > 2025 ? 'Welcome 2026!' : 'Welcome!'—— 缓存后永远不更新
生产环境必须清除缓存链,否则改了语言文件也不生效
出海项目上线后常遇到“明明改了 zh-Hans/messages.php,用户看到的还是旧翻译”,问题几乎 100% 出在缓存没清干净。
-
APP_DEBUG=false时,Laravel 会缓存语言文件、配置、视图三者;只运行php artisan view:clear不够 - 完整清理命令:
php artisan config:clear && php artisan view:clear && php artisan lang:publish --force(后者仅当用了laravel-lang包) - 如果你手动新增了
resources/lang/ko,lang:publish不会自动复制内容,得自己从 en 复制再翻译 - Docker 部署时注意 volume 挂载是否覆盖了
storage/framework/cache,否则缓存残留更难排查
最易被忽略的点:浏览器请求头里的 Accept-Language: zh-CN,zh;q=0.9 不会自动触发 Laravel 切换 locale,它只影响 Request::getPreferredLanguage() 返回值——你要自己读这个值、校验白名单、再写进 session 或 cookie,否则用户语言偏好永远无法落地。


















