guglielmoseminara/translatable

可翻译的eloquent模型。

2.1.0 2021-03-25 09:56 UTC

README

Build Status

此软件包提供了一种强大且透明的方式来管理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();

注意:目前对使用关系更新和插入新记录的支持有限。相反,您可以使用上述描述的辅助函数。