Laravel 9 语言文件目录迁移后失效的常见原因与解决方案

升级 laravel 8 到 9 后,若将 `resources/lang` 移至项目根目录 `lang/` 但翻译未生效,通常是因为旧目录未彻底删除,导致 laravel 优先加载残留的 `resources/lang`,从而忽略新路径。

Laravel 9 确实将语言文件默认路径从 resources/lang 迁移至项目根目录下的 lang/(即 base_path('lang')),这是框架内部语言加载器(TranslationLoader)的硬编码查找逻辑变更所致。然而,该迁移并非强制覆盖式切换,而是采用“多路径回退查找”机制:Laravel 会按顺序检查以下路径,并使用第一个存在且非空的语言目录:

  1. resources

    /lang(向后兼容保留)
  2. lang(Laravel 9 新默认路径)

这意味着:只要 resources/lang 目录仍存在于项目中(即使为空或仅含 .gitkeep),Laravel 就会停止继续查找,直接使用该路径——而你的旧目录很可能已无有效语言文件,导致 Lang::get() 返回原始键名(如 "messages.welcome"),而非翻译值。

✅ 正确迁移步骤如下:

  1. 彻底删除旧目录

    rm -rf resources/lang
    ⚠️ 注意:不要仅重命名或移动,必须确保该路径完全不存在。可通过 ls resources/ 验证。
  2. 确保新目录结构正确

    lang/
    └── pt-BR/
        └── messages.php  # 返回 ['welcome' => 'Welcome to the app!']
  3. 清空配置与语言缓存(关键!)

    php artisan config:clear
    php artisan lang:clear  # Laravel 9.19+ 支持;旧版可手动删除 storage/framework/cache/data/*lang*
    php artisan view:clear
  4. 验证配置无误

    // config/app.php
    'locale' => 'pt-BR',
  5. 测试调用(推荐使用辅助函数提升可读性)

    // Controller 或任意位置
    return response()->json([
        'message' => __('messages.welcome'), // 推荐:比 Lang::get() 更简洁
        // 或
        // 'message' => \Lang::get('messages.welcome')
    ]);

? 补充说明:

  • 新建 Laravel 9 项目默认不包含 resources/lang,因此天然使用 lang/,这也是为何“全新项目能正常工作”的原因;
  • composer.json 依赖一致 ≠ 配置状态一致,迁移需关注文件系统状态缓存状态
  • 若因历史原因需保留 resources/lang(如多环境差异化部署),可通过自定义 TranslationServiceProvider 覆盖加载路径,但违背升级初衷,不建议。

完成上述操作后,__('messages.welcome') 将正确返回 'Welcome to the app!',语言系统即可按 Laravel 9 规范稳定运行。