Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Translations Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Install in four steps, in this order:

composer require outhebox/laravel-translations
php artisan translations:install   # publishes config, migrations, pre-compiled assets
php artisan migrate
php artisan vendor:publish --tag=translations-config

Then hit /translations. The frontend is React/Inertia with pre-compiled assets — you do not need npm, Vite, or a build step in your app. That's the single biggest practical advantage over rolling your own translation admin.

Look here first:

  • config/translations.php — this is where you'll spend your first 10 minutes. Check path (default lang/), middleware, authentication, source_language, and import/export settings. Do this before anyone else opens the UI.
  • php artisan translations:status — gives you a snapshot of what the package sees (locales, groups, key counts). Run it immediately after install to confirm your existing lang/ tree was detected correctly.
  • The migrations — they add several tables (languages, groups, keys, translations, contributors). Knowing they exist matters later, because the database becomes the source of truth once you import.

First use case: import your existing translation files to establish a baseline, then let a non-developer edit copy without touching the repo.

php artisan translations:import          # additive — adds new keys, leaves edits alone
php artisan translations:import --fresh  # destructive — overwrites existing translations

Follow with translations:export to confirm a round-trip is byte-clean for your file structure before you invite a translator. Round-trip fidelity is the thing you want to validate on day one, not after someone has hand-edited 400 strings. Pay particular attention to nested folders (lang/en/admin/users.php), dot-notation keys, and JSON string-key files — these have historically been the source of the most regressions in this package's changelog.

Minimum viable production hardening: wrap the route behind your existing auth. Do not leave /translations open — a fresh install exposes an editing UI at a guessable path.

// config/translations.php
'middleware' => ['web', 'auth', 'can:manage-translations'],

Implementation Patterns

The import → edit → export → commit loop

The package is a DB-backed editor over file-backed translations. Treat it as a two-way sync with a human in the middle, and codify the loop:

  1. Developer adds __('admin.users.title') in code, commits a key to lang/en/... (or leaves it missing).
  2. translations:import pulls new keys into the DB.
  3. Translator edits in the UI (or gets invited via the contributors system).
  4. translations:export writes back to lang/{locale}/....
  5. Exported files are committed and reviewed in a PR like any other code change.

