optimistdigital/nova-lang
Laravel Nova package that adds multi-language support to your admin panel: manage languages, switch the active locale per user, and localize resources and fields. Integrates with nova-translatable and ships middleware, a Language model, and configurable fallbacks.
Install with Composer and pin the version explicitly — the package has not shipped since October 2020, so you want a lockfile entry you can audit later:
composer require optimistdigital/nova-lang:^1.0
Register the service provider (Laravel 5.5+ auto-discovery usually handles this, but verify by checking vendor/optimistdigital/nova-lang/composer.json for a laravel.extra.providers block). If it is not auto-discovered, add it to config/app.php.
Where to look first, in order:
vendor/optimistdigital/nova-lang/src/ — read the service provider, any traits, and the config file. Documentation for this package is thin; the source is the documentation.vendor/optimistdigital/nova-lang/config/*.php — publish it with php artisan vendor:publish --tag=novalang-config (check the actual tag in the provider) and inspect the available locale keys and default locale.HasLocales or Locatable) — this is what you attach to the Eloquent model.The first use case to validate: take one existing Nova Resource, attach the package's trait to its underlying model, run php artisan migrate if the package ships migrations (check database/migrations/), and confirm the resource's index view still renders. Do this in isolation before touching multiple resources — it tells you immediately whether the package is compatible with your Nova version.
Per-resource locale assignment. The core pattern is attaching the trait to each localizable model and then either adding a Select/locale field in the resource fields, or relying on the package's own field/component. Keep the trait on the model, not the Nova Resource — Nova Resources are not Eloquent models and traits on them won't persist.
Locale-scoped queries. Once a model is locale-aware, wrap your resource's indexQuery() override to constrain by the active locale. This is where the package's value lives: it gives you a consistent source of truth for "which locale is this resource row in" so you don't have to hand-roll a locale column on every table.
public static function indexQuery(NovaRequest $request, $query)
{
return parent::indexQuery($request, $query)
->where('locale', app()->getLocale());
}
Sorting the index view. If you need deterministic ordering across locales (alphabetical names differ per language), sort by the localized column rather than the base column. The package's sorting hook — if present — typically needs to be composed with your own defaultSort on the resource, not replace it.
Middleware / locale switcher. For day-to-day work, pair the package with a small Nova tool or nav menu entry that flips the active locale. The package assigns locales to resources; it rarely provides the switcher UI you'll actually want. Budget an afternoon for a custom Nova card that writes the chosen locale to the session and reloads.
Integration tip: store the active locale in the session, not just config('app.locale'). Nova is a SPA-ish experience; a config-only approach requires a full page reload to switch context and produces confusing results in the browser.
composer.json for the Nova constraint before upgrading Nova. A Nova 3 → 4 jump will almost certainly require forking.laravel/nova is a private Composer package. The require block here was written against Nova 3.x; check the constraint manually and override with "extra": {"laravel": {"dont-discover": [...]}} if auto-discovery breaks.php artisan config:clear — Nova caches aggressively and stale locale lists are a common "why isn't my locale showing" cause.locale column, run them before seeding or adding the trait to existing models, otherwise mass-assignment and firstOrCreate calls will silently write null locales.src/) rather than guessing; the resolution order is usually session → config → app default, and it's undocumented.register() method after the package provider in config/app.php — that's the cleanest override without editing vendor files.where('locale', ...) you add, decide explicitly whether missing-locale rows fall back to the default locale or are excluded. Mixed behavior between resources is the #1 source of "missing content" bug reports.How can I help you explore Laravel packages today?