Introducing laravel-translation
Keeping track of translations or strings in general are a recurring source of friction. Developers don't want to play copy editor, and translators don't want to touch PHP arrays. laravel-translation moves the source of truth to a Google Sheet and keeps your Laravel files in lock-step via a push/pull workflow. The Google Sheet becomes a version controlled source of truth, which can be populated from the codebase and then easily pulled back in when content is accurate.
What it does
- 🔄 Bi-directional sync — push translations to Google Sheets and pull updates back.
- ✏️ Surgical pull — updates land in place via AST manipulation; comments, blank lines, indentation, and quote styles are preserved.
- 🌍 Multi-language by default —
translations:pushwith no argument syncs every locale underlang/. - 🔤 Translator-friendly sheets — non-English sheets show the English source alongside each translation.
- 🔐 Service Account authentication — simple, secure auth using a Google service account.
- 🗂️ Local JSON backups — sheet snapshots written to a gitignored folder before every push.
Why AST instead of regeneration
The original version of this package regenerated translation files from scratch on every pull. That worked, but it nuked comments, blank lines, and any custom formatting. Switching to AST manipulation (via nikic/php-parser) means pull only touches the string values whose keys already exist in your file — nothing else moves.
Sheet layout
Each locale gets its own tab named Translations - {locale}:
- Source locale (en): Column A is the key, B is the original value, C is the editor's revised wording.
- Other locales (fr, es, …): Column A is the key, B is the English source, C is the translation. Rows with an empty C are skipped on pull, falling through to Laravel's
fallback_locale.
Installation
The package lives at paper-leaf-tech/laravel-translation.
"repositories": [
{
"type": "github",
"url": "[email protected]:paper-leaf-tech/laravel-translation.git"
}
]
composer require paper-leaf-tech/laravel-translation --dev
php artisan vendor:publish --tag=laravel-translation-config
The workflow
- Initial push —
php artisan translations:pushfrom a project withlang/en/(and optionally other locales). Each locale gets its own tab. - Translators work in the sheet — non-source tabs show English in Column B and let translators fill Column C.
- Pull —
php artisan translations:pullwrites Column C back to the matchinglang/{locale}/*.phpfiles. Untranslated rows are left alone. - Re-push when you add new keys to your code.
Guardrails on pull
Pull intentionally won't create files, append new keys, or touch non-string values. Anything unexpected gets surfaced as a warning rather than silently rewriting your code:
⚠ Skipped 1 new key(s) in lang/en/auth.php (add to code first, then re-pull):
- auth.captcha.invalid