Nastavení cookies

Používám cookies

Nezbytné cookies zajišťují správné fungování webu a ukládají vaši volbu. Se souhlasem mohu použít také funkční cookies pro zapamatování vzhledu a interaktivní mřížky a analytické cookies pro měření návštěvnosti.

Volitelné cookies můžete přijmout najednou, odmítnout nebo si je nastavit podle kategorií. Souhlas lze později změnit; podrobnosti najdete v zásadách cookies.

PavelZanek.com
article Článek

20. listopadu 2021

Lokalizace Laravel aplikace

Naučte se, jak lokalizovat Laravel aplikaci. Tento průvodce pokrývá vše od nastavení jazykových souborů až po přepínání jazyků.

Lokalizace Laravel aplikace

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 CS_CONTENT continues from where it was cut:

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:

Výsledek - Laravel lokalizace - Česká verze

Anglická verze:

Výsledek - Laravel lokalizace - 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;

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 () {
            Route::get('/user/profile', [UserProfileController::class, 'show'])
                        ->name('profile.show');

            if (Jetstream::hasApiFeatures()) {
                Route::get('/user/api-tokens', [ApiTokenController::class, 'index'])->name('api-tokens.index');
            }

            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 () {
        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();
}
...

Kategorie

alternate_email

Zůstaňme v kontaktu

Odebírejte novinky ze světa Laravelu a infrastruktury přímo do své schránky.