ufirst/lang-import-export
Laravel package for importing and exporting language files, making it easy to sync translations between PHP/JSON language files and database-backed translation storage. Includes configurable paths and Artisan commands for managing multilingual content.
Install the package and its auto-discovered service provider:
composer require ufirst/lang-import-export
Publish the config before you do anything else — the defaults are the thing you will most likely need to change on day one:
php artisan vendor:publish --tag=lang-import-export-config
The package exposes two artisan commands. Check them explicitly on your installed version rather than assuming names:
php artisan list | grep lang
The typical pair is an export command that walks your lang/ (or legacy resources/lang/) tree and produces a CSV whose first column is the flattened dot-notation key and whose remaining columns are locales (key,en,de,fr), and an import command that reads that same shape and writes nested PHP array files back out.
First use case is the round-trip translator handoff: export today's strings to CSV, hand the CSV to a translator who edits only the value columns, import the result back. Look first at the config file to confirm export path, the locale list, and the CSV delimiter — those three settings drive everything else.
Round-trip handoff. Export, commit the CSV to a translations/ folder (or attach it to a ticket), let the translator fill empty cells, import on merge. Because the key column is stable, translators never touch PHP and you never touch spreadsheets you did not generate.
Adding a locale. Export, add an empty pt_BR column, import. The importer will create the corresponding lang/pt_BR/*.php files. This is much less error-prone than hand-copying file trees.
Locale-scoped exports. If the commands accept a locale filter, export only the locale in flight so a translator for German never sees the French column accidentally translated. Combine with a per-locale CSV convention (de.csv, fr.csv) so diffs stay small and reviewable.
CI / pre-merge check. Run the export command in CI and git diff --exit-code against a committed CSV. Any drift means someone edited a language file directly without updating the canonical source, or a new key was added without a translation. This is the highest-leverage integration — it turns translation drift into a build failure.
Deploy-time sync. If translations live centrally (a translation platform or a shared repo), run import as a deploy step after fetching the latest CSV. Guard it with a check that the CSV is newer than the lang files, or you will silently re-import stale strings.
Reviewing diffs instead of PHP. A CSV diff shows exactly which string changed and in how many locales, in one view. Reviewing the same change across three PHP files is tedious and easy to skim past.
Programmatic use. If the package exposes a service/export class under the hood, prefer calling it from your own command or test rather than shelling out to artisan. That lets you assert "every key present in en also exists in every other locale" as a unit test.
lang/ (or commit) before the first import, and confirm whether the mode is merge or replace by reading the config.null, or key removed entirely — because the difference is visible to users in production.auth.failed) flattens cleanly, but anything that is genuinely an array in Laravel — validation rules with :attribute, passwords, pluralization arrays with one/other — may not round-trip. Test a pluralized string before trusting bulk import.resources/lang became lang/ at the project root. Confirm which directory the package reads from; older config defaults will silently export nothing on a new app.vendor/ or debug-only keys), do it via the config or a pre/post hook rather than post-processing PHP output — you will re-run this every week and want it automated.How can I help you explore Laravel packages today?