levgenij / translatable
可翻译的Eloquent模型。
Requires
- php: >=5.5.0
- illuminate/database: ~5.2
Requires (Dev)
- phpunit/phpunit: 5.1.*
README
此包提供了一种强大且透明的方式来管理Eloquent中的多语言模型。
它利用Laravel 5.2增强的全局作用域将翻译属性连接到每个查询,而不是像一些替代包那样利用关系。因此,只需要一个查询即可检索翻译属性,无需为翻译表创建单独的模型,这使得此包更容易使用。
快速演示
要在模型中启用翻译,您首先需要根据约定准备您的模式。然后,您可以引入Translatable
特征
use Laraplus\Data\Translatable; use Illuminate\Database\Eloquent\Model; class Post extends Model { use Translatable; }
这就完了!不需要其他配置。翻译属性将被自动缓存,并且所有查询都将开始返回翻译属性
Post::first(); $post->title; // title in the current locale Post::translateInto('de')->first(); $post->title; // title in 'de' locale Post::translateInto('de')->withFallback('en')->first(); $post->title; // title in 'de' if available, otherwise in 'en'
由于翻译已连接到查询,因此也可以非常容易地通过翻译属性进行过滤和排序
Post::where('body', 'LIKE', '%Laravel%')->orderBy('title', 'desc');
甚至只返回翻译记录
Post::onlyTranslated()->all()
所有基本CRUD操作都提供了一些辅助器。有关所有可用选项,请参阅下面的完整文档。
安装
此包可以在Laravel或Lumen应用程序中使用,以及任何使用Laravel数据库组件的应用程序https://github.com/illuminate/database。可以通过composer安装此包
composer require laraplus/translatable
Laravel中的配置
要配置包,请将服务提供程序添加到您的app.php
配置文件中的providers
键下
'providers' => [ // other providers Laraplus\Data\TranslatableServiceProvider::class ];
您还可以通过发布translatable.php
配置文件来配置一些其他选项
php artisan vendor:publish --provider="Laraplus\Data\TranslatableServiceProvider" --tag="config"
打开配置文件以检查所有可用设置:https://github.com/laraplus/translatable/blob/master/config/translatable.php
Laravel之外的配置
当在Laravel之外使用此包时,您可以使用TranslatableConfig
类进行配置
TranslatableConfig::currentLocaleGetter(function() { // return the current locale of the application }); TranslatableConfig::fallbackLocaleGetter(function() { // return the fallback locale of the application });
您还可以调整一些其他设置。要查看所有可用选项,请检查Laravel的服务提供程序:https://github.com/laraplus/translatable/blob/master/src/TranslatableServiceProvider.php
创建迁移
要使用多语言模型,您需要以特定方式准备您的数据库表。每个可翻译的表由可翻译属性和非可翻译属性组成。虽然非可翻译属性可以像通常那样添加到您的表中,但可翻译字段需要在其自己的表中,该表应按照约定命名。
以下是一个针对posts
表的示例迁移
Schema::create('posts', function(Blueprint $table) { $table->increments('id'); $table->datetime('published_at'); $table->timestamps(); }); Schema::create('posts_i18n', function(Blueprint $table) { $table->integer('post_id')->unsigned(); $table->string('locale', 6); $table->string('title'); $table->string('body'); $table->primary(['post_id', 'locale']); });
默认情况下,翻译表必须以_i18
后缀结尾,但可以在配置文件中更改。此外,翻译表必须包含指向父表的键以及一个locale
字段(也可以配置),该字段将存储翻译属性的区域设置。不允许在翻译模型上使用递增键。需要定义一个包含locale
和父模型外键引用的复合键。您还可以选择定义外键约束,但即使没有这些约束,该包也能正常工作。
重要:请确保没有翻译的属性与任何未翻译的属性同名,因为这样会破坏查询。这也适用于时间戳(不应添加到翻译表中,而应仅添加到主表中)和递增键(不允许在翻译表中)。
配置模型
为了使您的模型意识到翻译属性,您需要引入Translatable
特性。
use Laraplus\Data\Translatable; use Illuminate\Database\Eloquent\Model; class Post extends Model { use Translatable; }
您可以可选地定义一个$translatable
属性数组,但该包设计为无需它也能工作。在这种情况下,翻译属性将自动从数据库模式中确定并无限期缓存。如果您使用缓存方法,请不要忘记在模式更改时清除缓存。
默认情况下,如果模型未翻译成当前区域设置,将选择回退翻译。如果没有可用的翻译,所有翻译属性将返回null。如果您希望更改此行为,您可以修改translatable.php
配置文件或根据“每个模型”调整行为。
class Post extends Model { use Translatable; protected $withFallback = false; protected $onlyTranslated = true; }
CRUD操作
选择行
要选择您的可翻译模型的行,您可以使用所有常规Eloquent查询助手。可翻译属性将返回您的当前区域设置。有关如何在Laravel中配置本地化的更多信息,请参阅官方文档:https://laravel.net.cn/docs/5.2/localization
Post::where('active', 1)->orderBy('title')->get();
查询助手
上述查询默认情况下也将返回在当前或回退区域设置中没有翻译的记录。要返回仅翻译的行,您可以将defaults.only_translated
配置选项更改为true
,或使用onlyTranslated()
查询助手。
Post::onlyTranslated()->get();
有时您可能希望完全禁用回退翻译。为此,您可以更改defaults.with_fallback
配置选项为false
或使用withoutFallback()
查询助手。
Post::withoutFallback()->get();
上述两个助手也有它们的对立形式:withUntranslated()
和withFallback()
。您还可以向withFallback()
助手提供一个可选的$locale
参数,以更改默认的回退区域设置。
Post::withUntranslated()->withFallback()->get(); Post::withUntranslated()->withFallback('de')->get();
有时您可能希望以与当前区域设置不同的区域设置检索翻译。为此,您可以使用translateInto($locale)
助手。
Post::translateInto('de')->get();
如果您根本不需要翻译属性,您可以使用withoutTranslations()
助手,这将从查询中删除可翻译的全局作用域。
Post::withoutTranslations()->get();
按翻译属性过滤和排序
您经常可能希望通过翻译属性过滤查询结果。此包允许您使用所有常规Eloquent where
子句。这将与回退翻译一起工作,因为where子句中的所有列都将自动用ifnull
语句包装,并使用适当的表名作为前缀。
Post::where('title', 'LIKE', '%Laravel%')->orWhere('description', 'LIKE', '%Laravel%')->get();
相同的规则也适用于order by
子句,它也将自动转换为正确的格式。
Post::orderBy('title')->get();
注意:如果您使用whereRaw
子句,由于我们不解析whereRaw表达式,我们将无法自动格式化您的表达式。相反,您需要手动包括适当的表前缀。
插入行
在当前区域设置中创建新模型时,您可以使用正常的Laravel语法,就像您在单个表中插入行一样。
Post::create([ 'title' => 'My title', 'published_at' => Carbon::now() ]);
如果您想将记录存储在替代区域设置中,您可以使用createInLocale($locale, $attributes)
助手。
Post::createInLocale('de', [ 'title' => 'Title in DE', 'published_at' => Carbon::now() ]);
通常,您需要将新记录与其所有翻译一起存储。为此,您可以将可翻译属性作为create()
方法的第二个参数列出。
Post::create([ 'published_at' => Carbon::now() ], [ 'en' => ['title' => 'Title in EN'], 'de' => ['title' => 'Title in DE'], ]);
上述所有助手都有它们的force
形式,允许您破坏大量赋值保护。
Post::forceCreate([/*attributes*/], [/*translations*/]); Post::forceCreateInLocale($locale, [/*attributes*/]);
更新行
在当前区域设置中更新记录就像更新单个表一样简单。
$user = User::first(); $user->title = 'New title'; $user->save();
如果您想更新其他地区的记录,可以使用saveTranslation($locale, $attributes)
辅助函数,该函数将更新现有翻译或创建新的翻译(如果尚不存在)
$user = User::first(); $user->saveTranslation('en', [ 'title' => 'Title in EN' ]); $user->saveTranslation('de', [ 'title' => 'Title in DE' ]);
还有一个forceSaveTranslation($locale, $attributes)
辅助函数,可用于绕过大量赋值保护。
要一次性更新多行,您还可以使用查询构建器。
User::where('published_at', '>', Carbon::now())->update(['title' => 'New title']);
要使用查询构建器更新不同的地区,可以调用transleteInto($locale)
辅助函数。
User::where('published_at', '>', Carbon::now())->translateInto('de')->update(['title' => 'New title']);
删除行
删除行非常简单。按照常规操作,翻译将自动与父行一起删除。
$user = User::first(); $user->delete();
要一次性删除多行,您还可以使用查询构建器。翻译将自动清理。
User::where('published_at', '>', Carbon::now())->delete();
作为关系的翻译
有时您可能希望检索模型的所有翻译。幸运的是,该包实现了hasMany
关系,这将帮助我们完成这项任务。
$user = $user->first(); foreach($user->translations as $translation) { echo "Title in {$translation->locale}: {$translation->title}"; }
当您希望访问特定地区的属性时,可以调用translate($locale)
辅助函数。
$user = $user->first(); $user->translate('en')->title; // Title in EN $user->translate('de')->title; // Title in DE
在使用关系时,通常希望预加载它而不将翻译属性连接到查询。有一个withAllTranslations()
辅助函数可以做到这一点。
User::withAllTranslations()->get();
注意:目前对使用关系更新和插入新记录的支持有限。相反,您可以使用上面描述的辅助函数。