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:
- Detecting changes to translatable attributes
- Queuing translation jobs automatically
- Storing translations in a separate table
- Retrieving translations based on current locale
Setup
1. Configure Translatable Models
Add your models to the configuration:
// 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
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:
// 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:
// 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:
$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:
$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:
$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:
$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:
$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:
$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:
php artisan translations:sync
Working with Relationships
Eager Loading Translations
Load translations efficiently:
// 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:
$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:
// config/translations.php
'use_permanent_cache' => true,
Queued Operations
Translation operations are automatically queued:
// This happens in the background
$post->translateAttributes('es');
Batch Operations
Process multiple models efficiently:
// 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:
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:
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:
$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
- Commands - Complete command reference
- Advanced Usage - Advanced features and customization