laravel-translatable

repository·main·Indexed 25 days ago

https://github.com/spatie/laravel-translatable

A Laravel package that provides the HasTranslations trait to make Eloquent models translatable using JSON columns. It allows for managing translations via setTranslation and getTranslation methods, supports nested JSON keys, and provides scoped query builders like whereLocale and whereJsonContainsLocale to filter records by locale and value without requiring extra translation tables.

Tokens
8.4K
Snippets
27
Records
47
Agent score
81%

What's inside spatie/laravel-translatable

  1. Define translatable attributes

    main

    You have two ways to declare translatable columns:

    1. Using the #[Translatable] attribute: This is the modern approach. It accepts a variadic list of column names.

    2. Using the $translatable property: A public array of column names.

    If both are used, the values are merged and deduplicated.

    // Option 1: Attribute
    #[Translatable('name', 'description')]
    class NewsItem extends Model
    {
        use HasTranslations;
    }
    
    // Option 2: Property
    class NewsItem extends Model
    {
        use HasTranslations;
    
        public $translatable = ['name'];
    }
  2. Configure fallback behavior

    main

    By default, getTranslation() falls back to config('app.fallback_locale'). You can customize this behavior per model:

    1. Disable fallback: Set public $useFallbackLocale = false; on the model.
    2. Custom fallback locale: Implement the getFallbackLocale(): ?string method on the model.
    class NewsItem extends Model
    {
        use HasTranslations;
    
        public $useFallbackLocale = false; // disable fallback for this model
    
        public function getFallbackLocale(): ?string
        {
            return 'en'; // custom fallback
        }
    }
  3. Make Eloquent models translatable

    main

    To make an Eloquent model translatable, use the HasTranslations trait. Translations are stored as JSON within the existing database columns, so no additional tables are required. You can define which attributes are translatable using either a PHP Attribute or a public $translatable property.

    use Illuminate\Database\
    use Spatie\Translatable\Attributes\Translatable;
    use Spatie\Translatable\HasTranslations;
    
    #[Translatable('name', 'description')]
    class NewsItem extends Model
    {
        use HasTranslations;
    
        // ...
    }
  4. Make a model translatable

    main

    To enable translation support on an Eloquent model, follow these three steps:

    1. Add the Spatie\Translatable\HasTranslations trait to your model.
    2. Declare which attributes are translatable using either the #[Translatable] PHP attribute or the public $translatable array property.
    3. Ensure the corresponding database columns use the json data type. If your database does not support json columns, use text instead.

    Using the #[Translatable] attribute

    You can use the #[Translatable] attribute on the class. It accepts a variadic list of column names.

    Using the $translatable property

    Alternatively, you can define a public $translatable array property on the model.

    Note: If you use both the attribute and the property, the values will be merged and deduplicated.

    use Illuminate\Database\Eloquent\Model;
    use Spatie\Translatable\Attributes\Translatable;
    use Spatie\Translatable\HasTranslations;
    
    #[Translatable('name', 'description')]
    class NewsItem extends Model
    {
        use HasTranslations;
    }
  5. Customize the toArray method for translatable attributes

    main

    By default, when a model is serialized via toArray(), translatable attributes are returned as JSON strings (the raw database format). If you want toArray() to return the translation for the current locale instead of the JSON object, you can create a custom trait that wraps Spatie\Translatable\HasTranslations and overrides the toArray() method.

    This approach ensures that whenever the model is converted to an array (e.g., when returning a model from a controller in an API response), the translatable fields are automatically populated with the value for the current application locale.

    namespace App\
    Traits;
    use Spatie\Translatable\HasTranslations as BaseHasTranslations;
    
    trait HasTranslations
    {
        use BaseHasTranslations;
    
        public function toArray()
        {
            $attributes = $this->attributesToArray(); // attributes selected by the query
            // remove attributes if they are not selected
            $translatables = array_filter($this->getTranslatableAttributes(), function ($key) use ($attributes) {
                return array_key_exists($key, $attributes);
            });
            foreach ($translatables as $field) {
                $attributes[$field] = $this->getTranslation($field, \App::getLocale());
            }
            return array_merge($attributes, $this->relationsToArray());
        }
    }
  6. Upgrade from v5 to v6: Configure fallback behavior

    main
    In version 6, the dedicated configuration file has been removed. Instead of using a config file, you must now define your fallback locale and behavior using the Translatable::fallback() method. This allows you to set a fallback locale, enable fallBackAny, and handle custom behavior for missing translations programmatically.
  7. Configure global fallback locales

    main

    To handle cases where a requested translation is missing, you can configure fallback behavior using the Spatie\Translatable\Facades\Translatable facade. This is typically done within a Service Provider.

    By default, the package uses the application's fallback locale defined in config/app.php. You can override this globally by passing a specific locale to the fallback() method.

    use Spatie\Translatable\Facades\Translatable;
    
    Translatable::fallback(
        fallbackLocale: 'fr',
    );
  8. Validate attribute uniqueness for translations

    main
    The core laravel-translatable package does not include built-in validation for ensuring translated attributes are unique across the database. If you need to validate an attribute for uniqueness before saving or updating the database, use the companion package laravel-unique-translation, which is specifically designed to work with laravel-translatable.
  9. Set translations for a model attribute

    main

    You can set translations for a translatable attribute using several methods:

    1. Current Locale: Assign a string directly to the attribute. This sets the translation for the application's current locale.
    2. Bulk Creation: Pass an associative array of locales and values when calling create().
    3. Specific Locale: Use the setTranslation method to target a specific language.
    4. Multiple Locales: Assign an associative array to the attribute or use the setTranslations method to update multiple languages at once.

    Note: Always call save() on the model to persist changes to the database.

    // Set for current locale
    $newsItem->name = 'New translation';
    $newsItem->save();
    
    // Set during creation
    NewsItem::create([
       'name' => [
          'en' => 'Name in English',
          'nl' => 'Naam in het Nederlands'
       ],
    ]);
    
    // Set for a specific locale
    $newsItem->setTranslation('name', 'en', 'English Name');
    
    // Set multiple locales at once
    $translations = ['en' => 'hello', 'es' => 'hola'];
    $newsItem->setTranslations('name', $translations);
    $newsItem->save();