optimistdigital/nova-locale-manager
Nova Locale Manager is a Laravel Nova tool for managing your app’s locales from the admin panel. Add, edit, enable, or disable languages and set the default locale without editing config files, simplifying multilingual Nova applications.
Install the package
composer require optimistdigital/nova-locale-manager
Publish anything it ships (config and/or migrations — check the service provider for publish tags):
php artisan vendor:publish --provider="OptimistDigital\NovaLocaleManager\NovaLocaleManagerServiceProvider"
php artisan migrate
Inspect the generated migration to understand the schema (typically a locales table with name, code, and a default flag).
Register the tool in app/Providers/NovaServiceProvider.php:
use OptimistDigital\NovaLocaleManager\LocaleManager;
public function tools()
{
return [
new LocaleManager(),
];
}
Where to look first
config/nova-locale-manager.php — table name, model override, any Nova-resource settings.vendor/optimistdigital/nova-locale-manager/src/Models/Locale.php — the model you'll reference from your app.src/Nova/ or src/Http/ — the resource/controller powering the tool UI.resources/js/ — the Vue components, if you need to extend the UI.First use case — add a locale your app doesn't yet support (e.g. et / Estonian), set a default, then wire a language switcher or route prefix to that list. Confirm the tool lists it in the Nova sidebar and that the table row exists via php artisan tinker.
Treat the package's model as the source of truth. Reference it everywhere you need "available languages" instead of hardcoding ['en', 'fr']:
use OptimistDigital\NovaLocaleManager\Models\Locale;
$locales = Locale::orderBy('name')->get();
Nova select fields backed by the table
use Laravel\Nova\Fields\Select;
Select::make('Language')
->options(Locale::pluck('name', 'code'))
->rules('required', 'exists:locales,code'),
Locale detection middleware — validate against the DB so a deleted locale stops serving traffic:
public function handle($request, Closure $next)
{
$code = $request->segment(1) ?? session('locale');
if ($code && Locale::where('code', $code)->exists()) {
app()->setLocale($code);
session(['locale' => $code]);
}
return $next($request);
}
Route-prefix multilingual routing — wrap your localized routes:
Route::group(['prefix' => '{locale}', 'middleware' => SetLocale::class], function () {
// ...
});
Validate {locale} in the middleware rather than in the route constraint so it stays in sync with the DB.
Default-locale discipline — enforce a single default with an observer on Locale:
static::saving(function ($locale) {
if ($locale->is_default) {
static::where('id', '!=', $locale->id)->update(['is_default' => false]);
}
});
Cache the list — the tool reads it from the DB on every page render in admin; wrap in Cache::remember('locales', 3600, ...) and flush on the model's saved/deleted events.
Pair with your translation files — keep resources/lang/{code} (or lang/{code}) in sync manually or via a small Artisan command that scaffolds missing directories when a locale is created. The package manages the locale list, not the translation strings.
Fallback locale — configure config/app.php fallback_locale from the default row on boot, or expose it as a setting so admins can promote another locale without code edits.
Tool base class has changed across majors.deleting observer to clean up or guard routes.canSee() in the tool registration or wrap the tool behind a Nova gate:
public function canSee(NovaRequest $request) { return $request->user()->isAdmin(); }
php artisan config:clear; the tool won't pick up a changed table name otherwise.locales table. If you already have one (e.g. from another i18n package), rename via the config before migrating or the package will silently reuse/conflict.created_at/updated_at or soft deletes — don't assume them in your queries.fields() / fieldsForUpdate() to add columns (flag icon, native name, RTL flag). Same trick applies to the model via config('nova-locale-manager.model') if the package exposes it — confirm in the config file.app(Nova::class)->tools() output and Nova's NOVA_LICENSE state — tools fail silently when Nova itself isn't booted.How can I help you explore Laravel packages today?