Skip to content

Model Attributes Translation

The Laravel Translations package provides powerful functionality to automatically translate Eloquent model attributes. This feature allows you to store content in one language and automatically generate translations for other languages.

Overview

Model attribute translation works by:

  1. Detecting changes to translatable attributes
  2. Queuing translation jobs automatically
  3. Storing translations in a separate table
  4. Retrieving translations based on current locale

Setup

1. Configure Translatable Models

Add your models to the configuration:

php
// config/translations.php
'eloquent' => [
    'translatable-models' => [
        App\Models\Post::class,
        App\Models\Product::class,
        App\Models\Category::class,
    ],
],

2. Implement the Contract and Use the Trait

Your model must implement the TranslatesAttributes contract AND use the HasTranslatableAttributes trait:

php
<?php

namespace App\Models;

use Backstage\Translations\Laravel\Contracts\TranslatesAttributes;
use Backstage\Translations\Laravel\Models\Concerns\HasTranslatableAttributes;
use Illuminate\Database\Eloquent\Model;

class Post extends Model implements TranslatesAttributes
{
    use HasTranslatableAttributes; // Required trait for translatable attributes

    protected $fillable = [
        'title',
        'content',
        'excerpt',
        'meta_description',
    ];

    // Define which attributes should be translated
    public function getTranslatableAttributes(): array
    {
        return [
            'title',
            'content',
            'excerpt',
            'meta_description',
        ];
    }

    // Define casts for translatable attributes
    protected $casts = [
        'title' => 'string',
        'content' => 'string',
        'excerpt' => 'string',
        'meta_description' => 'string',
    ];
}

3. Database Migration

The package creates a translated_attributes table to store translations:

php
// Migration: create_translated_attributes_table.php
Schema::create('translated_attributes', function (Blueprint $table) {
    $table->id();
    $table->string('code'); // Language code
    $table->morphs('translatable'); // Polymorphic relationship
    $table->string('attribute'); // Attribute name
    $table->text('translated_attribute'); // Translated value
    $table->timestamp('translated_at')->nullable();
    $table->timestamps();
    $table->softDeletes();
});

Basic Usage

Creating and Updating Models

When you create or update a model with translatable attributes, translations are automatically queued:

php
// Create a new post
$post = Post::create([
    'title' => 'Hello World',
    'content' => 'This is my first post',
    'excerpt' => 'A short description',
]);

// Translations are automatically queued for all active languages
// No additional code needed!

Retrieving Translations

Get translated attributes for the current locale:

php
$post = Post::find(1);

// Get translated title for current locale
$title = $post->getTranslatedAttribute('title');

// Get translated title for specific locale
$spanishTitle = $post->getTranslatedAttribute('title', 'es');

// Get all translated attributes for current locale
$translations = $post->getTranslatedAttributes();

// Get all translated attributes for specific locale
$spanishTranslations = $post->getTranslatedAttributes('es');

Manual Translation

Translate attributes manually:

php
$post = Post::find(1);

// Translate single attribute
$translatedTitle = $post->translateAttribute('title', 'es');

// Translate all attributes for specific language
$translations = $post->translateAttributes('es');

// Translate all attributes for all languages
$allTranslations = $post->translateAttributesForAllLanguages();

Advanced Features

Overwriting Existing Translations

Force translation of existing content:

php
$post = Post::find(1);

// Overwrite existing Spanish translation
$post->translateAttribute('title', 'es', overwrite: true);

// Overwrite all translations for this attribute
$post->translateAttributeForAllLanguages('title', overwrite: true);

Custom Translation Prompts

Add custom context for better translations:

php
$post = Post::find(1);

// Translate with custom prompt
$translatedTitle = $post->translateAttribute(
    'title', 
    'es', 
    overwrite: false,
    extraPrompt: 'This is a blog post title about technology'
);

Pushing Manual Translations

Store translations manually:

php
$post = Post::find(1);

// Store a manual translation
$post->pushTranslateAttribute('title', 'Hola Mundo', 'es');

// This bypasses automatic translation

Synchronization

Automatic Sync

The package automatically syncs translations when:

  • A model is created
  • Translatable attributes are updated
  • Languages are added or removed

Manual Sync

Force synchronization:

php
$post = Post::find(1);

// Sync all translations for this model
$post->syncTranslations();

// Sync with progress output
$post->syncTranslations($output);

Bulk Sync

Sync all models at once:

bash
php artisan translations:sync

Working with Relationships

Eager Loading Translations

Load translations efficiently:

php
// Load posts with their translations
$posts = Post::with('translatableAttributes')->get();

// Load specific language translations
$posts = Post::with(['translatableAttributes' => function ($query) {
    $query->where('code', 'es');
}])->get();

Translation Relationships

Access translation relationships:

php
$post = Post::find(1);

// Get all translations for this post
$translations = $post->translatableAttributes;

// Get translations for specific language
$spanishTranslations = $post->translatableAttributes()
    ->where('code', 'es')
    ->get();

// Get translations for specific attribute
$titleTranslations = $post->translatableAttributes()
    ->where('attribute', 'title')
    ->get();

Performance Optimization

Caching

Enable caching for better performance:

php
// config/translations.php
'use_permanent_cache' => true,

Queued Operations

Translation operations are automatically queued:

php
// This happens in the background
$post->translateAttributes('es');

Batch Operations

Process multiple models efficiently:

php
// Translate multiple posts at once
$posts = Post::where('created_at', '>', now()->subDay())->get();

foreach ($posts as $post) {
    $post->translateAttributesForAllLanguages();
}

Best Practices

Choose Translatable Attributes Wisely

Only translate attributes that need translation:

php
public function getTranslatableAttributes(): array
{
    return [
        'title',           // ✅ User-facing content
        'content',         // ✅ User-facing content
        'excerpt',         // ✅ User-facing content
        // 'id',           // ❌ System data
        // 'created_at',   // ❌ System data
        // 'user_id',      // ❌ System data
    ];
}

Use Appropriate Casts

Define proper casts for translatable attributes:

php
protected $casts = [
    'title' => 'string',
    'content' => 'string',
    'excerpt' => 'string',
    'meta_data' => 'array', // If storing JSON
];

Troubleshooting

Common Issues

Translations not created: Check that the model is registered in config AND uses the HasTranslatableAttributes trait

Missing translations: Run translations:sync to fill missing translations

Performance issues: Enable caching and use queued operations

Translation errors: Check your translation provider configuration

Model not implementing contract: Ensure your model implements TranslatesAttributes and uses HasTranslatableAttributes trait

Debugging

Check translation status:

php
$post = Post::find(1);

// Check if attribute is translatable
$isTranslatable = $post->isTranslatableAttribute('title');

// Get translation status
$translations = $post->translatableAttributes;
foreach ($translations as $translation) {
    echo "{$translation->attribute}: {$translation->code} - {$translation->translated_at}";
}

Next Steps