On this page
Overview
Laravel Localizer is the backend half of a translation workflow for Laravel apps with a JavaScript frontend. It scans your code for translation keys, keeps the language files in lang/ in sync, and exports every locale as a TypeScript file that your React or Vue app can import. A middleware picks the visitor’s locale and shares it with Inertia, so the frontend always knows the current language and text direction.
Laravel stays the single source of truth for strings. The frontend reads them through a small hook or composable from the matching npm package: Laravel Localizer React or Laravel Localizer Vue. Localizer is built by the DevWizard core team and is MIT licensed.
Features
- Key scanning: finds
__(),trans()andlang()calls across PHP, Blade, JavaScript, TypeScript and Vue files and adds the missing keys to your language files. - TypeScript generation: one typed file per locale plus an index with
translations,getAvailableLocales(),hasLocale()andgetTranslations(). - Auto-translation of missing values with Google Translate, run as a queued job (needs an optional package).
LocalizerMiddlewarewith a fixed locale detection order and Inertia shared props.- Right-to-left support through a
dirvalue per locale. - A
Localizerfacade to create, rename, delete and edit locales and keys from code. - Interactive installer that can also set up the npm package for your framework.
- In-memory caching of loaded translations.
Requirements
- PHP 8.3 or newer.
- Laravel 11, 12 or 13.
- Inertia.js with the Laravel adapter if you want the shared locale props (the middleware skips sharing when Inertia is absent).
- Optional:
stichoza/google-translate-phpforlocalizer:translate.
Installation
composer require devwizardhq/laravel-localizerRun the interactive installer. It publishes the config, creates locale files, registers the middleware and generates the first TypeScript files:
php artisan localizer:installPass --framework=react or --framework=vue to choose the frontend package without a prompt, and --force to overwrite existing files.
To set things up by hand, publish the config and the middleware stub:
php artisan vendor:publish --tag="laravel-localizer-config"
php artisan vendor:publish --tag="laravel-localizer-middleware"Then append the published middleware to the web group in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\App\Http\Middleware\LocalizerMiddleware::class,
]);
})Finally install the frontend package: React or Vue.
Configuration
Everything lives in config/localizer.php:
| Key | Default | Purpose |
|---|---|---|
default |
env('APP_LOCALE', 'en') |
Locale used when nothing else matches |
fallback |
env('APP_FALLBACK_LOCALE', 'en') |
Fallback locale value; the package code itself does not read it, so use Laravel’s own app.fallback_locale for runtime fallback |
available |
en, ar, bn, es, fr, de | Locales exposed to the frontend, each with label, flag and dir |
path |
lang_path() |
Where language files are read and written |
typescript_output_path |
resource_path('js/lang') |
Where generated TypeScript files go |
scan.include |
app, resources, routes |
Directories scanned for translation keys |
scan.exclude |
bootstrap, lang, public, storage, vendor, node_modules |
Directories skipped while scanning |
scan.extensions |
php, blade.php, js, jsx, ts, tsx, vue |
File types scanned |
A minimal locale list with a right-to-left language:
'available' => [
'en' => ['label' => 'English', 'flag' => '🇬🇧', 'dir' => 'ltr'],
'ar' => ['label' => 'Arabic', 'flag' => '🇸🇦', 'dir' => 'rtl'],
],Usage
The normal loop has three steps. Scan for keys, optionally translate them, then generate the frontend files.
php artisan localizer:sync --all
php artisan localizer:generate --allKeys without a dot, such as welcome, are stored in lang/en.json. Keys with a dot, such as validation.required, are stored in lang/en/validation.php.
Each locale becomes a file like resources/js/lang/en.ts that exports a constant object and a TranslationKeys type. An index.ts exports every locale and a combined translations registry.
The frontend packages do the rest: they run localizer:generate from a Vite plugin whenever a language file changes, and read the generated files through useLocalizer(). See React and Vue for the hook setup.
Locale detection
LocalizerMiddleware tries these sources in order and uses the first one that is a configured locale:
- The
localequery parameter. - The
X-Localerequest header. - The locale stored in the session.
getLocale()on the authenticated user, if the model defines it.- The browser
Accept-Languageheader. config('localizer.default').
The chosen locale is set with App::setLocale(), stored in the session and shared with Inertia as a locale prop with current, dir and available.
Deployment
Generated TypeScript files are git-ignored by the installer, so regenerate them before building the frontend:
php artisan localizer:generate --all
pnpm buildAPI Reference
Artisan commands
| Command | Options | Description |
|---|---|---|
localizer:install |
--framework=, --force |
Interactive setup |
localizer:sync |
--locales=*, --all |
Scan code for keys and add missing ones to language files |
localizer:translate |
--source=, --target= |
Translate missing values from one locale to another |
localizer:generate |
--locales=*, --all |
Write TypeScript files |
Without --all or --locales, the sync and generate commands ask which locales to use.
Localizer facade
DevWizard\Localizer\Facades\Localizer proxies the Localizer class.
| Method | Description |
|---|---|
create($locale, $fromLocale = null) |
Create a locale, optionally copying another |
rename($oldLocale, $newLocale, $fromLocale = null) |
Rename a locale |
delete($locale) |
Delete a locale |
get($locale) |
All translations, JSON and PHP combined |
getJson($locale) |
JSON translations only |
getAllPhpTranslations($locale), getPhpTranslations($locale, $file) |
Read PHP translation files |
set($key, $value = null, $locale = null) |
Set a JSON key |
setPhp($key, $value, $locale = null) |
Set a dotted PHP key |
bulkSet($items, $locale = null), bulkSetPhp($file, $items, $locale = null) |
Set many keys at once |
unset($key, $locale = null), unsetPhp($key, $locale = null) |
Remove a key |
translate($fromLocale, $toLocale) |
Queue an auto-translation job |
availableLocales() |
Locales found on disk |
Examples
Add a locale cloned from English, then fill in a few strings:
use DevWizard\Localizer\Facades\Localizer;
Localizer::create('fr', fromLocale: 'en');
Localizer::bulkSet(['hello' => 'Bonjour', 'goodbye' => 'Au revoir'], 'fr');
Localizer::setPhp('validation.required', 'Ce champ est obligatoire', 'fr');Machine-translate a new locale. Install the optional package first, and run a queue worker because the translation is a queued job:
composer require stichoza/google-translate-php
php artisan localizer:translate --source=en --target=frLet each user keep a preferred language by defining getLocale() on the model. The middleware uses it after the session check:
public function getLocale(): string
{
return $this->preferred_locale;
}FAQ & Troubleshooting
The frontend shows raw keys instead of text. Generate the files with php artisan localizer:generate --all and confirm the frontend initialises window.localizer. The setup is covered in the React and Vue docs.
The locale never changes. The locale must be listed in available in config/localizer.php. Values that are not listed are ignored by the middleware, and the detection order means an earlier source such as the query string wins over the session.
localizer:translate throws an error about GoogleTranslate. Install stichoza/google-translate-php. The translation runs as a queued job, so start a worker.
A key is missing after localizer:sync. Only literal keys in __(), trans() and lang() calls inside scan.include directories and the configured extensions are found. Keys built from variables cannot be detected.
Do I commit the generated TypeScript? The installer git-ignores them. Regenerate during deployment before the frontend build.
Changelog & Support
Release history is in the CHANGELOG and on the GitHub releases page. Open bugs and feature requests in GitHub issues. Source: DevWizardHQ/laravel-localizer. For help with multilingual products, the DevWizard team takes project contracts and monthly retainers through the contact page.