使用 laravel-translatable 实现 Laravel 中的模型翻译(多语言模型)

一些客户要求我们提供一项新功能——拥有多语言模型的能力。我们本可以将它内置到我们的生成器中,但是有一个包可以完成 99% 的工作,那么为什么要重新发明轮子而不是推荐一个好的替代方案呢?所以这里有一篇带有演示版本的文章如何添加Astrotomic/laravel-translatable (例如 dimsav/laravel-translatable) 进入我们的管理面板。

即使您没有使用我们的生成器,本文也将展示这个流行的多语言包是如何工作的,以及它是多么容易设置。

首先,我们所拥有的 - 一个使用 QuickAdminPanel生成的简单管理面板,其中有一个名为 articles 的 CRUD 项目 - 每篇文章都有一个标题全文

laravel 多语言文章

最重要的是,我们增加了使文章多语言的可能性。

步骤1. 安装包

composer require astrotomic/laravel-translatable

步骤2. 迁移翻译表

在此示例中,我们正在使用 Article 模型,因此我们将相应地创建迁移 - 包要求它是 XXXTranslation。

php artisan make:model ArticleTranslation -m

它将创建一个翻译模型和迁移,我们填充如下:

public function up()
{
   Schema::create('article_translations', function (Blueprint $table) {
       // 必须填写
       $table->bigIncrements('id'); // Laravel 5.8+ use bigIncrements() instead of increments()
       $table->string('locale')->index();

       // 主模型的外键
       $table->unsignedInteger('article_id');
       $table->unique(['article_id', 'locale']);
       $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');

       // 您要翻译的实际字段
       $table->string('title');
       $table->longText('full_text');
   });
}

此外,如果您在文章模型中有这些字段,你需要在迁移中删除它们。

Schema::table('articles', function (Blueprint $table) {
    $table->dropColumn('title');
    $table->dropColumn('full_text');
});

注意:如果您有真实的文章,请提前 备份/导出 您的文章数据。

同时,在模型的 $fillable  数组中删除它们:

class Article extends Model
{
    // You don't need these anymore
    protected $fillable = [
      // 'title',
      // 'full_text'
    ];

现在,完事,运行:

php artisan migrate

步骤 3. 模型设置

让我们开始模型设置 – 在我们的例子使用 app/Article.php

现在您需要在类签名之后,添加带有所谓 use 关键字的 trait。我们将使用 Translatable trait。并确保您在命明空间下声明了 use Astrotomic\Translatable\Translatable; 。

另一件事是添加 $translatedAttributes 属性,它分配有要翻译的属性数组。内容如下所示:

public $translatedAttributes = ['title', 'full_text']. 

所以这是最终的 Article.php 模型和需要注意的三个要点 —— 请参考备注:

namespace App;

use Illuminate\Database\Eloquent\Model;

// 1. 指定你正在使用的包的类
use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Astrotomic\Translatable\Translatable;

class Article extends Model implements TranslatableContract
{
    use Translatable; // // 2. 添加翻译方法

    //  3. 定义哪些属性需要翻译
    public $translatedAttributes = ['title', 'full_text'];
}

现在我们需要设置一个翻译模型—— app/ArticleTranslation.php. 在这里,您只需将与我们在之前模型中分配给 $translatedAttributes的数组相同的数组分配给 protected $fillable , 并使用 public $timestamps = false; 指定我们不需要时间戳。

namespace App;

use Illuminate\Database\Eloquent\Model;

class ArticleTranslation extends Model
{
   protected $fillable = ['title', 'full_text'];
   public $timestamps = false;
}

步骤 4. 配置包

让我们回到终端来完成配置。

