outhebox/laravel-translations
Laravel Translations gives you a clean dashboard to import, edit, search, and export your app's translations—no npm or Vite needed. Simple install, Artisan commands, and configurable settings for PHP 8.3+ and Laravel 11/12.
Architecture fit. The package behaves less like a library and more like a mounted mini-application: it registers its own routes (default /translations), ships migrations and its own database tables (languages, groups, keys, translations, contributors), provides a pre-compiled React 19 / Inertia frontend, and exposes artisan commands for import, export, status, install, update, and upgrade. That is a strong fit for teams that want an internal translation console without standing up a separate service, and a poor fit for teams with an existing TMS (Crowdin, Lokalise, Phrase) or a strict "lang files only" policy.
The central architectural fact is the dual source of truth: Laravel reads translations from lang/ files at runtime, while the package stores working state in the database and only reconciles via translations:import / translations:export. Any integration design must explicitly decide which side is authoritative. The defensible pattern is: files are the deployable artifact, the database is a staging/workbench, and an export step is a required part of the release pipeline. If that isn't enforced, drift is guaranteed.
A genuine positive: because compiled assets are bundled, there is no npm/Vite requirement in the host project. This removes the biggest operational objection to embedding a React/Inertia admin UI into a legacy Blade/Livewire app.
Integration feasibility. Broad but not free. Hard requirements are PHP 8.3+, Laravel 11/12/13, and Inertia (the package pulls inertiajs/inertia-laravel ^2||^3 and spatie/laravel-query-builder). Expect moderate work in four places:
database_connection. Either choice needs a migration/rollback plan and backup posture, since these tables hold content, not derivable state.translations:update to re-publish assets.Technical risk. Rated medium-high, driven by governance rather than code quality:
Outhebox\TranslationsUI to Outhebox\Translations, new config shape). That is a precedent for breaking upgrades. v2.0.1 already had to fix a MySQL/MariaDB DDL-in-transaction failure in translations:upgrade.import --fresh overwrites existing translations; export writes into the lang/ directory. Both need guardrails (branch protection, dry-run/status checks in CI, filesystem permissions review).database_connection config, file-select filtering.Key questions for the vendor/team:
lang/ files — and who owns the export?translations:status give us a reliable CI gate against DB/file drift?lang/ files + a TMS)?Stack fit. Good for a Laravel 11/12 monolith on a modern PHP baseline that already runs (or can tolerate) Inertia for a single admin surface. If the app is Laravel 10 or PHP 8.2, this package is simply unavailable — that alone can defer the decision. If the app is a multi-tenant SaaS with per-tenant translations, this is a poor fit: the schema and file paths assume a single application-level translation set.
Migration path. Two independent migrations must be planned:
lang/ files → translations:import → DB. Non-destructive by default; validate a sample of nested and dot-notation keys round-trip through export before trusting it broadly.php artisan migrate:rollback --path=vendor/... is operationally awkward against the primary schema).For anyone on v1, budget a dedicated spike for translations:upgrade on a MySQL/MariaDB replica first — the 2.0.1 DDL/transaction bug is exactly the class of failure that shows up only in the upgrade path.
Compatibility. Pin the minor version (^2.1) and treat asset re-publishing as part of the upgrade, not an afterthought. Add the documented post-update-cmd hook for translations:update, but note it means composer update mutates served assets — that is a deploy-time side effect CI should own, not a developer laptop. Verify spatie/laravel-query-builder v7 and Inertia version alignment against the host app, since v2.1.0 shipped specifically to fix those constraints.
Sequencing (recommended):
lang/; export; diff the output byte-for-byte. This single test tells you whether the tool is safe for your key shapes.lang/ is the artifact, translations:export runs in CI/deploy, translations:status fails the build on drift.Maintenance. Ongoing cost is low but nonzero and slightly unusual: every package upgrade requires re-publishing assets (translations:update). Miss it and the UI breaks with stale or missing bundles while the backend still works — a confusing failure. Beyond that, you own a small content database and its backups, plus the CI drift gate. Single-maintainer risk means you should expect to self-diagnose issues from source rather than from documentation; the README is good on the happy path and thin on failure modes.
Support. GitHub issues only, no SLA, no commercial support on the free tier. That is acceptable for an internal admin tool and unacceptable for anything on the critical path of a customer-facing release. Mitigation: keep the exit path warm — because translations are ultimately plain lang/ files, you can drop the package and retain all content. That reversibility is the single strongest argument for adoption.
Scaling. Three dimensions:
translations:export writes to local disk. On multi-node or containerized deploys, export must run in a build step or against a shared volume — never as a runtime request on one node. Octane compatibility is claimed and was specifically fixed in v2.0.0, but treat that as "reported working," not "verified in our stack."Failure modes to design against:
| Failure | Impact | Guardrail |
|---|---|---|
import --fresh run against prod DB |
Silently loses edited translations | Command allowlist; no prod DB credentials in dev tooling |
| Export never runs | DB and shipped lang/ files diverge; UI shows translations users never see |
translations:status as a required CI check |
| Assets not re-published post-upgrade | Blank/broken UI | post-update-cmd hook + smoke test in staging |
Export writes to a read-only or non-shared lang/ path |
Export fails or writes to one node only | Build-step export, volume permissions |
| Route left unauthenticated | Public write access to content | Middleware + prefix config verified in staging |
| Translator flips approval status (fixed in v2.1.1) | Workflow integrity | Pin >=2.1.1 |
| Pro-gated feature turns out to be required | Forced license purchase or re-platform | Decide audit-trail requirement up front |
Ramp-up. Two distinct audiences. Developers need roughly half a day: install, config, auth wiring, and understanding the import/export contract. Translators need almost none — that is the product's core value and it is genuinely good. The hidden ramp-up cost is process definition, not tooling: someone must own "when does the DB become files," and that decision is what determines whether this package reduces or increases coordination overhead. Budget PM time for that, not engineer time.
Verdict. Adopt as a reversible, staging-scoped convenience layer for a small number of locales, with the file-as-artifact contract enforced in CI. Do not adopt as a system of record, and do not adopt at all if audit history or an external TMS is a requirement — in both cases the open-core boundary means you are really evaluating the Pro product, not this package.
How can I help you explore Laravel packages today?