Multi-locale support BETA
English is the most widely used language on the web, but it's far from the only one. Supporting multiple languages helps you reach a global audience. Leaf Lingo provides an official solution for adding multi-language support to your Leaf applications, without restructuring your code or adding middleware.
Installation
You can easily install Lingo using Composer.
leaf install lingocomposer require leafs/lingoOnce installed, Lingo automatically sets up everything you need for multi-language support. Define your translation files in the app/locales folder using language codes like en.yml and de.yml, or specific locales like en_US.yml and pt_BR.yml.
# app/locales/fr.yml
hero.title: "Bonjour le monde"Now you can use the lingo() helper function to translate strings in your views or controllers:
$heroTitle = lingo('hero.title'); // "Bonjour le monde"In Blade templates, use it the same way:
<h1>@lingo('hero.title')</h1> <!-- "Bonjour le monde" -->Lingo Modes
By default, Lingo uses routes for the translation strategy which means that if you have routes like this in your Leaf app:
app()->get('/home', function() {
return response()->render('home');
});
app()->get('/about', function() {
return response()->render('about');
});Lingo automatically creates routes for each language:
/en/home
/fr/home
/en/about
/fr/aboutThe routes are generated based on your translation files. If you have de.yml and fr.yml, Lingo creates routes for /de/* and /fr/*. It also redirects requests to base paths (like /home) to the default language route (e.g., /en/home). Set your default language in .env with APP_LOCALE=....
Header Mode Experimental
Use header mode when building an API that needs to support multiple languages via the Accept-Language header. In this mode, Lingo doesn't create language-specific routes. Instead, it determines the language from the Accept-Language header sent by the client.
For example, a request with Accept-Language: fr uses French translations, even though the route isn't prefixed with /fr.
To enable header mode, you need to set the following in your .env file:
LOCALES_STRATEGY=headerSession Mode Experimental
Use session mode when you want users to switch languages without changing the URL. Lingo stores the selected language in the user's session, so all subsequent requests use that language. Like header mode, session mode doesn't create language-specific routes.
To enable session mode, you need to set the following in your .env file:
LOCALES_STRATEGY=sessionSwitching Locales
Lingo uses the same approach for switching locales across all modes. Use the lingo()->setCurrentLocale() method to create a route that handles locale switching. The method switches the current locale based on your configured strategy (routes or session). In header mode, this method has no effect since the locale is determined by the Accept-Language header.
Here is an example of how to create a route for switching locales:
app()->post('/language/switch', function() {
$locale = request()->get('locale');
return lingo()->setCurrentLocale($locale);
});setCurrentLocale() will automatically redirect the user to the expected location based on the strategy you are using.
Switcher Templating
Create a simple language switcher in your views. Here's an example in Blade:
<form method="post" action="/language/switch">
<select name="locale" onchange="this.form.submit()">
@foreach(lingo()->getAvailableLocalesWithNames() as $locale => $name)
<option value="{{ $locale }}" {{ lingo()->getCurrentLocale() === $locale ? 'selected' : '' }}>{{ $name }}</option>
@endforeach
</select>
</form>
<h1>@lingo('welcome.title')</h1>getAvailableLocalesWithNames() returns an array with locale codes as keys and language names as values, making it easy to create dropdowns or other UI elements:
[
'en_US' => 'English (US)',
'es' => 'Español',
'it' => 'Italiano',
'zh' => '中文',
'zh_CN' => '简体中文',
'fr_FR' => 'Français (France)',
'de_DE' => 'Deutsch (Deutschland)',
]Use getAvailableLocales() if you only need the locale codes:
[
'en_US',
'es',
'it',
'zh',
'zh_CN',
'fr_FR',
'de_DE',
]You now have everything you need to display translations and switch languages in your Leaf application with Lingo!
Current Locale Info
You can retrieve information about the current locale using the following methods:
lingo()->getCurrentLocale(): Returns the current locale code (e.g.,en_US,de, ...).lingo()->getCurrentLanguage(): Returns the current language code (not including region, e.g.,en,de, ...).lingo()->getDefaultLocale(): Returns the default locale code as defined in your.envfile or configuration.lingo()->is(): Checks if the current locale matches a given locale code.
Translation Parameters
Lingo supports translation parameters for inserting dynamic values into translations. Define placeholders in your translation strings using the or $parameterName syntax:
# app/locales/en.yml
greeting.message: "Hello, {{ name }}! Welcome to our website."
farewell.message: "Goodbye, $name! See you next time."You can then pass an associative array of parameters to the lingo() function to replace the placeholders with actual values:
$message1 = lingo('greeting.message', ['name' => 'John']); // "Hello, John! Welcome to our website."
$message2 = lingo('farewell.message', ['name' => 'John']); // "Goodbye, John! See you next time."Multi-language routes Router Mode Only
Some applications need multi-language routes where URL segments are translated based on the current locale. For example, /en/products could be /fr/produits in French. Lingo supports this through Leaf's route parameters. Define your routes as usual, then pass route variants as an array:
app()->get('/products', [
'lingo.routes' => [
'en' => '/products',
'fr' => '/produits',
'de' => '/produkte',
],
'ProductsController@index'
]);Leaf automatically handles routing based on the current locale. Switching locales redirects users to the appropriate translated route without any additional handling.
Note that this feature only works with Lingo's route-based strategy.
Disabling Auto-Route Generation Router Mode Only
By default, Lingo's route-based strategy generates localized routes for all your routes. To disable this for specific routes, set lingo.routes to false:
app()->get('/contact', [
'lingo.routes' => false,
'ContactController@index'
]);This is useful for routes that shouldn't be localized, like API endpoints or routes that should be language-independent.r
Lingo URL Router Mode Only
When using Lingo's route-based strategy, you can generate localized URLs using the lingo()->url() method. This method takes a path as an argument and returns the localized URL based on the current locale.
$url = lingo()->url('home'); // e.g., "/en/home" or "/fr/home"In non-route-based strategies, this method returns the path unchanged.
Using Variants
The variants() method lets you define different string variants based on the current locale. This is useful for localizing routes or strings outside your translation files:
$localizedRoute = lingo()->variants([
'en' => '/products',
'fr' => '/produits',
'es' => '/productos',
]);
// e.g., "/en/products" or "/fr/produits" or "/es/productos"You can also use variants for text, URLs, or other strings:
$greeting = lingo()->variants([
'en' => 'Hello',
'fr' => 'Bonjour',
'es' => 'Hola',
]);
// e.g., "Hello" or "Bonjour" or "Hola"For most text, translation files are better because they're more organized and maintainable. Use variants() for one-off translations or localized routes.
