Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Translatable Laravel Package

fevrok/laravel-translatable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to Begin

  1. Installation

    composer require fevrok/laravel-translatable
    

    For Laravel <5.5, add the service provider to config/app.php:

    Fevrok\Translatable\TranslatableServiceProvider::class,
    
  2. Publish Config & Migrations

    php artisan vendor:publish --provider="Fevrok\Translatable\TranslatableServiceProvider"
    php artisan migrate
    
  3. Configure Defaults Update config/translatable.php:

    'enabled' => true,
    'locale' => 'en', // Default language
    
  4. Make a Model Translatable Add the Translatable trait and define $translatable fields:

    use Fevrok\Translatable\Translatable;
    
    class Product extends Model
    {
        use Translatable;
    
        protected $translatable = ['name', 'description'];
    }
    

First Use Case: Basic Translation

// Create a translatable record
$product = Product::create([
    'name' => 'Base Name',
    'description' => 'Base Description',
]);

// Set translations
$product->setTranslation('name', 'es', 'Nombre Traducido');
$product->setTranslation('description', 'es', 'Descripción Traducida');

// Retrieve translations
$esName = $product->getTranslation('name', 'es'); // 'Nombre Traducido'

Implementation Patterns

Common Workflows

1. Dynamic Field Translation

Use setTranslation() and getTranslation() for runtime translations:

// In a controller or service
$product->setTranslation('name', request('locale'), request('translated_name'));

2. Mass Assignment with Translations

Override $fillable to include translatable fields:

protected $fillable = ['name', 'description'];
protected $translatable = ['name', 'description'];

// Mass assign with translations
Product::create([
    'name' => 'Base',
    'description' => 'Base Desc',
    'translations' => [
        'name' => ['es' => 'Español'],
        'description' => ['es' => 'Descripción']
    ]
]);

3. Scopes for Localized Queries

Filter records by translation:

// In a model scope
public function scopeInLanguage($query, $locale)
{
    return $query->whereHas('translations', function($q) use ($locale) {
        $q->where('locale', $locale);
    });
}

// Usage
Product::inLanguage('es')->get();

4. API Responses with Translations

Use accessors to format translations in responses:

public function getTranslatedNameAttribute()
{
    return $this->getTranslation('name', app()->getLocale());
}

5. Form Request Validation

Validate translations in a FormRequest:

public function rules()
{
    return [
        'name_en' => 'required|string',
        'description_es' => 'required|string',
    ];
}

public function prepareForValidation()
{
    $this->merge([
        'name_en' => $this->input('name.translations.en'),
        'description_es' => $this->input('description.translations.es'),
    ]);
}

Integration Tips

Laravel Scout (Search)

Extend search to include translations:

use Laravel\Scout\Searchable;

class Product extends Model
{
    use Translatable, Searchable;

    public function toSearchableArray()
    {
        return [
            'name' => $this->getTranslation('name', app()->getLocale()),
            'description' => $this->getTranslation('description', app()->getLocale()),
        ];
    }
}

Laravel Nova (Admin Panel)

Customize Nova fields for translations:

use Laravel\Nova\Fields\Text;

Text::make('Name Translation', 'name_translations')
    ->onlyOnDetail()
    ->asFunctionOf(function ($value) {
        return $value->getTranslation('name', 'es');
    });

Eloquent Relationships

Translate related models:

class Category extends Model
{
    use Translatable;

    protected $translatable = ['title'];

    public function products()
    {
        return $this->hasMany(Product::class);
    }
}

// Access translated category title
$product->category->getTranslation('title', 'fr');

Gotchas and Tips

Pitfalls

  1. Missing Migrations

    • Forgetting to run php artisan migrate after publishing will break translation storage.
    • Fix: Always run migrations post-installation.
  2. Locale Mismatch

    • Translations may silently fail if the locale column in the translations table doesn’t match config/translatable.php.
    • Fix: Ensure locale in config matches your app’s default and user-selected locales.
  3. Mass Assignment Risks

    • Translatable fields aren’t automatically added to $fillable. Explicitly include them or use merge():
      $product->merge([
          'translations' => [
              'name' => ['es' => 'Nombre']
          ]
      ]);
      
  4. Caching Issues

    • Translations aren’t cached by default. Use fresh() or freshTimestamp() if translations aren’t updating:
      $product = Product::find(1)->fresh();
      
  5. Overwriting Translations

    • setTranslation() overwrites existing translations for the same field/locale. Use pushTranslation() (if available) for appending.

Debugging Tips

  1. Check the translations Table Verify translations are stored:

    SELECT * FROM translations WHERE translatable_id = 1;
    
  2. Log Translation Calls Temporarily add logging to the trait:

    trait Translatable {
        public function setTranslation($field, $locale, $value)
        {
            \Log::debug("Setting {$field} to {$value} for locale {$locale}");
            // ... rest of the method
        }
    }
    
  3. Validate Config Ensure config/translatable.php has:

    'enabled' => true,
    'locale' => 'en', // Must match your app's default locale
    

Extension Points

  1. Custom Translation Storage Override the getTranslationsTable() method in your model:

    public function getTranslationsTable()
    {
        return 'custom_translations';
    }
    
  2. Add Translation Events Listen for translation changes:

    use Fevrok\Translatable\Events\TranslationSaved;
    
    TranslationSaved::listen(function ($model, $field, $locale, $value) {
        \Log::info("Translation updated: {$field} ({$locale}) = {$value}");
    });
    
  3. Dynamic Locale Handling Extend the trait to support runtime locale switching:

    public function setCurrentLocale($locale)
    {
        $this->currentLocale = $locale;
    }
    
    public function getTranslation($field, $locale = null)
    {
        $locale = $locale ?: $this->currentLocale;
        // ... rest of the method
    }
    
  4. Fallback Locales Implement fallback logic in getTranslation():

    public function getTranslation($field, $locale)
    {
        $translation = $this->translations->firstWhere('field', $field)->where('locale', $locale);
        if (!$translation) {
            $translation = $this->translations->firstWhere('field', $field)->where('locale', config('translatable.fallback_locale'));
        }
        return $translation ? $translation->value : null;
    }
    
  5. API Resource Formatting Create a custom resource for translations:

    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->getTranslation('name', $request->locale),
            'description' => $this->getTranslation('description', $request->locale),
        ];
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware