laravel dimsav/laravel-translatable

石俊雄
2023-12-01

Step 1: Install package

Add the package in your composer.json by executing the command.

composer require dimsav/laravel-translatable

Next, add the service provider to app/config/app.php

Dimsav\Translatable\TranslatableServiceProvider::class,

Step 2: Migrations

In this example, we want to translate the model Country. We will need an extra table 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');
});

Step 3: Models

  1. The translatable model Country should use the trait Dimsav\Translatable\Translatable.
  2. The convention for the translation model is 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'];

}

The array $translatedAttributes contains the names of the fields being translated in the "Translation" model.

Step 4: Configuration

Laravel 4.*

php artisan config:publish dimsav/laravel-translatable

Laravel 5.*

php artisan vendor:publish

With this command, initialize the configuration and modify the created file, located under app/config/packages/dimsav/laravel-translatable/translatable.php.

Note: There isn't any restriction for the format of the locales. Feel free to use whatever suits you better, like "eng" instead of "en", or "el" instead of "gr". The important is to define your locales and stick to them.

Configuration

The translation model

The convention used to define the class of the translation model is to append the keyword Translation.

So if your model is \MyApp\Models\Country, the default translation would be \MyApp\Models\CountryTranslation.

To use a custom class as translation model, define the translation class (including the namespace) as parameter. For example:

<?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';
}

Features list

Please read the installation steps first, to understand what classes need to be created.

Available methods

// 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();

// Remove all translations linked to an object
$germany->deleteTranslations();

// Delete one or multiple translations
$germany->deleteTranslations('de');
$germany->deleteTranslations(['de', 'en']);

Available scopes

// 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();

Magic properties

To use the magic properties, you have to define the property $translatedAttributes in your main model:

 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'

Fallback locales

If you want to fallback to a default translation when a translation has not been found, enable this in the configuration using the use_fallback key. And to select the default locale, use the fallback_locale key.

Configuration example:

return [
    'use_fallback' => true,

    'fallback_locale' => 'en',    
];

You can also define per-model the default for "if fallback should be used", by setting the $useTranslationFallback property:

class Country {

    public $useTranslationFallback = true;

}

Country based fallback

Since version v5.3 it is possible to use country based locales. For example, you can have the following locales:

  • English: en
  • Spanish: es
  • Mexican Spanish: es-MX
  • Colombian Spanish: es-CO

To configuration for these locales looks like this:

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

We can also configure the "glue" between the language and country. If for instance we prefer the format es_MX instead of es-MX, the configuration should look like this:

   'locale_separator' => '_',

What applies for the fallback of the locales using the en-MX format?

Let's say our fallback locale is en. Now, when we try to fetch from the database the translation for the locale es-MX but it doesn't exist, we won't get as fallback the translation for en. Translatable will use as a fallback es (the first part of es-MX) and only if nothing is found, the translation for en is returned

 类似资料: