dimsav / laravel-translatable
Requires
- php: >=7.1.3
- illuminate/support: 5.6.*|5.7.*|5.8.*
Requires (Dev)
- orchestra/testbench: 3.6.*|3.7.*|3.8.*
- dev-master
- v10.0.0
- v9.5.0
- v9.4.0
- v9.3.0
- v9.2.0
- v9.1.0
- v9.0
- v8.1
- v8.0
- v7.3
- v7.2.1
- v7.2
- v7.1
- v7.0
- v6.1
- v6.0.1
- v6.0
- v5.6.1
- v5.6
- v5.5.1
- v5.5
- v5.4
- v5.3
- v5.2
- v5.1.2
- v5.1.1
- v5.1
- v5.0.1
- v5.0
- v4.5
- v4.4
- v4.3.2
- v4.3.1
- v4.3
- v4.2.1
- v4.2
- v4.1.1
- v4.1
- v4.0.1
- v4.0.0
- v3.0.1
- v3.0.0
- v2.0.0
- v1.0.1
- dev-ft-unify-where-translation-scopes
- dev-issue-309
This package is auto-updated.
Last update: 2022-02-01 12:30:58 UTC
README
此包已被弃用。但不用担心。您可以使用 Astrotomic/laravel-translatable.
Laravel-Translatable
如果您想要将模型翻译存储到数据库中,这个包就是为您准备的。
这是一个用于翻译模型的 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 兼容性
Laravel | 可翻译 |
---|---|
5.8 | 9.* |
5.7 | 9.* |
5.6 | 9.* |
5.5 | 8.* |
5.4 | 7.* |
5.3 | 6.* |
5.2 | 5.5 - 6.* |
5.1 | 5.0 - 6.* |
5.0 | 5.0 - 5.4 |
4.2.x | 4.4.x |
4.1.x | 4.4.x |
4.0.x | 4.3.x |
教程
- 请查看 laravel-news 中关于 laravel-translatable 的教程:如何在 Eloquent 中添加多语言支持
- 如何为您的 Laravel 应用程序构建高效且 SEO 友好的多语言架构
4 步安装
步骤 1:安装包
通过执行命令将包添加到您的 composer.json 中。
composer require dimsav/laravel-translatable
接下来,将服务提供者添加到 app/config/app.php
Dimsav\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:模型
- 可翻译模型
Country
应该使用 特质Dimsav\Translatable\Translatable
。 - 翻译模型的约定是
CountryTranslation
。
// models/Country.php class Country extends Eloquent { use \Dimsav\Translatable\Translatable; public $translatedAttributes = ['name']; protected $fillable = ['code']; /** * The relations to eager load on every query. * * @var array */ // (optionaly) // protected $with = ['translations']; } // models/CountryTranslation.php class CountryTranslation extends Eloquent { public $timestamps = false; protected $fillable = ['name']; }
数组 $translatedAttributes
包含了在 "Translation" 模型中翻译的字段名称。
步骤 4:配置
我们将配置文件复制到我们的项目中。
Laravel 5.*
php artisan vendor:publish --tag=translatable
Laravel 4.*
php artisan config:publish dimsav/laravel-translatable
注意:对本地化格式的格式没有限制。请随意使用您认为更好的格式,例如使用“eng”而不是“en”,或使用“el”而不是“gr”。重要的是要定义您的本地化并坚持使用。
配置
配置文件
您可以在配置文件中查看进一步定制的选项。
翻译模型
定义翻译模型类时使用的约定是附加关键字Translation
。
因此,如果您的模型是\MyApp\Models\Country
,则默认翻译为\MyApp\Models\CountryTranslation
。
要使用自定义类作为翻译模型,请将包含命名空间的自定义类(作为参数)定义为翻译类。例如
<?php namespace MyApp\Models; use Dimsav\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 default 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 default locale. // So in this case, french. If no french translation is found, it returns null. $translation = $germany->translate(); // It is possible to define a default locale per model by overriding the model constructor. public function __construct(array $attributes = []) { parent::__construct($attributes); $this->defaultLocale = 'de'; } // It is also possible to define a default locale for our model on the fly: $germany->setDefaultLocale('de'); // 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 default 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); // To set the translation for a field you can either update the translation model. // Saving the model will also save all the related translations. $germany->translate('en')->name = 'Germany'; $germany->save(); // Alternatively we can use the shortcut $germany->{'name:en'} = 'Germany'; $germany->save(); // There are two ways of inserting mutliple translations into the database // First, using the locale as array key. $greece = $country->fill([ 'en' => ['name' => 'Greece'], 'fr' => ['name' => 'Grèce'], ]); // The second way is to use the following syntax. $greece = $country->fill([ 'name:en' => 'Greece', 'name:fr' => 'Grèce', ]); // 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(); // Remove all translations linked to an object $germany->deleteTranslations(); // Delete one or multiple translations $germany->deleteTranslations('de'); $germany->deleteTranslations(['de', 'en']); // Gel all the translations as array $germany->getTranslationsArray(); // Returns [ 'en' => ['name' => 'Germany'], 'de' => ['name' => 'Deutschland'], 'fr' => ['name' => 'Allemagne'], ]; // Creates a clone and clones the translations $replicate = $germany->replicateWithTranslations();
可用作用域
// 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 value, only in the specified locale Country::whereTranslation('name', 'Greece', 'en')->first(); // Or where translation Country::whereTranslation('name', 'Greece')->orWhereTranslation('name', 'France')->get(); // Filters countries by checking the translation against the given string with wildcards Country::whereTranslationLike('name', '%Gree%')->first(); // Or where translation like Country::whereTranslationLike('name', '%eece%')->orWhereTranslationLike('name', '%ance%')->get();
魔法属性
要使用魔法属性,您必须在主模型中定义属性$translatedAttributes
。
class Country extends Eloquent { use \Dimsav\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; }
按属性回退
尽管我们尽量使所有模型都得到很好的翻译,但某些字段可能会被留空。结果是什么?您会发现这些字段缺少翻译!
属性回退功能就是为了帮助这种情况。启用此功能后,可翻译将返回回退语言的空属性值。
此功能在新的安装中默认启用。如果您的配置文件在v7.1之前设置,请确保添加以下行以启用此功能
'use_property_fallback' => true,
当然,必须启用回退本地化才能使用此功能。
如果配置中启用了属性回退,则可翻译将返回回退本地化的翻译,用于翻译为空的字段。
自定义空翻译属性检测
此包旨在翻译字符串,但通常它也能翻译数字、布尔值或您想翻译的任何内容。默认情况下,使用简单的empty()
调用检测翻译值是否为空。如果您想自定义此操作或为每个属性使用不同的逻辑,您可以在主模型中覆盖isEmptyTranslatableAttribute()
。
protected function isEmptyTranslatableAttribute(string $key, $value): bool { switch($key) { case 'name': return empty($value); case 'price': return !is_number($value); default: return is_null($value); } }
基于国家的回退
从版本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
的翻译作为回退。可翻译将使用es
(es-MX
的第一部分)作为回退,并且只有在没有找到任何内容时,才会返回en
的翻译。
翻译自动加载
如果调用toArray()
方法,则可以自动加载所有翻译。为了控制此功能,该包提供了一个配置值to_array_always_loads_translations
和特例中的三个静态方法
enableAutoloadTranslations()
- 强制加载所有翻译disableAutoloadTranslations()
- 禁用自动加载并返回父属性defaultAutoloadTranslations()
- 不更改默认行为逻辑(默认)
附加组件
多亏了社区,一些包被编写出来,以便在处理表单时更容易使用可翻译
常见问题解答
我需要一些示例代码!
我需要帮助!
有任何问题或建议?请随意打开一个问题。
我想帮助!
你很棒!关注仓库并回复问题。你将帮助为包的用户提供出色的体验。#communityWorks
此外,通过捐赠给我一杯啤酒。❤️
我遇到了与其他特例方法冲突的情况!
可翻译与所有类型的Eloquent扩展完全兼容,包括Ardent。如果您需要帮助将这些扩展与可翻译一起实现,请参阅此示例。
我如何将现有的表迁移到使用laravel-translatable?
请参阅安装步骤以了解您的数据库应该如何构建。
如果您的属性是用英文编写的,我们建议在迁移中使用以下命令
// We insert the translation attributes into the fresh translated table: \DB::statement("insert into country_translations (country_id, name, locale) select id, name, 'en' from countries"); // We drop the translation attributes in our main table: Schema::table('countries', function ($table) { $table->dropColumn('name'); });
我如何根据翻译进行排序?
这里的一个提示是首先执行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', function ($join) { $join->on('countries.id', '=', 't.country_id') ->where('t.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 版本。并且务必确保开发和生产环境中使用相同的版本!
捐赠
这款软件是经过精心制作的。
通过向以下地址发送比特币来表达你的爱和支持:167QC4XQ3acgbwVYWAdmS81jARCcVTWBXU
或者通过以下 PayPal 地址发送:ds@dimsav.com
❤️ 感谢!