Description
This package contains a trait to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them.
This package contains a trait HasTranslations to make Eloquent models translatable. Translations are stored as json. There is no extra table needed to hold them.
use Illuminate\Database\Eloquent\Model;use Spatie\Translatable\Attributes\Translatable;use Spatie\Translatable\HasTranslations; #[Translatable('name', 'description')]class NewsItem extends Model{ use HasTranslations; // ...}
The attribute accepts a variadic list of column names, so you can pass as many as you need.
Alternatively, you can declare the translatable attributes via a public $translatable property:
use Illuminate\Database\Eloquent\Model;use Spatie\Translatable\HasTranslations; class NewsItem extends Model{ use HasTranslations; public $translatable = ['name'];}
When both the property and the attribute are present, their values are merged and deduplicated.
After the trait is applied on the model you can do these things:
$newsItem = new NewsItem;$newsItem ->setTranslation('name', 'en', 'Name in English') ->setTranslation('name', 'nl', 'Naam in het Nederlands') ->save(); $newsItem->name; // Returns 'Name in English' given that the current app locale is 'en'$newsItem->getTranslation('name', 'nl'); // returns 'Naam in het Nederlands' app()->setLocale('nl');$newsItem->name; // Returns 'Naam in het Nederlands' $newsItem->getTranslations('name'); // returns an array of all name translations // You can translate nested keys of a JSON column using the -> notation// First, add the path to the $translatable array, e.g., 'meta->description'$newsItem ->setTranslation('meta->description', 'en', 'Description in English') ->setTranslation('meta->description', 'nl', 'Beschrijving in het Nederlands') ->save(); $attributeKey = 'meta->description';$newsItem->$attributeKey; // Returns 'Description in English'$newsItem->getTranslation('meta->description', 'nl'); // Returns 'Beschrijving in het Nederlands'
Also providing scoped queries for retrieving records based on locales
// Returns all news items with a name in EnglishNewsItem::whereLocale('name', 'en')->get(); // Returns all news items with a name in English or DutchNewsItem::whereLocales('name', ['en', 'nl'])->get(); // Returns all news items that has name in English with value `Name in English`NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in English')->get(); // Returns all news items that has name in English or Dutch with value `Name in English`NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in English')->get(); // The last argument is the "operand" which you can tweak to achieve something like this: // Returns all news items that has name in English with value like `Name in...`NewsItem::query()->whereJsonContainsLocale('name', 'en', 'Name in%', 'like')->get(); // Returns all news items that has name in English or Dutch with value like `Name in...`NewsItem::query()->whereJsonContainsLocales('name', ['en', 'nl'], 'Name in%', 'like')->get();
Related Content on Laravel Daily
Video
Video
Recent Courses on Laravel Daily
AI Agents/IDEs for Laravel: May 2026 (Claude Code, Codex, OpenCode, etc)
7 lessons
52 min
Laravel 13 Eloquent: Expert Level
41 lessons
1 h 34 min
How to Build Laravel 13 API From Scratch
30 lessons
1 h 23 min