Laravel Translation Manager
Database overrides for Laravel translations: edit any key - app, JSON or vendor package - at runtime, find missing translations per locale and export the result back to lang files.
#Laravel Translation Manager
Override any Laravel translation from the database — your app's lang/{locale}/*.php groups, the lang/{locale}.json strings and the lines of every installed package (filament-panels::, validation, your plugins…) — without a deploy. Find the keys missing in each locale, and when you're happy, export the overrides back to lang/ so they live in Git.
The lang files stay the source of truth: the package only lays the database overrides over what the framework's file loader returns. For an admin UI, use jeffersongoncalves/filament-translation-manager.
#Installation
composer require jeffersongoncalves/laravel-translation-manager php artisan migrate php artisan translation-manager:scan
Optionally publish the config:
php artisan vendor:publish --tag=translation-manager-config
#How it works
translation-manager:scanreads every lang file — app groups, JSON, and the groups of each registered package namespace (including the ones you published tolang/vendor) — for every locale, and stores the values in thetranslation_linestable (sourcecolumn). Re-run it after adding keys or installing packages; it never touches your overrides.- An override is a value in the
textcolumn for a locale.__(),trans()and@langreturn it instead of the file value. An empty override falls back to the file. - Overrides are cached per namespace + group and the cache is flushed whenever a line is saved or deleted.
- If the table doesn't exist yet (fresh install, migrations pending) the files are used as-is — translations never break the app.
- Long-running processes (queue workers, Octane) keep the groups they already loaded — restart them after changing overrides.
#Usage
use JeffersonGoncalves\TranslationManager\Models\TranslationLine; // app group: lang/pt_BR/messages.php → messages.welcome TranslationLine::query()->updateOrCreate( ['namespace' => '*', 'group' => 'messages', 'key' => 'welcome'], ['text' => ['pt_BR' => 'Olá!']], ); // package line: filament-panels::pages/dashboard.title TranslationLine::query() ->where(['namespace' => 'filament-panels', 'group' => 'pages/dashboard', 'key' => 'title']) ->first() ?->update(['text' => ['pt_BR' => 'Início']]); // keys with neither a file value nor an override in a locale TranslationLine::query()->missing('pt_BR')->get()->map->fullKey();
namespace is * for the app's own lines and group is * for JSON lines. $line->value('pt_BR') returns what __() would, $line->fullKey() the key you'd pass to it.
#Export to lang files
php artisan translation-manager:export # every locale php artisan translation-manager:export --locale=pt_BR # one locale php artisan translation-manager:export --clear # and drop the exported overrides from the database
| Override | Written to |
|---|---|
| JSON line | lang/{locale}.json |
| App group | lang/{locale}/{group}.php |
| Package line | lang/vendor/{namespace}/{locale}/{group}.php — the file Laravel already lays over the package's own |
Existing keys in those files are kept; only the overridden keys are added or replaced.
#Configuration
| Key | Default | |
|---|---|---|
table |
translation_lines |
|
locales |
[] |
locales to scan and manage; empty = every locale found in lang/ plus app.locale and app.fallback_locale |
namespaces.include |
[] |
package namespaces to scan; empty = all |
namespaces.exclude |
[] |
package namespaces to skip |
cache_store |
null |
cache store for the overrides; null = default |
#Testing
composer test
#Changelog
Please see CHANGELOG for more information on what has changed recently.
#Contributing
Please see CONTRIBUTING for details.
#Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
#Credits
#License
The MIT License (MIT). Please see License File for more information.