savannabits/translatable
A Laravel package for translating Eloquent model attributes across multiple locales, letting you store and retrieve localized values with locale fallbacks. Useful for multilingual apps that need simple, flexible model translations without heavy dependencies.
This is the first standalone release of the Translatable package, versioned in lockstep with savannabits/craftable: ^7.0.0. Treat it as the translatable-model layer of the Craftable admin ecosystem rather than a general-purpose i18n library.
Minimal setup:
^7.0.0 of the Craftable meta-package, confirm your Laravel/PHP versions satisfy Craftable 7 requirements before installing in isolation. Installing this package outside a Craftable 7 project is untested territory.composer require savannabits/translatable (or as pulled in transitively by savannabits/craftable), then check for publishable config/migrations with php artisan vendor:publish. Start by reading the package's config/ and any migration stubs — that tells you whether translations live in JSON columns or a side table.HasTranslations-style trait (in src/), the service provider bindings, and the default/fallback locale config. Those three determine 90% of day-to-day behavior.Because there is no prior assessment and the release note is a single line, validate assumptions against the actual source rather than assuming Laravel-Translatable parity.
Trait-based model translation. The expected pattern is use HasTranslations on an Eloquent model, declaring a $translatable array of attributes. Store/retrieve via the model as normal; the trait intercepts attribute access per active locale.
Locale resolution. Drive the active locale from App::getLocale() and set it in middleware from the request (session, user preference, or route segment). Keep a separate fallback locale for reads so admin UIs never show blanks.
Form handling. In Craftable admin forms, render one input group per configured locale, keyed by locale code, and map them back to the translatable attribute array on save. Validate each locale's required fields explicitly rather than relying on the model.
Ecosystem integration. Since this ships as part of the Craftable 7 bundle, prefer registering it through the Craftable service provider flow and reusing Craftable's locale configuration instead of maintaining a second locale list. If you run Craftable's generators, confirm generated CRUD includes translated fields — if not, extend the stubs.
Version alignment. Pin savannabits/translatable and savannabits/craftable to the same major (^7.0.0). Treat a bump on one without the other as unsupported.
null. This is the single most common source of "empty field" bugs; assert it in a test early.where('name', ...) will not match translated values on all DB drivers. Use the package's query scopes/helpers, or add generated columns, rather than raw where on translated attributes.$fillable/isDirty expectations. Verify save() persists all locales and that getDirty() reflects changes per locale.toArray()/API resources emit — full locale map or active locale only. Configure explicitly; don't inherit accidental behavior into a public API.$translatable, then the raw DB value — in that order, it resolves most issues fastest.src/ and config/ before relying on them.How can I help you explore Laravel packages today?