  • 运行 php artisan vendor:publish ‐‐tag=translatable
  • 打开 config/translatable.php 来决定我们使用什么语言。在这个案例中我们将仅使用英语和西班牙语。但是您可以随意地使用您想要的语言。
  • 改动 locales 数组,添加您想要的语言代码。
// ...
'locales' => [
   'en',
   'es'
],

步骤 5. 创建视图 – 选择语言

现在我们将准备一个 resources/views/admin/articles/create.blade.php 文件,用于创建新制作的多语言文章。后续设计方案,它只是众多可用的解决方案之一。

首先,我们将添加用于语言和数据之间的引导选项卡:

<ul class="nav nav-tabs">
   <li class="nav-item">
       <a class="nav-link bg-aqua-active" href="#" id="english-link">EN</a>
   </li>
   <li class="nav-item">
       <a class="nav-link" href="#" id="spanish-link">ES</a>
   </li>
</ul>

现在我们为输入字段添加两个相同样式的面板——英语和西班牙语:

<div class="card-body" id="english-form">
    <div class="form-group">
        <label class="required" for="en_title">{{ trans('cruds.article.fields.title') }} (EN)</label>
        <input class="form-control {{ $errors->has('en_title') ? 'is-invalid' : '' }}" type="text" name="en_title" id="en_title" value="{{ old('en_title', '') }}" required>
        @if($errors->has('en_title'))
            <div class="invalid-feedback">
                {{ $errors->first('en_title') }}
            </div>
        @endif
        <span class="help-block">{{ trans('cruds.article.fields.title_helper') }}</span>
    </div>
    <div class="form-group">
        <label for="en_full_text">{{ trans('cruds.article.fields.full_text') }} (EN)</label>
        <textarea class="form-control {{ $errors->has('en_full_text') ? 'is-invalid' : '' }}" name="en_full_text" id="en_full_text">{{ old('en_full_text') }}</textarea>
        @if($errors->has('en_full_text'))
            <div class="invalid-feedback">
                {{ $errors->first('en_full_text') }}
            </div>
        @endif
        <span class="help-block">{{ trans('cruds.article.fields.full_text_helper') }}</span>
    </div>
</div>

<div class="card-body d-none" id="spanish-form">
    <div class="form-group">
        <label class="required" for="title">{{ trans('cruds.article.fields.title') }} (ES)</label>
        <input class="form-control {{ $errors->has('es_title') ? 'is-invalid' : '' }}" type="text" name="es_title" id="es_title" value="{{ old('es_title', '') }}" required>
        @if($errors->has('es_title'))
            <div class="invalid-feedback">
                {{ $errors->first('es_title') }}
            </div>
        @endif
        <span class="help-block">{{ trans('cruds.article.fields.title_helper') }}</span>
    </div>
    <div class="form-group">
        <label for="es_full_text">{{ trans('cruds.article.fields.full_text') }} (ES)</label>
        <textarea class="form-control {{ $errors->has('es_full_text') ? 'is-invalid' : '' }}" name="es_full_text" id="es_full_text">{{ old('es_full_text') }}</textarea>
        @if($errors->has('es_full_text'))
            <div class="invalid-feedback">
                {{ $errors->first('es_full_text') }}
            </div>
        @endif
        <span class="help-block">{{ trans('cruds.article.fields.full_text_helper') }}</span>
    </div>
</div>

注意事项 1:字段名称以语言代码为前缀并带有符号“_”,例如 en_titlees_full_text。它将帮助我们以后保存数据。
注意事项 2: 一个面板有一个来自Bootstrap 4的代码class=“d-None”

您可以通过动态地从配置中获取语言来进一步自定义它,但在本文中,我们将其简化为这两种语言。

现在只需添加几行jQuery代码:

   var $englishForm = $('#english-form');
   var $spanishForm = $('#spanish-form');
   var $englishLink = $('#english-link');
   var $spanishLink = $('#spanish-link');

   $englishLink.click(function() {
     $englishLink.toggleClass('bg-aqua-active');
     $englishForm.toggleClass('d-none');
     $spanishLink.toggleClass('bg-aqua-active');
     $spanishForm.toggleClass('d-none');
   });

   $spanishLink.click(function() {
     $englishLink.toggleClass('bg-aqua-active');
     $englishForm.toggleClass('d-none');
     $spanishLink.toggleClass('bg-aqua-active');
     $spanishForm.toggleClass('d-none');
   });

您应该会看到如下内容:

Laravel

现在,编辑 表单几乎与创建表单相同,但有以下改变:

1. 不同的头部和操作路径:

<form action="{{ route('admin.articles.update', $article->id) }}" method="PUT">

也相应的更改每个 old() 函数的参数以加载模型的旧数据:

<label class="required" for="en_title">{{ trans('cruds.article.fields.title') }} (EN)</label>
<input type="text" name="en_title" value="{{ $article->translate('en')->title }}" class="form-control" />

步骤 6. 在控制器中保存翻译

直接前往 app/Http/Controllers/Admin/ArticlesController.php 来保存我们的表单数据,然后我们就可以开始了。

创建我们的模型时,关键点是指定那种语言获取哪种数据,此代码应放在以下位置:

public function store(Request $request) {
    $article_data = [
       'en' => [
           'title'       => $request->input('en_title'),
           'full_text' => $request->input('en_full_text')
       ],
       'es' => [
           'title'       => $request->input('es_title'),
           'full_text' => $request->input('es_full_text')
       ],
    ];

    // 现在只需将此数组传递给常规的 Eloquent 函数,瞧
    Article::create($article_data);

    // 重定向到上一页
    return redirect()->route('admin.articles.index');
}

从现在开始,当您想要访问模型的翻译属性时,只需在您代码中的任何位置键入

$article->translate('en')->title

获得英文版的标题。或者,如果您想要当前语言环境(语言)的翻译版本,只需键入:

$article->title

此外,update() 方法也非常相似:

public function update($id, Request $request) {
    $article_data = [
       'en' => [
           'title'       => $request->input('en_title'),
           'full_text' => $request->input('en_full_text')
       ],
       'es' => [
           'title'       => $request->input('es_title'),
           'full_text' => $request->input('es_full_text')
       ],
    ];

    $article = Article::findOrFail($id);
    $article->update($article_data);

    // Redirect to the previous page successfully    
    return redirect()->route('admin.articles.index');
}

最后的小提示。如果您想改变当前应用程序语言环境,它就像这样简单:

App::locale('es');

进一步了解这么棒的语言包,请访问 github.com/Astrotomic/laravel-tran... 以获得更深入的文档。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://blog.quickadminpanel.com/how-to-...

译文地址:https://learnku.com/laravel/t/69043

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 1

不用对接平台就能实现翻译吗

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!