slivka-b/laravel-translatable

[分支] 该包提供使用单个数据库表将您的 Eloquent 模型翻译成不同语言的功能。

0.1.1 2023-03-21 13:40 UTC

This package is auto-updated.

Last update: 2024-09-21 16:38:54 UTC


README

此包是从 nevadskiy/laravel-translatable 分支出来的。

Tests Code Coverage License Latest Stable Version

该包提供使用单个数据库表将您的 Eloquent 模型翻译成不同语言的功能。

🍬 特点

  • 自动解决当前区域的模型翻译。
  • 无需重写现有的迁移、模型或视图。
  • 将所有翻译存储在单个 'translations' 表中。
  • 与模型访问器 & 变更器 & 转换器一起工作,甚至与 JSON 一起工作。
  • 与路由模型绑定一起工作。
  • 存档翻译以改善搜索体验。
  • 提供有用的事件。

⚙️ 演示

$book = Book::create(['title' => 'Book about giraffes']);

// Storing translations
app()->setLocale('es');
$book->title = 'Libro sobre jirafas';
$book->save();

// Reading translations
app()->setLocale('es');
echo $book->title; // 'Libro sobre jirafas'

app()->setLocale('en');
echo $book->title; // 'Book about giraffes'

✅ 要求

  • Laravel 9.0 或更高版本
  • PHP 8.0 或更高版本

🔌 安装

  1. 通过 composer 安装此包。
composer require imcity-tech/laravel-translatable
  1. 可选。如果您不打算为具有 UUID 主键的模型使用翻译,请执行以下操作:
  • 发布包迁移
php artisan vendor:publish --tag=translatable
  • 在发布的迁移中将行 $table->uuidMorphs('translatable'); 替换为 $table->morphs('translatable');
  1. 运行迁移命令。
php artisan migrate

🔨 使模型可翻译

  1. HasTranslations 特性添加到您想要使可翻译的模型中。
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Nevadskiy\Translatable\HasTranslations;

class Post extends Model
{
    use HasTranslations;
}
  1. $translatable 数组添加到您的模型中,包含您想要可翻译的属性。
/**
 * The attributes that can be translatable.
 *
 * @var array
 */
protected $translatable = [
    'title',
    'description',
];

最终模型可能看起来像这样

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Nevadskiy\Translatable\HasTranslations;

class Post extends Model
{
    use HasTranslations; 

    protected $translatable = [
        'title', 
        'description',
    ];
}

📄 文档

默认区域值按常规存储在原始表中。

每个可翻译模型的非默认区域的值存储在单个 translations 表中。

该包从 config('app.fallback_locale') 值中获取默认区域。

自动使用可翻译属性存储和检索模型的翻译
$book = Book::where('title', 'Book about birds')->first();

app()->setLocale('ru');

$book->update(['title' => 'Книга о птицах']);

echo $book->title; // 'Книга о птицах'

app()->setLocale('en');

echo $book->title; // 'Book about birds'
手动存储和检索模型的翻译
$book = Book::where('title', 'Book about dolphins')->first();

$book->translate('title', 'Книга о дельфинах', 'ru');

echo $book->getTranslation('title', 'ru'); // 'Книга о дельфинах'
读取翻译的方法
创建可翻译模型

请注意,即使当前区域不同,可翻译模型也将始终在 默认 区域中创建。任何翻译都可以仅附加到 现有 模型。

app()->setLocale('de');
Book::create(...); // This will persist model as usual with the default application locale.
显示模型集合

该包自动为您预加载当前区域的翻译,因此您可以像平常一样轻松检索模型集合。

// In a controller
app()->setLocale('ru');
$books = Book::paginate(20);

// In a view
@foreach ($books as $book)
    {{ $book->title }} // Shows a title in the current locale OR in the default locale if a translation is missing.
@endforeach
翻译与模型访问器一起工作
class Book extends Model
{
    // ...

    public function getTitleAttribute()
    {
        return Str::ucfirst($this->attributes['title']);
    }
}

$book = Book::create(['title' => 'book about birds']);
$book->translate('title', 'книга о птицах', 'ru');

// Using attribute with the current locale
app()->setLocale('ru');
echo $book->title; // 'Книга о птицах'

// Using getTranslate method
echo $book->getTranslation('title', 'ru'); // 'Книга о птицах'
翻译也与模型变更器一起工作
class Book extends Model
{
    public function setDescriptionAttribute($description)
    {
        $this->attributes['description'] = Str::substr($description, 0, 10);
    }
}

$book = Book::create(['description' => 'Very long description']);
$book->translate('description', 'Очень длинное описание', 'ru');

// Using attribute with the current locale
app()->setLocale('ru');
echo $book->description; // 'Очень длин'

// Using getTranslation method
echo $book->getTranslation('description', 'ru'); // 'Очень длин'
删除未使用的翻译

