themsaid/laravel-langman-gui
A clean web interface for managing Laravel translations. Browse, search, add, edit, and delete localization keys and values across all locales without touching language files, built on the Laravel Langman translation manager. Supports PHP and JSON translation files.
Install
composer require themsaid/laravel-langman-gui
On Laravel 5.5+ the LangmanGUIServiceProvider is auto-discovered. On 5.4 and below, register it manually in config/app.php:
Themsaid\LangmanGUI\LangmanGUIServiceProvider::class,
Publish the config and views so you can control the route, middleware, and markup:
php artisan vendor:publish --provider="Themsaid\LangmanGUI\LangmanGUIServiceProvider"
Where to look first
config/langman-gui.php — the only file that matters at boot. It holds the route/path and the middleware stack. Do this before visiting anything.resources/lang/*.json — the GUI operates on these files directly; there is no database. If a locale file doesn't exist, the GUI can create it, but it needs a locales list or you add the language from the UI.vendor/themsaid/laravel-langman — the GUI is a thin web layer over the Langman Manager class. Every "save" is a filesystem write performed by that class. Reading its Manager::__construct/updateTranslation methods answers 90% of "why did it write that?" questions.First use case (5 minutes)
Open /{route} (default /langman). You'll see a two-pane layout: languages on the left, key/value table on the right. The fastest win is:
fr.json) from the language selector.en.json.git diff resources/lang/fr.json — confirm the write before you trust it in a workflow.That's the whole product: a browser-based editor for JSON catalogs, with search and per-locale tabs. It does not scan your code for new keys — that's the CLI sibling (themsaid/laravel-langman, pulled in as a dependency) via php artisan langman:sync.
CLI finds keys, GUI fills them. The productive loop is to let langman:sync walk your app/ and resources/views/ for __(), @lang, and trans() calls and append missing keys to the JSON files, then use the GUI for the human part — reading the key in context and typing the translation. Don't try to invent keys in the browser unless you're also using them in code; orphan keys accumulate fast and the GUI has no "unused key" column.
Pair it with langman:missing in CI. Before a release, run php artisan langman:missing in a build step and fail on output. The GUI is for editing; the CLI is for enforcement. This keeps translators from silently skipping keys and gives you a diff-based audit trail.
Treat resources/lang as source, not runtime state. Commit JSON changes to git, review them in PRs, and let the GUI be a local-authoring convenience. Because the GUI writes the entire file on save, a PR diff is the only reliable record of what changed — there is no history, no undo, no audit log in the package.
Gate the route aggressively. In config/langman-gui.php:
'middleware' => ['web', 'auth', 'can:manage-translations'],
or an environment check in AppServiceProvider::boot():
if (app()->environment('production')) {
config(['langman-gui.middleware' => ['web', 'auth', 'can:manage-translations']]);
}
The default middleware is empty — that is the single biggest thing to fix on install. A translations editor is effectively a remote code-adjacent write surface: strings rendered through {{ }} are escaped, but {!! !!} call sites and @lang inside attributes make unvetted writes a real escalation path.
Split the audience. Give translators an account with only the manage-translations ability and point them at the GUI. Keep developers on the CLI. This works well because the GUI has no concept of users, permissions, or approval — you supply all of that with middleware and route gating.
Customize views rather than fork. Published views land in resources/views/vendor/langman-gui/. Reordering columns, adding a "copy from fallback locale" button, or embedding a link back to the repo is a Blade edit, not a package fork. The controller passes a flat key/value map per locale, so most cosmetic changes are trivial.
Use the underlying Manager directly for bulk operations. Anything the GUI does, you can script:
use Themsaid\Langman\Manager;
$manager = app(Manager::class);
$manager->updateTranslation('fr', 'Welcome back', 'Bon retour');
This is the right escape hatch for seeding a new locale from a spreadsheet or an external TMS export. The GUI is a convenience layer; Manager is the actual API.
Namespace and package translations are out of scope. The GUI edits the app's resources/lang files only. Third-party package translations (vendor/.../resources/lang) and namespaced PHP-array groups aren't part of its model — handle those with vendor:publish and normal editing.
It is frozen at Laravel 5.x / PHP 7.x (last release October 2017). This is the dominant risk. The package and its laravel-langman dependency are unmaintained; they predate the removal of array_get, str_slug, and friends, and predate Laravel 6's semantic versioning split. On a modern Laravel you should expect to fork it, or budget a morning to port the provider and controller. Do not add this to a greenfield Laravel 10/11 project without verifying it boots — check the composer.json constraints first, then smoke-test /langman before writing any docs for your team.
The route is unauthenticated out of the box. If you install it, visit it once to confirm, then lock it down. A forgotten langman route on a staging server that's publicly reachable is how translation files get defaced.
Last-write-wins, whole-file writes. Every save serializes the full JSON file. Two people editing the same locale simultaneously will silently clobber each other, and a browser tab left open for an hour will overwrite newer changes. Tell translators to refresh before saving; keep the editing window short.
JSON formatting churn. Writes may not use JSON_UNESCAPED_UNICODE/JSON_UNESCAPED_SLASHES, so a single edit can produce a diff full of \u00e9 escapes across the whole file, burying the real change. If diffs get noisy, normalize the files with a formatter in a pre-commit hook rather than fighting the package.
Key ordering is not guaranteed. langman:sort exists on the CLI, but the GUI's save path may reorder or reformat. Pick one ordering convention, apply it via CLI or a script, and don't expect the GUI to preserve it.
Empty string ≠ missing. A key with "" counts as present to both the GUI and langman:missing. If your workflow relies on "missing" detection to find untranslated strings, empty values will hide from you. Grep for ": "" as a separate check.
Filesystem permissions bite silently. The web server user needs write access to resources/lang. If saves appear to succeed but nothing changes, check storage/logs/laravel.log and the ownership of the JSON files — the Manager will throw, and the package's error surfacing is minimal.
Config and route caching. The route is registered by the service provider, so php artisan route:cache can interact badly if you change the route config later. After editing config/langman-gui.php, run config:clear (and route:clear if cached). In deploy scripts, clear caches before verifying the route responds.
Search is client-side-ish and the table is flat. With thousands of keys the page gets heavy and long keys are hard to scan. Use search rather than scrolling, and consider keeping keys short and descriptive — the JSON key is the English string in Laravel's JSON translation model, so key length is user-visible prose length.
Extension points are limited to config, views, and middleware. There are no events, no save hooks, and no storage driver abstraction. If you need audit logging or an approval workflow, wrap the routes with your own middleware that snapshots resources/lang before and after, or skip the GUI and build a small controller over Manager yourself — the package is small enough that reimplementation is often cheaper than forking.
The 2017 date is itself the assessment. With ~500 stars and near-perfect "opportunity" scoring, this package is a well-known, well-liked tool that nobody has maintained. For a Laravel 5.x legacy app with a translation backlog, it's a genuinely useful afternoon install. For anything current, treat it as a reference implementation of the idea — a JSON translation editor behind auth — rather than a dependency you ship.
How can I help you explore Laravel packages today?