如何在Laravel项目中不使用lang/*.json文件实现多语言支持?
Laravel 无lang/*.json多语言集成方案(动态管理版)
核心方案:数据库驱动翻译(优先满足动态需求)
完全抛弃lang目录下的json文件,将翻译存储在数据库中,支持后台动态新增语言、修改翻译内容,无需改动代码。
推荐第三方包:spatie/laravel-translation-loader
该包完美兼容Laravel原生翻译体系,自动从数据库加载翻译,同时可兼容lang目录下的PHP数组文件(可选)。
分步实现:
- 安装包
composer require spatie/laravel-translation-loader
- 发布迁移文件
php artisan vendor:publish --provider="Spatie\TranslationLoader\TranslationLoaderServiceProvider" --tag="migrations"
- 运行迁移
生成language_lines表,存储翻译键、语言标识、翻译内容等字段:
php artisan migrate
- 动态管理翻译
直接通过后台CRUD操作language_lines表:
- 新增语言:添加
locale字段为目标语言(如fr、de)的记录 - 添加翻译:给指定
locale和key赋值text内容
- 使用翻译
依然使用Laravel原生翻译函数,自动从数据库读取:
// 视图中 @lang('welcome.greeting') // 控制器/模型中 __('welcome.greeting')
自定义实现(无第三方包)
若不想依赖第三方包,可自行实现Laravel的TranslationLoaderInterface,完全控制翻译加载逻辑。
1. 创建数据库表
生成translations表迁移:
php artisan make:migration create_translations_table
迁移文件内容:
public function up() { Schema::create('translations', function (Blueprint $table) { $table->id(); $table->string('key'); // 翻译键名,如welcome.greeting $table->string('locale'); // 语言标识,如zh-CN、en $table->text('value'); // 翻译内容 $table->string('namespace')->nullable(); // 命名空间,可选 $table->timestamps(); $table->unique(['key', 'locale', 'namespace']); }); }
运行迁移:
php artisan migrate
2. 创建翻译模型
// app/Models/Translation.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Translation extends Model { protected $fillable = ['key', 'locale', 'value', 'namespace']; }
3. 实现自定义翻译加载器
// app/Translation/DatabaseTranslationLoader.php namespace App\Translation; use Illuminate\Contracts\Translation\Loader; use App\Models\Translation; use Illuminate\Support\Facades\Cache; class DatabaseTranslationLoader implements Loader { protected $model; public function __construct(Translation $model) { $this->model = $model; } public function load($locale, $group, $namespace = null) { // 缓存翻译,减少数据库查询 $cacheKey = "translations_{$locale}_{$group}_{$namespace}"; return Cache::remember($cacheKey, now()->addDays(7), function () use ($locale, $namespace) { $query = $this->model->where('locale', $locale); if ($namespace) { $query->where('namespace', $namespace); } return $query->pluck('value', 'key')->toArray(); }); } public function addLines(array $lines, $locale, $group = '*', $namespace = null) { foreach ($lines as $key => $value) { $this->model->updateOrCreate( ['key' => $key, 'locale' => $locale, 'namespace' => $namespace], ['value' => $value] ); } } public function namespaces() { return $this->model->distinct()->pluck('namespace')->filter()->toArray(); } }
4. 替换Laravel默认加载器
在AppServiceProvider的register方法中绑定自定义加载器:
// app/Providers/AppServiceProvider.php use App\Translation\DatabaseTranslationLoader; use App\Models\Translation; public function register() { $this->app->extend('translation.loader', function ($originalLoader, $app) { return new DatabaseTranslationLoader(new Translation()); }); }
5. 动态管理与使用
- 后台通过CRUD操作
translations表实现翻译新增/修改 - 使用Laravel原生翻译函数即可调用数据库中的翻译内容
最佳实践注意事项
- 语言回退配置
在config/app.php中设置 fallback 语言,避免翻译缺失:
'fallback_locale' => 'en',
- 支持的语言列表
添加可用语言配置,用于验证动态切换的语言:
'available_locales' => ['en', 'zh-CN', 'fr', 'de'],
- 动态切换语言中间件
编写中间件根据URL参数、Cookie或请求头切换语言:
// app/Http/Middleware/SetLocale.php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\App; class SetLocale { public function handle($request, Closure $next) { $availableLocales = config('app.available_locales'); // 优先取URL参数 if ($request->has('locale') && in_array($request->locale, $availableLocales)) { App::setLocale($request->locale); cookie()->queue('locale', $request->locale, 365 * 24 * 60); } // 其次取Cookie elseif ($request->cookie('locale') && in_array($request->cookie('locale'), $availableLocales)) { App::setLocale($request->cookie('locale')); } return $next($request); } }
将中间件注册到web中间件组即可生效。
内容的提问来源于stack exchange,提问作者PHP LARAVEL
相关产品推荐
相关产品推荐