该包自动删除删除的模型的翻译,并尊重 softDeletes,但如果使用查询构建器删除了可翻译模型,其翻译将存在于数据库中。要手动删除所有未使用的翻译,请运行 php artisan translatable:remove-unused 命令。

查询没有翻译的模型

有时您可能需要查询没有 translations 关系的可翻译模型。您可以使用 withoutTranslations 范围来实现这一点。

$books = Book::withoutTranslations()->get();
查询翻译

您可以通过可翻译属性执行可翻译模型的查询。

$books = Book::whereTranslatable('title', 'Книга о жирафах')->get();

它也可以与默认区域的值一起工作。

如果您只想按特定区域查询行,您应该自己传递它。

$books = Book::whereTranslatable('title', 'Книга о жирафах', 'ru')->get();

否则,查询构建器将返回所有可用区域中匹配的行。

您还可以使用不同的运算符来查询翻译。

$books = Book::whereTranslatable('title', 'Book about%', null, 'LIKE')->get();
// or
$books = Book::whereTranslatable('title', 'Книги о%', 'ru', 'LIKE')->get();
排序翻译

按当前区域的可翻译属性对模型进行排序。

$books = Book::orderByTranslatable('title')->get();

按特定区域的可翻译属性对模型进行排序。

$books = Book::orderByTranslatable('title', 'desc', 'de')->get();

对于更复杂的查询 - 随意使用 Laravel 关系查询

禁用自动加载

如果您不想在交互可翻译属性时自动加载或保存翻译,可以禁用此功能。

要为特定模型禁用,请在您的模型中覆盖如下 autoLoadTranslationsautoSaveTranslations 方法。

class Post extends Model
{
    use HasTranslations;

    protected $translatable = ['title'];

    public function autoLoadTranslations()
    {
        return false;
    }

    public function autoSaveTranslations()
    {
        return false;
    }
}

或全局应用于所有模型。

use Nevadskiy\Translatable\Translatable;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->app[Translatable::class]->disableAutoLoading();
        $this->app[Translatable::class]->disableAutoSaving();
    }
}
归档翻译

有时,归档一些不会自动解决的翻译,但可用于搜索功能是有用的。例如,您可以使用以下代码手动存储归档翻译

$post = Post::first();
$post->archiveTranslation('title', 'Old title', 'en');

现在 旧标题 与允许使用 whereTranslatable 范围查找帖子的帖子相关联

Post::whereTranslatable('title', 'Old title')->get();

当不知道区域设置时,您也可以将 null 作为 archiveTranslation 方法的第三个参数传递。如果不传递 null,则将使用当前区域设置。

路由模型绑定

可翻译模型可以很容易地使用 路由模型绑定 功能解析。

您需要做的全部是设置用于查询模型的所需区域设置,在请求到达 Illuminate\Routing\Middleware\SubstituteBindings::class 中间件之前使用 before

最简单的解决方案是创建一个新的中间件,例如 SetLocaleMiddleware,将其附加到您想要解析可翻译模型的路由上,并在 app/Http/Kernel.php 文件中注册中间件,在 \Illuminate\Routing\Middleware\SubstituteBindings::class 类之上。

它可能看起来像这样

// app/Http/Middleware/SetLocaleMiddleware.php
public function handle($request, Closure $next)
{
    // Setting the current locale from cookie
    app()->setLocale($request->cookie('locale'));
}
// app/Http/Kernel.php
protected $middlewareGroups = [
    'web' => [
        // ... default middleware stack
        \App\Http\Middleware\SetLocaleMiddleware::class, // <--- your middleware
        \Illuminate\Routing\Middleware\SubstituteBindings::class, // <--- bindings middleware
    ],
];

protected $middlewarePriority = [
    // ... default middleware stack
    \App\Http\Middleware\SetLocaleMiddleware::class, // <--- your middleware above
    \Illuminate\Routing\Middleware\SubstituteBindings::class, // <--- bindings middleware below
];

有关排序中间件的更多信息,请参阅 这里

// routes/web.php
Route::get('posts/{post:slug}', 'PostsController@show');
// app/Http/Controllers/PostController.php
public function show(Post $post)
{
    // Post model is resolved by translated slug using the current locale.
}
使用形态映射

建议为所有可翻译模型使用 morph map 以最小化数据库与应用程序结构之间的耦合。

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'posts' => Post::class,
    'categories' => Category::class,
]);

有关形态映射的更多信息,请参阅 这里

📑 更新日志

请参阅 更新日志 以获取有关最近更改的更多信息。

☕ 贡献

请参阅 贡献指南 以获取更多信息。

🔓 安全性

如果您发现任何与安全性相关的问题,请通过 电子邮件 而不是使用问题跟踪器与我联系。

📜 许可证

MIT 许可证(MIT)。有关更多信息,请参阅 许可证