接近/laravel-translatable

此包已被弃用且不再维护。未建议替代包。

Laravel 多语言模型包

dev-master 2017-03-25 15:30 UTC

This package is not auto-updated.

Last update: 2018-02-16 13:29:01 UTC


README

这是一个为可翻译模型提供的 Laravel 包。如果您想将模型的翻译存储到数据库中,这个包适合您。

演示

获取翻译属性

  $greece = Country::where('code', 'gr')->first();
  echo $greece->translate('en')->name; // Greece
  
  App::setLocale('en');
  echo $greece->name;     // Greece

  App::setLocale('de');
  echo $greece->name;     // Griechenland

保存翻译属性

  $greece = Country::where('code', 'gr')->first();
  echo $greece->translate('en')->name; // Greece
  
  $greece->translate('en')->name = 'abc';
  $greece->save();
  
  $greece = Country::where('code', 'gr')->first();
  echo $greece->translate('en')->name; // abc

填充多个翻译

  $data = [
    'code' => 'gr',
    'en'  => ['name' => 'Greece'],
    'fr'  => ['name' => 'Grèce'],
  ];

  $greece = Country::create($data);
  
  echo $greece->translate('fr')->name; // Grèce

教程

查看laravel-news上关于laravel-translatable的教程: 如何为 Eloquent 添加多语言支持

4 步安装

第 1 步:安装包

通过执行以下命令将包添加到您的 composer.json 中。

composer require approached/laravel-translatable

接下来,将服务提供者添加到 app/config/app.php

Approached\Translatable\TranslatableServiceProvider::class,

第 2 步:迁移

在这个例子中,我们想翻译模型 Country。我们需要一个额外的表 country_translations

Schema::create('countries', function(Blueprint $table)
{
    $table->increments('id');
    $table->string('code');
    $table->timestamps();
});

Schema::create('country_translations', function(Blueprint $table)
{
    $table->increments('id');
    $table->integer('country_id')->unsigned();
    $table->string('name');
    $table->string('locale')->index();

    $table->unique(['country_id','locale']);
    $table->foreign('country_id')->references('id')->on('countries')->onDelete('cascade');
});

第 3 步:模型

  1. 可翻译模型 Country 应该使用 特性 Approached\Translatable\Translatable
  2. 翻译模型的约定是 CountryTranslation
// models/Country.php
class Country extends Eloquent {
    
    use \Approached\Translatable\Translatable;
    
    public $translatedAttributes = ['name'];
    protected $fillable = ['code', 'name'];
    
    /**
     * The relations to eager load on every query.
     *
     * @var array
     */
    // (optionaly)
    // protected $with = ['translations'];

}

// models/CountryTranslation.php
class CountryTranslation extends Eloquent {

    use CompositeKeys;

    public $timestamps = false;
    protected $fillable = ['name'];
    public $incrementing = false;

    protected $primaryKey = [
        'id',
        'locale'
    ];

}

数组 $translatedAttributes 包含在 "Translation" 模型中翻译的字段名称。

第 4 步:配置

Laravel 4.*

php artisan config:publish approached/laravel-translatable

Laravel 5.*

php artisan vendor:publish 

使用此命令初始化配置并修改位于 app/config/packages/approached/laravel-translatable/translatable.php 下的创建的文件。

注意:对地区格式的限制没有任何限制。请随意使用您更喜欢的格式,例如 "eng" 而不是 "en",或 "el" 而不是 "gr"。重要的是定义您的地区并坚持使用。

配置

翻译模型

用于定义翻译模型类的约定是附加关键词 Translation

因此,如果您的模型是 \MyApp\Models\Country,则默认翻译为 \MyApp\Models\CountryTranslation

要使用自定义类作为翻译模型,定义翻译类(包括命名空间)作为参数。例如

<?php 

namespace MyApp\Models;

use Approached\Translatable\Translatable;
use Illuminate\Database\Eloquent\Model as Eloquent;

class Country extends Eloquent
{
    use Translatable;

    public $translationModel = 'MyApp\Models\CountryAwesomeTranslation';
}

文档

请首先阅读安装步骤,以了解需要创建哪些类。

可用方法

// Before we get started, this is how we determine the current locale.
// It is set by laravel or other packages.
App::getLocale(); // 'fr' 

// To use this package, first we need an instance of our model
$germany = Country::where('code', 'de')->first();

// This returns an instance of CountryTranslation of using the current locale.
// So in this case, french. If no french translation is found, it returns null.
$translation = $germany->translate();

// If an german translation exists, it returns an instance of 
// CountryTranslation. Otherwise it returns null.
$translation = $germany->translate('de');

// If a german translation doesn't exist, it attempts to get a translation  
// of the fallback language (see fallback locale section below).
$translation = $germany->translate('de', true);

// Alias of the above.
$translation = $germany->translateOrDefault('de');

// Returns instance of CountryTranslation of using the current locale.
// If no translation is found, it returns a fallback translation
// if enabled in the configuration.
$translation = $germany->getTranslation();

// If an german translation exists, it returns an instance of 
// CountryTranslation. Otherwise it returns null.
// Same as $germany->translate('de');
$translation = $germany->getTranslation('de', true);

// Returns true/false if the model has translation about the current locale. 
$germany->hasTranslation();

// Returns true/false if the model has translation in french. 
$germany->hasTranslation('fr');

// If a german translation doesn't exist, it returns
// a new instance of CountryTranslation.
$translation = $germany->translateOrNew('de');

// Returns a new CountryTranslation instance for the selected
// language, and binds it to $germany
$translation = $germany->getNewTranslation('it');

