如何为 Eloquent 添加多语言支持
Eloquent ORM 是 Laravel 非常强大的一个部分。麻烦地是,它不提供开箱即用的支持多语言的模型。不过,自己来添加这个功能也不是有多困难。
我们先随便来找个例子看看一个没有多语言支持的迁移:
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('text');
$table->timestamps();
});
通过为特定语言添加列,我们可以轻松地建一张包含多种语言的表,如下:
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('name_en');
$table->text('text_en');
$table->string('name_fr');
$table->text('text_fr');
$table->boolean('online');
$table->timestamps();
});
现在,此表支持以英语和法语存储文本。显然,这种方法有个缺点:每当你想添加一个新的语言支持,你就不得不添加新的字段到支持多语言的每个表里面。当想要支持的语言开始变多,或者使用多语言支持的表多到某种数量,这种做法明显行不通。
而人们暂时能想到的最好的方法是为必须翻译的字段创建一个新的表。
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->boolean('online');
$table->timestamps();
});
Schema::create('article_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('article_id')->unsigned();
$table->string('locale')->index();
$table->string('name');
$table->text('text');
$table->unique(['article_id','locale']);
$table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');
});
当应用程序需要支持额外的语言时,巧妙地使用上面的迁移方法,就不再需要创建额外的字段。
上面的字段 locale
用于确定存储记录的语言。在本文的下一个示例中,我们将在此字段中存储一个 iso-code
。
添加关联删除的外键确保当 articles
表中的记录被删除时,它相应的翻译也将被删除。
到这里我们就已经为数据库准备好可翻译的内容了,接下来和我一起逐步思考该如何使用它。
$frenchText = $article->getTranslation('fr')->text;
以上无需解释一目了然的使用方法是非常赞的。还有更好的一个点,就是如果先设置当前应用程序的语言环境为法语,article
模型将返回法语的翻译内容:
app()->setLocale('fr');
$frenchText = $article->text;
这样的做法让翻译数据的工作变得更加容易。当然视图也可以有这样方便的做法:
The article with title {{ $article->title }} is {{ $this->online ? 'online' : 'offline' }}.
你看,使用翻译字段和非翻译字段没有任何区别。真的是超赞!
推荐一个我经常使用的 laravel-translatable,Dimitris Savvopoulos 写的一个轮子,可以执行所有这些操作。
根据 指引安装后,更新你的模型以使用 Translatable-trait。该模型还应该有一个 $translatableAttributes
属性的数组,其中字段 name
可以被翻译:
// app/Article.php
class Article extends Model
{
use \Dimsav\Translatable\Translatable;
public $translatedAttributes = ['name', 'text'];
...
}
// app/ArticleTranslation.php
class ArticleTranslation extends Model
{
public $timestamps = false;
...
}
现在所有的设置完成了,我们可以存储一些新的可翻译文章。写个简单的路由例子:
Route::get('create', function($locale) {
$article = new Article();
$article->online = true;
$article->save();
foreach (['en', 'nl', 'fr', 'de'] as $locale) {
$article->translateOrNew($locale)->name = "Title {$locale}";
$article->translateOrNew($locale)->text = "Text {$locale}";
}
$article->save();
echo 'Created an article with some translations!';
});
在浏览到 /create
查看数据库时,会看到 articles
表包含的记录。 article_translations
表包含三个记录:一个用于上面示例中的每个语言环境。
现在我们来检索翻译。添加这个路由:
Route::get('{locale}', function($locale) {
app()->setLocale($locale);
$article = Article::first();
return view('article')->with(compact('article'));
});
再添加一个 article.blade.php
的视图和以下的内容:
<h1>{{ $article->name }}</h1>
{{ $article->text }}
当你浏览到 /en
,你会看到文章的英文翻译。浏览 /nl
、/fr
或 /de
以查看这些区域设置的本地化文章。
恭喜!看到这里我想你已经学会了如何为 Eloquent 模型添加多语言支持。GitHub 上面有本文的 示例代码。但我更建议你去阅读 Laravel-Translatable 的 readme。如果你想了解得多一些,就去他的 GitHub 上查看源码。这不会很难,你会从中学到很多。
以上内容翻译改编自 Freek Van der Herten 的 How To Add Multilingual Support to Eloquent
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: