Níže uvedený návod popisuje jednoduchou lokalizaci Laravel aplikace (tedy překlady pouze částí aplikace, nikoliv překlad obsahu stránek uloženého v databázi či lokalizace URL adres). Návod se tedy věnuje, jak nastavit překlady řetězců objevujících se v šabloně Laravel aplikace.
Testováno ve verzi: Laravel 8
Stack: Jetstream / Livewire + Blade/Tailwind CSS, ale prakticky se změnami na straně front endu lze použít kdekoliv
Dokumentace: https://laravel.com/docs/8.x/localization
Logika
Logika je poměrně jednoduchá, není potřeba žádného zásahu do databáze.
Nastavení jazyků
config/app.php:
...
'locales' => [
'en' => 'English',
'cs' => 'Czech',
],
...
Middleware Language
app/Http/Middleware/Language.php:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;
class Language
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
App::setLocale($request->language);
URL::defaults(['language' => $request->language]);
$request->route()->forgetParameter('language');
return $next($request);
}
}
Přidání middlewaru do kernelu
app/Http/Kernel.php:
...
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\Language::class, // Localization
],
...
];
...
Routy ve web.php
routes/web.php:
...
Route::group([
'prefix' => "{language}",
'where' => ['language' => '[a-zA-Z]{2}']
], function () {
...
});
...
Kontroler LanguageController.php
app/Http/Controllers/LanguageController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;
class LanguageController extends Controller
{
public function switchLang(Request $request, $lang)
{
// $urlParts[1] == current lang
$urlParts = explode('/', str_ireplace(array('http://', 'https://'), '', url()->previous()));
$newUrl = str_replace(
'/' . $urlParts[1] . '/',
'/' . $lang . '/',
url()->previous()
);
App::setLocale($lang);
URL::defaults(['language' => $lang]);
return redirect()->to($newUrl);
}
}
Přidání routy kontroleru do web.php
routes/web.php:
...
Route::get('lang/{lang}', [App\Http\Controllers\LanguageController::class, 'switchLang'])->name('langSwitcher');
...
RouteServiceProvider.php
app/Providers/RouteServiceProvider.php:
...
public const DASHBOARD = '/en/dashboard';
...
Vytvoření Language switcheru
Příklad pro použití ve stacku: Laravel, Jetstream – Livewire + Blade, Tailwindcss
resources/views/navigation-menu.blade.php:
Desktop
...
<!-- Language Dropdown -->
<div class="ml-3 relative">
<x-jet-dropdown align="right" width="48">
<x-slot name="trigger">
<span class="inline-flex rounded-md">
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition">
@lang(config('app.locales')[App::getLocale()])
<svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</span>
</x-slot>
<x-slot name="content">
<!-- Language Switcher -->
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Select language') }}
</div>
@foreach (config('app.locales') as $lang => $language)
@if ($lang !== App::getLocale())
<x-jet-dropdown-link href="{{ route('langSwitcher', $lang) }}">
@lang($language)
</x-jet-dropdown-link>
@endif
@endforeach
</x-slot>
</x-jet-dropdown>
</div>
...
Responzivní verze
...
<div class="mt-3 space-y-1">
<div class="border-t border-gray-200"></div>
<div class="block px-4 py-2 text-xs text-gray-400">
{{ __('Select language') }}
</div>
@foreach (config('app.locales') as $lang => $language)
@if ($lang !== App::getLocale())
<x-jet-responsive-nav-link href="{{ route('langSwitcher', $lang) }}">
@lang($language)
</x-jet-responsive-nav-link>
@endif
@endforeach
<div class="border-t border-gray-200"></div>
</div>
...
Doplnění překladů
Například resources/lang/cs.json:
{
"Dashboard": "Nástěnka",
"Select language": "Vyberte jazyk",
"Czech": "Čeština",
...
}
Výsledek
Česká verze:
Anglická verze:
Tip
Pokud používáte Jetstream spolu s Livewire jako v příkladu a chcete defaultní routy lokalizovat, pak musíte udělat ještě několik menších úprav.
Ze složky /vendor/jetstream/routes/ překopírujte routy k Vašim routám. Soubor pak může vypadat následovně (routes/web.php):
<?php
use Illuminate\Support\Facades\Route;
use Laravel\Jetstream\Http\Controllers\CurrentTeamController;
use Laravel\Jetstream\Http\Controllers\Livewire\ApiTokenController;
use Laravel\Jetstream\Http\Controllers\Livewire\PrivacyPolicyController;
use Laravel\Jetstream\Http\Controllers\Livewire\TeamController;
use Laravel\Jetstream\Http\Controllers\Livewire\TermsOfServiceController;
use Laravel\Jetstream\Http\Controllers\Livewire\UserProfileController;
use Laravel\Jetstream\Http\Controllers\TeamInvitationController;
use Laravel\Jetstream\Jetstream;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('lang/{lang}', [App\Http\Controllers\LanguageController::class, 'switchLang'])->name('langSwitcher');
Route::get('/', function () {
return redirect()->route('login');
});
Route::group([
'prefix' => "{language}",
'where' => ['language' => '[a-zA-Z]{2}']
], function () {
Route::group(['middleware' => config('jetstream.middleware', ['web'])], function () {
if (Jetstream::hasTermsAndPrivacyPolicyFeature()) {
Route::get('/terms-of-service', [TermsOfServiceController::class, 'show'])->name('terms.show');
Route::get('/privacy-policy', [PrivacyPolicyController::class, 'show'])->name('policy.show');
}
Route::group(['middleware' => ['auth:sanctum', 'verified']], function () {
// User & Profile...
Route::get('/user/profile', [UserProfileController::class, 'show'])
->name('profile.show');
// API...
if (Jetstream::hasApiFeatures()) {
Route::get('/user/api-tokens', [ApiTokenController::class, 'index'])->name('api-tokens.index');
}
// Teams...
if (Jetstream::hasTeamFeatures()) {
Route::get('/teams/create', [TeamController::class, 'create'])->name('teams.create');
Route::get('/teams/{team}', [TeamController::class, 'show'])->name('teams.show');
Route::put('/current-team', [CurrentTeamController::class, 'update'])->name('current-team.update');
Route::get('/team-invitations/{invitation}', [TeamInvitationController::class, 'accept'])
->middleware(['signed'])
->name('team-invitations.accept');
}
});
});
Route::group(['middleware' => ['auth:sanctum', 'verified']], function () {
// Dashboard
Route::get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
});
});
Pokud bychom upravili například routu pro zobrazení profilu, například takto (routes/web.php):
...
// Old value: /user/profile
Route::get('/profile', [UserProfileController::class, 'show'])->name('profile.show');
...
Pokud uděláme výše uvedenou změnu, zobrazení profilu bude dostupné jak na naší routě /profile, tak i můžeme využít výchozí routu /user/profile (načítanou z package – laravel/jetstream/routes/livewire.php). Pokud chceme výchozí routy vypnout, pak musíme upravit JetsreamServiceProvider.php (app/Providers/JetsreamServiceProvider.php).
...
public function register()
{
Jetstream::ignoreRoutes();
}
...