bernhardh/nova-translation-editor
A Laravel Nova tool for editing translations without leaving the admin panel. Browse, search, and update language strings across locales and files, so teams can manage copy quickly, keep translations consistent, and avoid manual file edits.
Verify it resolves against your stack before anything else. The repo is archived, the last release is 2023-03-01 (v2.0.4), and it targets the Nova 4 / Laravel 9–10 era. Your first five minutes should be a dependency check, not a code change:
composer require bernhardh/nova-translation-editor
composer why-not bernhardh/nova-translation-editor
why-not tells you exactly which laravel/framework or laravel/nova constraint blocks resolution. If it fails here, the remaining content applies only to a fork.
Register the tool in your Nova service provider. Confirm the class and namespace against src/ first — the README is stale and there is no maintained documentation to trust:
// app/Providers/NovaServiceProvider.php
public function tools()
{
return [
new \Bernhardh\NovaTranslationEditor\NovaTranslationEditor(),
];
}
Publish and refresh assets.
php artisan vendor:publish --provider="Bernhardh\NovaTranslationEditor\NovaTranslationEditorServiceProvider"
php artisan nova:publish
Run migrate only if the publish step actually emits a migration — its presence or absence is the fastest way to learn whether this is a DB-backed editor or a file writer (see the write-path note below).
Where to look first, in this order:
src/ — end to end. It is a single-screen tool; the whole thing fits in an afternoon and reading it is cheaper than any amount of guessing.language_lines-style table (group, key, locale, text) means you are editing DB-backed translations; no migration means it rewrites lang/ PHP/JSON files in place.lang/ in your own repo — confirm it is git-tracked before letting anyone edit through the UI.First use case: a timeboxed spike on a branch. Install, register, publish, then edit exactly one string end-to-end in a staging Nova panel and confirm it renders on the front end after a cache clear. Half a day. That spike answers the only question that matters for daily use: does a save actually take effect, and how long does it take to see it? If the answer is "sometimes," stop and read the write path before going further.
The daily-use shape to expect: an editor opens the tool, picks a locale, searches a key, edits the value, saves, and the change is live. Everything below is about making that loop reliable.
Keep it on the admin plane. The tool lives behind Nova's authenticated /nova route. Nothing in your application request path should reference it. That containment is the whole value proposition: if it breaks after a Nova bump, an internal editing workflow degrades, not the customer-facing app.
Pin down the write path on day one, because it determines your entire workflow.
lang/ PHP/JSON): saves are direct mutations of developer-authored files with no diff, history, or undo inside the tool. You need git-tracked lang/ and a reviewed deploy path.The two cases have different day-to-day habits. Know which one you are in before onboarding a content editor.
Make git your audit trail. If the write path touches files, the practical loop is: editor changes strings in staging Nova → git diff lang/ shows exactly what changed → the diff goes through the normal PR/deploy path. That diff is your review, your rollback, and your history. There is no built-in change log in this package, so if lang/ is not committed, you have no audit trail at all.
If the write path is a table, add the audit trail yourself — an updated_by column or a model observer — because the package will not provide one.
Decide cache invalidation explicitly and put it in the workflow. Laravel caches compiled translations, and DB-backed loaders cache their lookups. Confirm that a save busts the relevant cache. If it does not, add a save hook or make php artisan cache:clear part of your post-edit ritual. Silent stale reads after a "successful" save destroy editor trust faster than a hard error ever would.
Scope locales deliberately. Expose only the locales content owners actually own — not everything in config/app.php. Fewer locales keeps the index screen usable and keeps the blame surface small when a string goes wrong.
Gate access yourself; assume the package does not. Nova's default is "can access the panel," which is far too broad for a tool that rewrites customer-facing copy:
Gate::define('editTranslations', fn ($user) => $user->hasRole('content-admin'));
Then wire it through Nova's tool authorization or middleware on the tool route. Verify in src/ whether anything granular already exists; if not, add it.
Fork or vendor-copy before the first non-spike commit. "Pin upstream and hope" is not a maintenance strategy for an archived repo.
{
"repositories": [
{ "type": "vcs", "url": "[email protected]:yourorg/nova-translation-editor.git" }
],
"require": {
"bernhardh/nova-translation-editor": "dev-main"
}
}
The codebase is small enough that the cost is bounded — but it needs a named owner and a standing line item to re-verify compatibility at each Nova and Laravel major.
Use it as a reference implementation once you outgrow it. The realistic trajectory is spike → small internal pilot → either keep the fork alive at roughly half a day per upgrade cycle, or replace it with a thin custom Nova resource over a translations table (group, key, locale, text). That build is 3–5 dev-days and removes the fork obligation entirely. If browse-and-edit is all you need, the custom resource may be the better endpoint.
Integration tip: keep the editor's mental model aligned with the app's. The common failure in translation tooling is an editor picking a locale the app does not resolve for their context (app()->getLocale() vs. the tool's selector). Show the locale prominently, and verify the front end with the same locale you edited.
Composer conflicts are the primary failure mode. The archived tag's illuminate/* and Nova upper bounds will eventually block a framework upgrade and force an unplanned fork-or-remove decision. Never evaluate or upgrade this tool in parallel with a Nova or Laravel major — the failure modes will be indistinguishable and you will waste a day.
Stale compiled assets break the tool screen with no PHP error. Nova tools ship pre-built JS. After any Nova minor bump, run php artisan nova:publish and hard-refresh. A blank or partially rendered screen is almost always an asset mismatch, not a PHP bug. The final release, v2.0.4 "avoid overflow," being a CSS-level fix is a hint that the front end is hand-tuned and sensitive to Nova layout changes.
Check the namespace and class name against src/ before copying any snippet — including the one in this document. Namespaces drift, and there is no maintained documentation to arbitrate.
Debugging checklist when a save "succeeds" but nothing changes:
git diff lang/, or query the translations table directly.storage/logs/laravel.log — a permissions problem on lang/ often surfaces as a swallowed exception in admin tools.Test with long values and RTL text on day one. The last release was March 2023, so any layout or string-length bug filed after that is yours to fix. Push 200+ characters and a right-to-left string through the editor before handing it to a content team.
Watch what it scans. Confirm whether the tool walks vendor/ translation groups. Scanning vendor keys is slow and misleading, and writing there is destructive across composer install. If it does scan vendor, restrict the exposed groups in config.
Pagination at scale. Hundreds of locales × thousands of keys makes the index screen unusable without server-side filtering. Verify pagination and server-side search exist in src/ before putting a large translation set in front of editors — otherwise you are shipping a tool that times out on the first search.
Permissions on lang/. If the write path is file-based, the web process needs write access to lang/. That is a real deployment consideration: it means lang/ is not read-only in production, which affects container images, immutable deploys, and any "filesystem is read-only" hardening. Decide deliberately whether editing happens in staging (writes then flow through git) or in production (writes hit the live filesystem), because the latter breaks most hardened deploy models.
Write the exit plan down before the first non-spike commit. The two realistic options are: keep the fork alive with a named owner and a per-major compatibility budget, or replace it with a thin custom Nova resource. Pick one and pick the trigger, so the decision is not made under upgrade pressure at the worst possible moment.
How can I help you explore Laravel packages today?