brackets/translatable
brackets/translatable adds translation support to Laravel Eloquent models, letting you store and retrieve translatable attributes per locale without duplicating schema columns. A small, focused package for building multilingual apps on familiar Eloquent workflows.
Architecture fit
brackets/translatable follows the trait-plus-JSON-column pattern: a Translatable trait on Eloquent models, with each translatable attribute stored as a JSON object of {locale: value} in a single database column. This is a natural fit for a conventional Laravel monolith — no extra tables, no joins, no polymorphic translation records. It keeps the domain model flat and reads like normal Eloquent ($model->title, $model->translate('nl')->title). For a content-light product (marketing pages, category names, short copy) this is the lowest-friction shape available.
The trade-off is baked into the architecture: locale data is opaque to the relational layer. Anything requiring per-locale indexing, locale-scoped uniqueness, or relational integrity across translations will need generated columns or denormalization. It is also a content translation tool, not an interface localization tool — it does not replace Laravel's lang files.
Integration feasibility
Integration is genuinely small: composer require, publish the config (locale list, fallback), add the trait, cast the columns to json/array, and the API is live. A competent Laravel developer should complete a proof of concept in under a day and a first production model in two to three days including tests. The cost is not in the wiring; it is in the data migration and the decision to store translations this way permanently.
The real feasibility question is fit against alternatives the team already knows: spatie/laravel-translatable uses the same JSON-column model with orders of magnitude more adoption and active maintenance, and astrotomic/laravel-translatable uses a dedicated translations table with better query ergonomics at higher schema cost. Choosing this package over Spatie is only defensible if there is a specific behavioural difference you need — and that difference should be documented before adoption, not discovered mid-build.
Technical risk
This is the dominant concern. Eight stars, zero dependents, and a last release in October 2023 means effectively no external validation and no community safety net. The maintainer is an agency (BRACKETS by TRIAD) publishing an internal utility; there is no signal of a support commitment, and a package that has not shipped since 2023 is unlikely to have been validated against Laravel 11/12 and PHP 8.3+. Risk profile is high on two axes: abandonment (no one to fix a break) and correctness (untested edge cases in fallback logic, casting, and mass assignment go unnoticed when nobody else uses the code).
Mitigations exist — fork it, vendor it, pin it — but each converts a dependency into an owned asset, which changes the business case from "adopt a package" to "adopt a small codebase."
Key questions
composer.json, and does it install and pass tests on our target version today?spatie/laravel-translatable does not?Stack fit
Compatible with a standard Laravel + Eloquent + MySQL 5.7+/PostgreSQL stack. Requires JSON column support and a Laravel version within the package's constraint — verify this first, as it is the most likely hard blocker. No queue, cache, or service-provider complexity; it is a model-layer concern only.
Migration path
Three viable paths, in order of preference:
{default_locale: value}, then read exclusively from the JSON column and drop the old ones after a soak period.Avoid migrating an entire content estate in one release. Column-level cutover per model, behind a feature flag, keeps rollback to a config change.
Compatibility
Test explicitly on the target DB driver: JSON path operators differ between MySQL and PostgreSQL, and any whereJsonContains usage needs verification. Confirm the package's casting interacts cleanly with existing $casts, $fillable, validation rules, and API resources — translation-aware validation (required per locale) is usually the first gap a team hits.
Sequencing
Maintenance
Expect to own this. Pin the version, commit the lockfile, and assume no upstream fixes. Budget a small recurring allowance — a few hours per quarter — to verify the package against Laravel upgrades and apply patches locally. If the team cannot commit that, the honest recommendation is to use a package with a maintained community instead; the cost of a fork is small but it is not zero.
Support
No community, no issue-tracker velocity, no documented SLA. Support is whatever relationship exists with the vendor, and for an eight-star package that relationship is the deciding factor. Escalation for a production bug is internal engineering, not vendor.
Scaling
Reads are cheap: translations arrive with the row, so no joins and no N+1. This is a genuine advantage over table-per-translation designs at high read volume. Writes are fine at normal CMS throughput. The scaling cliff is querying: locale-filtered search and sorting over JSON require generated columns and indexes, which must be designed deliberately. Full-text search across locales should be handled by an external index, not by JSON operators on a large table. Caching translated content per locale is straightforward but needs locale in the cache key — a common and quiet source of cross-language bugs.
Failure modes
Ramp-up
Very low. Any Laravel developer is productive within an hour; the API surface is a trait plus a translate helper. The onboarding cost sits with the policy — which locales exist, what the fallback is, how editors enter translations, and how missing translations are surfaced — not with the code. Document those decisions in the repo before the second model adopts the trait, or locale handling will diverge team by team.
Assessment summary: technically low-cost and architecturally reasonable, but commercially unsupported and externally unvalidated. Adopt only for greenfield content types, only after a timeboxed spike against spatie/laravel-translatable, and only with explicit acceptance that the package becomes an internally owned asset.
How can I help you explore Laravel packages today?