Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Translation Laravel Package

bbs-lab/nova-translation

Laravel Nova package for managing translations in your admin panel. Edit and organize multilingual content, localization strings, and translated resource values from one Nova interface, so teams can maintain Laravel apps in multiple languages without switching tools or juggling separate translation...

View on GitHub
Deep Wiki
Context7

Getting Started

This is a maintenance release (v5.4.1) for bbs-lab/nova-translation, a Laravel Nova integration for managing translated model attributes (typically alongside spatie/laravel-translatable). There are no new features or breaking changes — it is a boot-timing fix for the model observer the package registers.

Start here:

  1. composer require bbs-lab/nova-translation and confirm your Nova major version matches the package branch (v5.x targets Nova 4/5-era APIs).
  2. Publish and review the package config (php artisan vendor:publish --tag="nova-translation-config"), which is where the supported locale list lives. Keep it aligned with config/app.php and spatie/laravel-translatable's fallback locale.
  3. Ensure each model you want to translate uses Spatie's HasTranslations trait and declares the attributes in $translatable — the package edits those JSON columns, it does not create a parallel translations table.
  4. Attach the package's translation field to your Nova resource (or register the tool in NovaServiceProvider::tools() if you are using the global management view).

First use case: take one resource with two translatable columns (e.g. title, body on Article), add the translation field, and verify you can switch locale in the Nova detail view, edit, save, and see the raw JSON column update. Do this before rolling it across resources — the field's behaviour on create vs. update is the thing most likely to surprise you.

Upgrade note: if you are on ≤5.4.0, upgrading is low-risk and specifically recommended if you saw observers not firing or behaving inconsistently when models were resolved early in the request lifecycle.

Implementation Patterns

  • Field-per-resource, not global. Add the translation field explicitly to each resource's fields() method rather than relying on the tool to cover everything; it keeps authorization and validation co-located with the rest of the resource.
  • Config as the single source of locales. Drive the displayed locale set from the package config (or a per-field locales() override if exposed) and derive your app.locales from the same array, so a new locale is one edit rather than three.
  • Locale switching, not tab duplication. The common workflow is one tab per locale in the detail view. For index views, prefer showing the fallback locale plus a "translated / missing" indicator over rendering every locale column.
  • Observer deferral is now the package's job. Because v5.4.1 registers the observer inside whenBooted, you no longer need any manual Model::observe(...) wiring in a service provider. If you wrote your own translation observer or a saving hook to work around the old timing, delete it after upgrading — otherwise you will get double writes.
  • Testing pattern: RefreshDatabase, create a model with setTranslation('title', 'fr', '...'), then assert against getTranslations('title') (raw array) rather than getTranslation() (which applies fallback). Set the locale explicitly in the test rather than relying on the default.
  • Pair with Nova policies. The field respects Nova's update ability; gate who can edit translations the same way you gate the underlying model, since translators are often a separate user group from authors.

Gotchas and Tips

  • Duplicate observers after upgrading. If you had a manual workaround for the pre-5.4.1 bug, remove it. Symptom of duplication: revision/audit entries written twice, or updated events firing twice on a translation save. Check with Model::getEventDispatcher()->hasListeners('eloquent.updated: App\Models\Article').
  • Booted is late; don't depend on the order. If your own provider also touches the same model's events, register it in boot() and be aware the package's observer may be attached afterwards. Do not assume the package observer exists when your provider's boot() runs.
  • Config caching. Locale changes made directly in the config file are invisible until php artisan config:clear in a cached environment. This is the most common "my new locale doesn't appear" report.
  • $translatable mismatch fails silently. A field pointing at a column not listed in $translatable (or a non-json column) will render but not persist as expected. Verify the schema column type and the trait array together.
  • Fallback masks empty input. With Spatie fallback enabled, getTranslation() returns the fallback string when a locale is blank, so an "empty" translation can look populated. Use getTranslations()/getTranslationsWithoutFallback() when you need the truth.
  • Per-locale validation. Nova rules like 'title' => 'required' apply to the array, not per locale. Use nested rules keyed by locale if you need "required in the primary locale only", or you will block saves on partially translated content.
  • Debugging checklist: php artisan about (Nova + package versions) → config published and locales correct → model trait and $translatable correct → observer registered (dump the event dispatcher) → raw DB row updated. That sequence isolates nearly every report.
  • Pin the patch version in composer.json if you ship on Octane or long-running workers; boot-timing fixes are exactly the class of change worth controlling deliberately.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource