The 0.2.0 release adds first-class support for dimsav/laravel-translatable, so any package feature that reads or writes Eloquent attributes can now work against translated attributes instead of the base table columns.
composer require dimsav/laravel-translatable
*_translations table, a Translatable trait on the model, and a $translatedAttributes array:class Post extends Model
{
use \Dimsav\Translatable\Translatable;
public $translatedAttributes = ['title', 'body'];
}
class PostTranslation extends Model
{
public $timestamps = false;
protected $fillable = ['title', 'body'];
}
Point the package's configuration at the attributes you want translated (config key / field mapping depends on the package's own config file — publish it first with php artisan vendor:publish and look for the attribute-mapping section).
First use case: take an existing form or API resource that writes title and switch it to write through the translation relation, then verify with app()->setLocale('fr') that reads return the French value.
Where to look first: the package's config file and the changelog entry for 0.2.0, then your model's translations() relation. If the package exposes a field/column resolver, that resolver is the integration seam.
Read/write through the current locale. The translatable trait handles locale resolution transparently, so package code that does $model->title will now resolve per app()->getLocale(). Keep your controllers locale-agnostic and set the locale once per request (middleware is the right place):
public function handle($request, Closure $next)
{
app()->setLocale($request->user()->locale ?? config('app.locale'));
return $next($request);
}
Explicit locale writes. When populating translations from an import, a queue job, or a multi-language admin form, don't rely on the active locale — use the trait's explicit API:
$post->translateOrNew('en')->title = $payload['title_en'];
$post->translateOrNew('fr')->title = $payload['title_fr'];
$post->save();
Eager loading to avoid N+1. Any listing endpoint that renders translated attributes should eager load the relation, otherwise every row triggers a translation query. Use withTranslation() or translated() where the package supports it; otherwise with('translations').
Filtering and sorting. Base-table queries can't see translated columns. Route search through the relation, e.g. whereTranslation('title', $term, $locale), or join the translations table explicitly. Sorting on a translated column needs the same treatment — plan for it before it becomes a bug report.
Integration tips for the 0.2.0 support:
title.en and title.fr should be distinct.DB::transaction() since the trait persists the parent row and translations as separate statements.dimsav/laravel-translatable is archived. The package was succeeded by astrotomic/laravel-translatable. 0.2.0's support targets the dimsav namespace, so you're pinning to an unmaintained dependency. Verify whether the support is duck-typed against the trait or hard-typed against Dimsav\... — if it's the latter, the astrotomic fork will not work without an alias or a shim. This is the single biggest thing to check before adopting.
Locale fallback surprises. With fallback_locale configured, a missing translation silently returns the fallback language instead of null. That's usually what you want for UI, and almost never what you want for validation ("this field is required" firing on a field that appears populated). Check $model->getTranslation($locale, false) or inspect translations directly when you need to know whether a translation truly exists.
Missing translations table rows. $model->translate('fr') returns null when no row exists for that locale — calling ->title on it fatals. Prefer translateOrNew() on write paths and null-checks on read paths.
Mass assignment. PostTranslation::$fillable is a separate concern from Post::$fillable. Forgetting to add a newly added attribute to the translation model's $fillable produces silently dropped values — no exception, just an empty column. Add a test that round-trips each translatable attribute.
Config caching. If you changed locale or attribute mappings and behavior didn't change, run php artisan config:clear. Translation bugs are frequently stale-config bugs.
Debugging. $model->translations is the ground truth — dump it before you dump the attribute. DB::listen() will show you whether the package is issuing an extra query per row, which is how you catch missing eager loads early.
Extension points. The trait's accessor pipeline (translated attribute getters) is the cleanest place to add trimming, sanitization, or markup processing so it applies per-locale rather than to whichever language happens to be active. Avoid mutating the ambient locale inside package code paths; it leaks across the request and produces "works in isolation, wrong in production" bugs.
How can I help you explore Laravel packages today?