laravel-auto-translations maintained by ipsumlab
Laravel Auto Translations
Composer package for Laravel >= 5.8 that automatically generates
missing translation keys in JSON format by intercepting every call to
__(), trans() and the Blade @lang() directive.
Handy during development: write your markup with
__('Save changes') and, if the key is missing, it gets added on its
own to lang/{locale}.json (or resources/lang/{locale}.json on
Laravel versions prior to 9), ready to be translated.
Features
- No changes needed to your application code: works on
__(),trans(),trans_choice()and@lang(), since they all go through the same LaravelTranslator, which this package extends. - Enabled by default only in the
localenvironment (configurable). - Ignores empty strings.
- Ignores "structured" keys already handled by Laravel's PHP
translation files (e.g.
validation.required,auth.failed,pagination.previous), so it never interferes with their resolution. - Safe writes via
flock(): no JSON corruption even with multiple concurrent requests (useful withphp artisan serve, Octane, queue workers, etc.). - Publishable config for enabling/disabling, overwriting existing keys, and choosing the target locale.
- Registers itself automatically thanks to Laravel's package
auto-discovery: no need to touch
AppServiceProvider.
Requirements
- PHP
^7.1.3|^8.0 - Laravel
>= 5.8(tested up to the most recent versions)
Installation
1. Require the package via Composer
composer require ipsumlab/laravel-auto-translations
Thanks to extra.laravel.providers in the package's composer.json,
AutoTranslatorServiceProvider is registered automatically via
Laravel's package auto-discovery. You don't need to add anything to
app/Providers/AppServiceProvider.php or to config/app.php.
If you've disabled package discovery for this package (i.e. you have a
dont-discoverentry in your app'scomposer.json), register the provider manually inconfig/app.php:'providers' => [ // ... Ipsumlab\AutoTranslations\AutoTranslatorServiceProvider::class, ],
2. (Optional) Publish the config
php artisan vendor:publish --tag=auto-translator-config
This creates config/auto-translator.php, where you can customize
whether the package is enabled, whether existing keys get
overwritten, the target locale, and which translation groups
(validation, auth, etc.) are ignored:
return [
'enabled' => env('AUTO_TRANSLATOR_ENABLED', app()->environment('local')),
'overwrite_existing' => env('AUTO_TRANSLATOR_OVERWRITE', false),
'locale' => env('AUTO_TRANSLATOR_LOCALE', null),
'ignored_groups' => ['validation', 'auth', 'passwords', 'pagination'],
];
If you skip this step, the package still works out of the box using
these same defaults (config values are merged automatically via
mergeConfigFrom()).
3. (Optional) Wire it into your own AppServiceProvider
The package works without touching any of your own provider files.
If you'd rather wire the binding yourself — for example to keep full
control over provider order, or to swap it in only under certain
conditions — you can replicate the same logic directly inside
app/Providers/AppServiceProvider.php:
use Ipsumlab\AutoTranslations\Translation\AutoTranslator;
public function register()
{
$this->app->singleton('translator', function ($app) {
$trans = new AutoTranslator($app['translation.loader'], $app['config']['app.locale']);
$trans->setFallback($app['config']['app.fallback_locale']);
return $trans;
});
}
In that case you can remove Ipsumlab\AutoTranslations\AutoTranslatorServiceProvider
from your discovered providers (via dont-discover) to avoid
registering the binding twice.
Environment variables (.env)
| Variable | Default | Description |
|---|---|---|
AUTO_TRANSLATOR_ENABLED |
true only if APP_ENV=local |
Enables/disables the package |
AUTO_TRANSLATOR_OVERWRITE |
false |
If true, overwrites keys already present in the JSON with the placeholder |
AUTO_TRANSLATOR_LOCALE |
(empty = current app locale) | Forces the locale to write missing keys into, e.g. en |
Example .env:
AUTO_TRANSLATOR_ENABLED=true
AUTO_TRANSLATOR_OVERWRITE=false
AUTO_TRANSLATOR_LOCALE=en
How it works
- The package's provider replaces Laravel's
translatorbinding withIpsumlab\AutoTranslations\Translation\AutoTranslator, a subclass ofIlluminate\Translation\Translator. - Every time
get()(used by__()andtrans()) orchoice()(used bytrans_choice()) is called, the class:- lets Laravel resolve the translation as usual;
- if the returned value matches the key itself, it means the translation is missing;
- skips the key if it's empty;
- skips the key if it belongs to an existing structured group
(
validation.*,auth.*, etc., or any group listed inignored_groups, or any group for which alang/{locale}/{group}.phpfile actually exists); - otherwise calls
JsonTranslationWriter, which openslang/{locale}.jsonwithflock(LOCK_EX), adds the missing key (initial value = the key itself, as a placeholder) and rewrites the file atomically.
- If the key already exists in the JSON file and
overwrite_existingisfalse(default), it's left untouched: translations you've already filled in by hand are never lost.
Example
{{-- resources/views/welcome.blade.php --}}
<h1>@lang('Welcome to our application')</h1>
<p>{{ __("Don't have an account?") }}</p>
On the first page load (with the package enabled), lang/en.json is
created or updated:
{
"Don't have an account?": "Don't have an account?",
"Welcome to our application": "Welcome to our application"
}
From there you can go in and fill in the actual translations on the right-hand side.
Important notes
- Performance: every missing key triggers a file open with a
lock. This is meant for development/staging use; that's why it's
enabled by default only when
APP_ENV=local. Avoid leaving it enabled in production. - Language file path: the package automatically detects whether
the app uses
resources/lang(Laravel <= 8) orlang/(Laravel >= 9, viaapp()->langPath()), including any custom path configuration. - Key source: as with all of Laravel's JSON translation
functionality, the key must be the exact string used in
__()/trans()/@lang(); slightly different strings (spacing, casing, punctuation) will generate separate entries. - Config/translation caching: if you run
php artisan config:cachein production, keep in mind that environment variables read inside the config file get "frozen" — that's fine, since the package should be disabled in production anyway.
License
MIT.