// The eloquent model relationship. Do what you want with it ;) 
$germany->translations();

可用作用域

// Returns all countries having translations in english
Country::translatedIn('en')->get();

// Returns all countries not being translated in english
Country::notTranslatedIn('en')->get();

// Returns all countries having translations
Country::translated()->get();

// Eager loads translation relationship only for the default
// and fallback (if enabled) locale
Country::withTranslation()->get();

// Returns an array containing pairs of country ids and the translated
// name attribute. For example: 
// [
//     ['id' => 1, 'name' => 'Greece'], 
//     ['id' => 2, 'name' => 'Belgium']
// ]
Country::listsTranslations('name')->get()->toArray();

// Filters countries by checking the translation against the given value 
Country::whereTranslation('name', 'Greece')->first();

// Filters countries by checking the translation against the given string with wildcards
Country::whereTranslationLike('name', '%Gree%')->first();

魔法属性

要使用魔法属性,您必须在主模型中定义属性 $translatedAttributes

class Country extends Eloquent {

    use \Approached\Translatable\Translatable;

    public $translatedAttributes = ['name'];
}
// Again we start by having a country instance
$germany = Country::where('code', 'de')->first();

// We can reference properties of the translation object directly from our main model.
// This uses the default locale and is the equivalent of $germany->translate()->name
$germany->name; // 'Germany'

// We can also quick access a translation with a custom locale
$germany->{'name:de'} // 'Deutschland'

回退语言

如果您想在没有找到翻译时回退到默认翻译,请使用 use_fallback 键在配置中启用它。要选择默认语言,请使用 fallback_locale 键。

配置示例

return [
    'use_fallback' => true,

    'fallback_locale' => 'en',    
];

您还可以通过设置 $useTranslationFallback 属性来为“是否使用回退”定义每个模型默认值。

class Country {

    public $useTranslationFallback = true;

}

基于国家的回退

从版本 v5.3 开始,可以使用基于国家的语言环境。例如,您可以有以下语言环境

  • 英语: en
  • 西班牙语: es
  • 墨西哥西班牙语: es-MX
  • 哥伦比亚西班牙语: es-CO

这些语言的配置如下所示

    'locales' => [ 
        'en',
        'es' => [
            'MX',
            'CO',
        ],
    ];

我们还可以配置语言和国家之间的“粘合剂”。例如,如果我们更喜欢格式 es_MX 而不是 es-MX,则配置应如下所示

   'locale_separator' => '_',

对于使用 en-MX 格式的语言回退,有何影响?

假设我们的回退语言是 en。现在,当我们尝试从数据库中检索 es-MX 语言环境的翻译,但不存在时,我们将不会回退到 en 的翻译。可翻译将使用 eses-MX 的第一部分)作为回退,并且只有在找不到任何内容时,才会返回 en 的翻译。

附加组件

多亏了社区,已经编写了一些包,使在使用表单时使用可翻译变得更容易

常见问题解答

我需要一些示例代码!

所有包功能的示例可以在 测试中使用的代码 中找到。

我需要帮助!

有任何问题或建议?请随时打开一个 问题

我想帮忙!

您太棒了!查看存储库并回复问题。您将帮助提供出色的用户体验。 #communityWorks

我遇到了与其他特质方法冲突的情况!

可翻译完全兼容所有类型的 Eloquent 扩展,包括 Ardent。如果您需要帮助将这些扩展与可翻译一起实现,请参阅此 示例

我如何根据翻译进行排序?

这里的一个提示是先执行 MySQL 查询,然后再执行 Eloquent 查询。

要获取按翻译字段排序的记录列表,您可以这样做

SELECT * from countries
JOIN country_translations as t on t.country_id = countries.id 
WHERE locale = 'en'
GROUP BY countries.id
ORDER BY t.name desc

相应的 Eloquent 查询如下所示

Country::join('country_translations as t', 't.country_id', '=', 'countries.id')
    ->where('locale', 'en')
    ->groupBy('countries.id')
    ->orderBy('t.name', 'desc')
    ->with('translations')
    ->get();

我如何通过翻译字段选择国家?

例如,让我们假设我们想要找到名称等于 '葡萄牙' 的国家。

Country::whereHas('translations', function ($query) {
    $query->where('locale', 'en')
    ->where('name', 'Portugal');
})->first();

您可以在 Laravel 的 查询关系文档 中找到更多信息。

为什么在运行迁移时我遇到了 mysql 错误?

如果您看到以下 mysql 错误

[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create table 'my_database.#sql-455_63'
  (errno: 150) (SQL: alter table `country_translations` 
  add constraint country_translations_country_id_foreign foreign key (`country_id`) 
  references `countries` (`id`) on delete cascade)

那么您的表使用的是 MyISAM 引擎,该引擎不允许外键约束。MyISAM 是 5.5 版本之前 mysql 的默认引擎。自 版本 5.5 以来,默认使用 InnoDB 存储引擎创建表。

如何修复

对于已经在生产环境中创建的表,更新迁移以更改表的引擎,然后再添加外键约束。

public function up()
{
    DB::statement('ALTER TABLE countries ENGINE=InnoDB');
}

public function down()
{
    DB::statement('ALTER TABLE countries ENGINE=MyISAM');
}

对于新表,一个快速解决方案是在迁移中设置存储引擎

Schema::create('language_translations', function(Blueprint $table){
  $table->engine = 'InnoDB';
  $table->increments('id');
    // ...
});

然而,最好的解决方案是更新您的 mysql 版本。并且 一定要确保开发和生产环境中的版本相同!