tooinfinity / lingua
Zero-config localization for Laravel 12 with Inertia.js and React
Fund package maintenance!
tooinfinity
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/tooinfinity/lingua
Requires
- php: ^8.4
- laravel/framework: ^11.0|^12.0
Requires (Dev)
- inertiajs/inertia-laravel: ^2.0.19
- laravel/pint: ^1.24.0
- orchestra/testbench: ^9.16|^10.9.0
- pestphp/pest: ^4.1.0
- pestphp/pest-plugin-type-coverage: ^4.0.2
- phpstan/phpstan: ^2.0 <2.1.34
- rector/rector: ^2.3.1
- symfony/var-dumper: ^7.3.3
README
⚠️ Under Development: This package is currently under active development and is not ready for production use.
Share Laravel translations with your Inertia.js + React frontend.
Quick Start
1. Install
composer require tooinfinity/lingua php artisan lingua:install
This installs the Laravel package, publishes the config, and installs the React package (@tooinfinity/lingua-react).
2. Configure Locales
Edit config/lingua.php:
'locales' => ['en', 'fr', 'es'],
3. Middleware
The middleware is auto-registered to the web group by default. No action needed for most apps.
To disable auto-registration and add manually:
// config/lingua.php 'middleware' => [ 'auto_register' => false, ], // bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ \TooInfinity\Lingua\Http\Middleware\LinguaMiddleware::class, ]); })
4. Create Translations
lang/
├── en/
│ └── messages.php
└── fr/
└── messages.php
// lang/en/messages.php return [ 'welcome' => 'Welcome!', 'greeting' => 'Hello, :name!', ]; // lang/fr/messages.php return [ 'welcome' => 'Bienvenue!', 'greeting' => 'Bonjour, :name!', ];
5. Use in React
import { useTranslations } from '@tooinfinity/lingua-react'; function Welcome() { const { __, locale, locales } = useTranslations(); return ( <div> <h1>{__('messages.welcome')}</h1> <p>{__('messages.greeting', { name: 'John' })}</p> <p>Current: {locale}</p> </div> ); }
Locale Switching
import { router } from '@inertiajs/react'; import { useTranslations } from '@tooinfinity/lingua-react'; function LocaleSwitcher() { const { locale, locales } = useTranslations(); const switchLocale = (newLocale: string) => { router.post('/locale', { locale: newLocale }); }; return ( <div> {locales.map((loc) => ( <button key={loc} onClick={() => switchLocale(loc)} disabled={loc === locale} > {loc.toUpperCase()} </button> ))} </div> ); }
Translation Groups (Optional)
Load only the translations needed for a specific request by passing group names to the middleware. When no groups are provided, Lingua shares all translations.
Route::middleware(['web', 'lingua:common,validation'])->get('/dashboard', function () { // ... });
You can also load specific groups manually via Lingua::translationsFor(['common', 'validation']).
API Reference
useTranslations() Hook
const { __, locale, locales, direction, isRtl } = useTranslations(); __('messages.welcome') // "Welcome!" __('messages.greeting', { name: 'John' }) // "Hello, John!"
| Property | Type | Description |
|---|---|---|
__ |
function |
Translation function |
locale |
string |
Current locale |
locales |
string[] |
Supported locales |
direction |
'ltr' | 'rtl' |
Text direction |
isRtl |
boolean |
Is RTL locale |
Facade
use TooInfinity\Lingua\Facades\Lingua; Lingua::getLocale(); // Get current locale Lingua::setLocale('fr'); // Set locale (optionally persists cookie) Lingua::supportedLocales(); // Get supported locales Lingua::translations(); // Get all translations (missing keys fall back to default locale)
Fallback Locale Behavior
When a translation key is missing in the current locale, Lingua automatically fills it from the default locale. This applies to:
- PHP translation groups loaded via
Lingua::translationGroup()andLingua::translations() - JSON translations loaded via
Lingua::translations()whentranslation_driverisjson
If the current locale already matches the default locale, no fallback merge occurs.
// config/lingua.php 'default' => 'en',
// lang/en/auth.php return [ 'login' => 'Login', 'logout' => 'Logout', ]; // lang/fr/auth.php return [ 'login' => 'Connexion', ]; Lingua::setLocale('fr'); // 'logout' comes from the default locale Lingua::translationGroup('auth'); // ['login' => 'Connexion', 'logout' => 'Logout']
Routes
| Method | URI | Description |
|---|---|---|
| POST | /locale |
Switch locale |
Note: The route prefix can be configured via
config('lingua.routes.prefix').
Translation File Formats
Lingua supports both PHP and JSON translation files. Configure the driver in config/lingua.php:
'translation_driver' => 'php', // or 'json'
PHP Translations (Default)
PHP translations are organized in groups (files) under lang/{locale}/:
lang/
├── en/
│ ├── messages.php
│ └── validation.php
└── fr/
├── messages.php
└── validation.php
// lang/en/messages.php return [ 'welcome' => 'Welcome!', 'greeting' => 'Hello, :name!', ];
Shared to React as:
{
"messages": {
"welcome": "Welcome!",
"greeting": "Hello, :name!"
},
"validation": { ... }
}
Access in React: __('messages.welcome')
JSON Translations
JSON translations use a flat key-value structure in lang/{locale}.json:
lang/
├── en.json
└── fr.json
// lang/en.json { "Welcome!": "Welcome!", "Hello, :name!": "Hello, :name!", "auth.login": "Login", "auth.logout": "Logout" }
Shared to React as-is (flat structure):
{
"Welcome!": "Welcome!",
"Hello, :name!": "Hello, :name!",
"auth.login": "Login",
"auth.logout": "Logout"
}
Access in React: __('Welcome!') or __('auth.login')
Tip: JSON translations are ideal for simple apps or when using Laravel's
__()helper with literal string keys.
Advanced
Custom Controller
// config/lingua.php 'controller' => \App\Http\Controllers\LocaleController::class,
namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Validation\Rule; use TooInfinity\Lingua\Lingua; class LocaleController { public function __invoke(Request $request, Lingua $lingua) { $validated = $request->validate([ 'locale' => ['required', 'string', Rule::in($lingua->supportedLocales())], ]); $lingua->setLocale($validated['locale']); return redirect()->route('dashboard'); } }
License
MIT License. See LICENSE.md.