rat.md / laravel-translatable
Awesome translatable Laravel Eloquent models (for MySQL, MariaDB, PostgreSQL, SQLite & MongoDB).
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- mongodb/laravel-mongodb: ^5.0
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
Suggests
- mongodb/laravel-mongodb: Required to use MongoDB as database driver.
Provides
None
Conflicts
None
Replaces
None
README
Version 0.1.4 (Beta)
- Fix: Reuse eager-loaded translations to avoid N+1 queries and invalidate stale translations after writes or removals.
Most Laravel “translatable” packages force you to either convert your translatable attributes into a
JSON column on the same table (for storing all strings on one place), or requires you to create and
maintain a dedicated {model}_translations table for each model.
Both approaches work, but they either bloat your base table with JSON logic or force you to manage a growing number of nearly identical tables.
rat.md/laravel-translatable takes a different path — inspired by OctoberCMS — by using a
single, shared translations table for all your models.
Features
- Support for MySQL, MariaDB, PostgreSQL, SQlite and MongoDB (Driver-aware querying and sorting).
- One polymorphic translations table for everything — no extra migrations per model.
- Keep your default language clean in the model’s own columns, exactly where it belongs.
- Transparent reads and writes through the model’s attributes, with automatic fallback.
Requirements
- PHP ≥ 8.2
- Laravel ≥ 11
- SQLite ≥ 3.35 | MySQL ≥ 8.0 | MariaDB ≥ 10.6 | PostgreSQL ≥ 13.22
- Only required for MongoDB driver (experimental):
- MongoDB ≥ v7.0 (may work with ≥ v5.0 too)
- mongodb/laravel-mongodb ≥ 5.0
Installation
Install the package via composer:
composer require rat.md/laravel-translatable
Publish and run the migrations using:
php artisan vendor:publish --tag="laravel-translatable-migrations"
php artisan migrate
Publish the configuration file with:
php artisan vendor:publish --tag="laravel-translatable-config"
Usage
Preparing your models
Simply add the Translatable trait to your Eloquent models and declare which attributes should
support translations. Array-Like attributes must be declared either in your $casts or in the
package-native $translatableArrayAttributes model property.
use Rat\Translatable\Concerns\Translatable; class Post extends Model { use Translatable; protected $fillable = ['title', 'content', 'tags']; protected $translatable = ['title', 'content', 'tags']; protected $casts = [ 'tags' => 'array' ]; }
Setting translations
Set translations in known / familiar ways.
// Mass assignment Post::create([ 'title' => [ 'en' => 'Hello World', 'de' => 'Hallo Welt', ] ]); // Manual assignment $post = new Post; $post->title = 'Hello World'; $post->setTranslation('de', 'title', 'Hallo Welt'); $post->save(); // Manual assignment using withLocale() $post = new Post; $post->title = 'Hello World'; $post->withLocale('de', function ($model) { $model->title = 'Hallo Welt'; });
Retrieving translations
Access translations directly, use helpers, or switch the application/model locale.
$post = Post::first(); // Direct access based on app()->getLocale() echo $post->title; app()->setLocale('de'); echo $post->title; // Manual access echo $post->getTranslation('de', 'title'); echo $post->getTranslations('de')['title']; // Access by mutating model locale $post->locale('de'); echo $post->title; // Access by cloning model with desired locale echo $post->in('de')->title; // Access by using withLocale() $post->withLocale('de', function ($model) { echo $model->title; });
Eager loading translations
Load translations together with model collections to avoid one additional query per model:
$posts = Post::with('translations')->get(); foreach ($posts as $post) { echo $post->in('de')->title; }
A loaded relation is authoritative: a missing locale falls back to the model's base value without another query. When constraining the relation to specific locales, include every locale you intend to read. Saving or removing translations invalidates the loaded relation.
Querying by locale
Query, filter, and sort your models by translated values across different locales.
Note
orderByLocale() is not yet supported for the MongoDB driver. We are actively exploring a clean
and efficient implementation. For now, this scope works only with SQL drivers.
Post::whereLocale('de', 'title', 'Hallo Welt')->get(); Post::query()->whereLocale('de', 'title', 'Hallo Welt')->get(); Post::whereHasLocale('de')->get(); Post::whereMissingLocale('de')->get(); // or "whereDoesntHaveLocale" Post::orderByLocale('de', 'title', 'ASC')->get();
Testing
./vendor/bin/pest
Changelog
Please see CHANGELOG for more information on what has changed recently.
License
Published under MIT License
Copyright © 2024 - 2025 Sam @ rat.md