Step 5 is non-negotiable if you care about review. The free tier has no revision history (that's a Pro feature), so git over the exported files is your audit log. Set the export step as an explicit PR in your workflow rather than letting the UI write directly to a server that deploys itself.

Gate the export step in CI

Because export is deterministic, you can make "translations are in sync" a CI check:

- run: php artisan translations:export
- run: git diff --exit-code lang/

This catches the classic failure mode: someone edited strings in the UI on staging, nobody exported, and the next deploy silently reverts them. It also catches import drift on branches.

Deployment ordering

The DB holds the truth between import and export, so your deploy pipeline needs a decision. Two workable stances:

  • Files are canonical in production. Ship lang/ from the repo; run translations:import only in staging/admin environments, and treat the UI as a staging tool. Simplest and safest.
  • DB is canonical. Export on a schedule or on-demand and commit the result; never import in production without --fresh awareness. Requires discipline and a backup of the translation tables.

Most teams shipping with a small number of locales pick the first. Teams with contract translators and many locales trend toward the second.

Contributor roles

v2 added a contributors system with role-based access and email invitations. Use it instead of sharing an admin login:

# contributor management is also available via artisan (see the ContributorCommand)
php artisan translations:contributor ...   # create/invite with a role

Practical pattern: developers keep an admin/manager role; translators get a scoped role. Note that v2.1.1 explicitly fixed a bug where translators could set approval status — if you're on an earlier 2.1.x, upgrade, because that's an authorisation boundary, not a cosmetic bug.

Integration with your own auth

The authentication config key lets you point the package at your guard/model so invitations and attribution land on real users. Wire it to your existing User model before inviting anyone, or you'll end up with orphaned contributor records you have to clean up by hand.

Surfacing what matters: priority + similar keys

v2 added a priority field on keys and a "similar keys" suggestion in the phrase editor. Two cheap wins:

  • Mark high-traffic/frequently-changed groups (marketing banners, pricing, legal) as priority so translators see them first in the DataTable.
  • Use similar-keys suggestions as a consistency check — if the editor suggests an existing key for your new phrase, you probably have a duplicate string that should be deduplicated in code.

Bulk operations

The v2 DataTable supports select/filter/bulk actions. Filter by file (group) and bulk-apply status or delete across a whole namespace. This is the fastest way to clean up a legacy project where lang/ accumulated hundreds of orphan keys — but do the first bulk delete on a database you can restore, because there is no undo in the free version.

Composer hook for updates

Assets are published into your app, so they go stale on every package update. Automate it:

{
    "scripts": {
        "post-update-cmd": ["@php artisan translations:update --ansi"]
    }
}

Without this, a composer update silently leaves you on old JS talking to new PHP routes — which usually manifests as a blank page or 419/404 on specific Inertia requests rather than a clean error.


Gotchas and Tips

The database, not the files, is authoritative between import and export. This is the number-one source of confusion. After import, editing lang/en/messages.php by hand has no effect on what the UI shows, and the next translations:export will overwrite your hand edit. Decide which side wins and communicate it. If you're unsure, assume files lose.

--fresh overwrites. translations:import is additive; --fresh clobbers existing translations. It is the single most dangerous flag in the package and there is no confirmation prompt worth relying on. Snapshot the translation tables before running it in any shared environment.

Route exposure. The install publishes a fully functional editing UI at /translations. Default middleware is web-only. If you deploy before configuring middleware + authentication, you have shipped an unauthenticated write endpoint. Put it behind a gate, and re-check after route:cache.

Asset staleness. Any package update requires translations:update. Symptoms of forgetting: blank UI, Inertia page component not found, or a Vue-era error message if you skipped v1→v2 properly.

Version compatibility is unusually tight for a UI package. Laravel 11/12 (13 from v2.1.0), PHP 8.3+ (8.5 from v2.1.0), Inertia v2 or v3, and spatie/laravel-query-builder v7. If you're on an older Laravel or Inertia v1, this package will not install cleanly — check constraints before proposing it. v2.1.0 also changed <title inertia> to <title data-inertia>, so any custom Inertia layout that reads the title attribute may need a tweak.

Upgrading from v1 is a namespace + schema break, not a patch. Outhebox\TranslationsUI → Outhebox\Translations, Vue → React, new tables. Sequence:

composer require outhebox/laravel-translations:^2.0
php artisan translations:upgrade            # migrates v1 data
php artisan migrate
php artisan translations:install            # re-publish

If you hit "There is no active transaction" on MySQL/MariaDB, you're on v2.0.0 — the upgrade command wrapped DDL in a transaction, which MySQL implicitly commits. Fixed in v2.0.1. Upgrade rather than debugging it.

Any code referencing the v1 namespace (Outhebox\TranslationsUI\Models\..., service provider references, custom views) breaks. Grep your codebase for the old namespace before upgrading.

Key case sensitivity. v2.1.1 fixed TranslationKey parameter validation failing on case mismatches. If you're resolving keys programmatically or via route model binding, upgrade — otherwise admin.Users.title and admin.users.title behave inconsistently between the UI and the resolver.

Dot notation and nested folders are load-bearing. lang/en/admin/users.php vs lang/en/admin_users.php, and keys with literal dots in them ('v1.2.3' => '...'), are both historically fragile in this package (see 1.0.4, 1.0.5, 1.1.2, 1.1.4). Before committing to it, run a full import → export → git diff on a branch. If the diff is non-empty, you've found your edge case early enough to work around it.

JSON string-key files. Supported ("Translation Strings as Keys"), but they map differently than PHP array files. If you use lang/en.json alongside lang/en/*.php, verify both round-trip independently — mixed setups are where export ordering bugs show up.

database_connection config. You can point the package at a non-default connection, but this was broken in early 1.1.x (fixed in 1.1.5/1.1.6). On a current 2.x it works; just remember the migration needs to run on that connection too, and translations:status may look at the default if you misconfigure it. Verify by counting rows in the target DB, not by trusting the UI.

Octane. v2 fixed model event handling for Octane. On Octane, translation caches and model observers are a known class of bug — clear caches after editing and don't assume long-lived workers see fresh data mid-request.

Windows import exclusions were fixed in 1.1.8 (path separator handling). Irrelevant on Linux CI, relevant if any developer runs the import locally on Windows.

Where the free tier stops. No revision history, no AI translation, no team collaboration beyond the contributors system. If your team needs "who changed this string and when," either pay for Pro or enforce the export-and-commit pattern so git provides it. For a team of one or two developers with a handful of locales, the free tier is genuinely sufficient for day-to-day use — the value is entirely in not hand-editing lang/ files and in letting a translator work without a repo checkout.

Back up the translation tables as part of your normal DB backup. They contain content that may exist nowhere else — if you edit in the UI without exporting, the DB is the only copy.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo