Локализация приложения Laravel
Доброго времени суток. В данной статье мы рассмотрим как создать мультиязычный сайт на Laravel. В качестве исходных данных мы будем использовать примеры из статей «Регистрация, активация и авторизация в Laravel (часть 1)» и «Регистрация, активация и авторизация в Laravel (часть 2)». Рассматривать теорию я не буду, по локализации Laravel вы можете прочитать в официальной документации. А в данной статье мы рассмотрим пример как на практике реализовать мультиязычность в Laravel.
Для упрощения нашей задачи воспользуемся пакетом mcamara/laravel-localization.
Установка пакета mcamara/laravel-localization в Laravel
Открываем файл composer.json и в раздел «require-dev» вставляем строку:
"mcamara/laravel-localization":"1.0.*"
Если у Вас Laravel 5.2.x-5.4.x, то замените версию пакета на 1.2.*
После запускаем команду:
composer update
После установки открываем файл config/app.php и добавляем провайдера:
Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider::class
А также добавляем алиас:
'LaravelLocalization' => Mcamara\LaravelLocalization\Facades\LaravelLocalization::class
Отлично установка завершена. Переходим к настройке.
Настройка пакета mcamara/laravel-localization в Laravel
Первое, что нам надо сделать это создать в папке config конфигурационный файл пакета. Для этого воспользуемся командой artisan:
artisan vendor:publish
После выполнения этой команды в папке config у нас появился файл конфигурации для данного пакета laravellocalization.php. В которм перечисляются все поддерживаемые локали. Не будем усложнять задачу и сделаем поддержку только двух локалей: ru и en. Для этого раскоментируйте строку с русской и английской локалью, а все остальные закоментируйте.
В пакете уже есть middleware, которые обеспечивают правильный переход по ссылкам, т. е. если пользователь переходит по ссылке http://lesson.loc, то пакет исправит ссылку в соответствии с локалью, например для русской локали, ссылка станет http://lesson.loc/ru
Давайте подключим эти middleware. Для этого откроем файл app/Http/Kernel.php и добавим в свойство $routeMiddleware:
'localize' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes::class, 'localizationRedirect' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter::class, 'localeSessionRedirect' => \Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect::class, 'localeViewPath' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationViewPath::class
Ну вот и все. Настройка пакета завершена. Переходим к настройке роутов.
Настройка роутов.
Вот как сейчас выглядит наш файл routes.php
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::get('/', function () { return view('welcome'); }); Route::get('auth/login', 'Auth\AuthController@getLogin'); Route::post('auth/login', 'Auth\AuthController@postLogin'); Route::get('auth/register', 'Auth\AuthController@getRegister'); Route::post('auth/register', 'Auth\AuthController@postRegister'); Route::get('auth/logout', 'Auth\AuthController@getLogout'); Route::get('auth/activate','Auth\AuthController@activate');
Отредактируем его следующим образом:
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::group( [ 'prefix' =>; LaravelLocalization::setLocale(), 'middleware' => [ 'localeSessionRedirect', 'localizationRedirect' ] ], function() { Route::get('/', function () { return view('welcome'); }); Route::get('auth/login', 'Auth\AuthController@getLogin'); Route::post('auth/login', 'Auth\AuthController@postLogin'); Route::get('auth/register', 'Auth\AuthController@getRegister'); Route::post('auth/register', 'Auth\AuthController@postRegister'); Route::get('auth/logout', 'Auth\AuthController@getLogout'); Route::get('auth/activate','Auth\AuthController@activate'); } );
Роуты настроены.
Следующим шагом будет создание папки в которой будут содержаться переводы. Более подробно читайте в документации.
Создание переводов.
В папке resources/lang создадим папку ru, а в ней создадим файл auth.php. В этом файле и будет лежать переводы для авторизации:
<?php return [ 'registration' => 'Регистрация', 'email' => 'Email', 'password' => 'Пароль', 'log_in' => 'Войти', ];
Аналогичным образом сделаем и для английской локали в папке resources/lang уже есть папка en с файлом auth.php. Исправим этот файл:
<?php return [ 'registration' => 'Registration', 'email' => 'Email', 'password' => 'Password', 'log_in' => 'Log In', ];
И все. Осталось поправить наш шаблон.
Получение перевода в шаблоне.
Для получения перевода из файла переводов используется функция trans(‘<имя файла>.<ключ>’).
Открываем наш шаблон resources/view/auth login.blade.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Авторизация</title> <link href="{{ asset('/css/bootstrap.css') }}" rel="stylesheet"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%7B%7B%20asset('%2Fjs%2Fjquery.js')%20%7D%7D%22%20type%3D%22text%2Fjavascript%22%20charset%3D%22utf-8%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%7B%7B%20asset('%2Fjs%2Fbootstrap.js')%20%7D%7D%22%20type%3D%22text%2Fjavascript%22%20charset%3D%22utf-8%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> </head> <body> <div class="container"> <nav class="navbar" role="navigation"> <ul class="nav navbar-nav"> <li class="active"> <a href="{{ url('auth/register') }}">Регистрация</a> </li> </ul> </nav> {{--Ошибки --}} @if ($errors->has()) <div class="row"> <div class="col-md-8 col-md-offset-2"> <div class="alert alert-danger" role="alert"> <button class="close" aria-label="Close" data-dismiss="alert" type="button"> <span aria-hidden="true">×</span> </button> <ul> @foreach($errors->all() as $error) <li> {{{ $error }}}</li> @endforeach </ul> </div> </div> </div> @endif {{--Успех --}} @if (Session::has('message')) <div class="row"> <div class="col-md-8 col-md-offset-2"> <div class="alert alert-success" role="alert"> <button class="close" aria-label="Close" data-dismiss="alert" type="button"> <span aria-hidden="true">×</span> </button> {{ Session::get('message') }} </div> </div> </div> @endif <form role="form" method="post" action="{{ url('auth/login') }}"> {!! csrf_field() !!} <div class="form-group"> <label for="email">Email</label> <input type="email" class="form-control" id="email" placeholder="Email" name='email'> </div> <div class="form-group"> <label for="password">Пароль</label> <input type="password" class="form-control" id="password" placeholder="Пароль" name="password"> </div> <button type="submit" class="btn btn-default">Войти</button> </form> </div> </body> </html>
И исправляем его:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Авторизация</title> <link href="{{ asset('/css/bootstrap.css') }}" rel="stylesheet"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%7B%7B%20asset('%2Fjs%2Fjquery.js')%20%7D%7D%22%20type%3D%22text%2Fjavascript%22%20charset%3D%22utf-8%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%7B%7B%20asset('%2Fjs%2Fbootstrap.js')%20%7D%7D%22%20type%3D%22text%2Fjavascript%22%20charset%3D%22utf-8%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> </head> <body> <div class="container"> <nav class="navbar" role="navigation"> <ul class="nav navbar-nav"> <li class="active"> <a href="{{ url('auth/register') }}">{{ trans('auth.registration') }}</a> </li> </ul> </nav> {{--Ошибки --}} @if ($errors->has()) <div class="row"> <div class="col-md-8 col-md-offset-2"> <div class="alert alert-danger" role="alert"> <button class="close" aria-label="Close" data-dismiss="alert" type="button"> <span aria-hidden="true">×</span> </button> <ul> @foreach($errors->all() as $error) <li> {{{ $error }}}</li> @endforeach </ul> </div> </div> </div> @endif {{--Успех --}} @if (Session::has('message')) <div class="row"> <div class="col-md-8 col-md-offset-2"> <div class="alert alert-success" role="alert"> <button class="close" aria-label="Close" data-dismiss="alert" type="button"> <span aria-hidden="true">×</span> </button> {{ Session::get('message') }} </div> </div> </div> @endif <form role="form" method="post" action="{{ url('auth/login') }}"> {!! csrf_field() !!} <div class="form-group"> <label for="email">{{ trans('auth.email') }}</label> <input type="email" class="form-control" id="email" placeholder="{{ trans('auth.email') }}" name='email'> </div> <div class="form-group"> <label for="password">{{ trans('auth.password') }}</label> <input type="password" class="form-control" id="password" placeholder="{{ trans('auth.password') }}" name="password"> </div> <button type="submit" class="btn btn-default">{{ trans('auth.log_in') }}</button> </form> </div> </body> </html>
Проверяем, что получилось. Переходим по ссылке http://lesson.loc/ru/auth/login :
Теперь перейдем по ссылке http://lesson.loc/en/auth/login :
Отлично. Все работает.
В следующей статье мы обновим нашу регистрацию и сделаем регистрацию по инвайтам.
Так, что не пропускайте выхода новых статей. Следите в Facebook, в Вконтакте, в Twiter и
в Google+
Спасибо за статью!
А как сделать так чтобы язык по умолчанию имел ссылку, например site.ua. А другие языки так: site.ua/en
Для версии Laravel 5.2 подойдёт? Как сделать чтобы локализация ru по умолчанию открывалась на основном домене https://site.com без этой приписки http://site.com/ru/ , но другие локали открывались как у вас?
Да, для Laravel 5.2 подойдет, все настраивается в конфиге
Я так понимаю язык будет храниться в сессии? А возможно ли настроить период жизни сессии, не 120 минут по умолчанию, а навсегда?
Каким образом можно языковые версии сайта сделать на поддоменах типа:
https://en.site.com
https://de.site.com
и т.д. ?
Каким образом можно сделать переключение языков, скажем через select? В версии Laravel 5.3 в файле маршрутов прописано так:
Auth::routes();
После перезагрузки страницы (перехода на другую и тд), настройки языка сбиваются, посколько мы их не ложим ни в сессию не в кукки, а вот догнать как это сделать не могу. Поможете?
Не должны сбиваться, у нас язык в адресе <название сайта>/<локализация>/…
Но тем не менее, сбиваются. У нас же по умолчанию «ru», и если допустим из example.com/en/ перейти по ссылке типа «Контакты«, то урл становится example.com/ru/contacts.
Не знаю как это связано, но ни кука ни сессия у меня не ложится, что это может быть?
Не, не, неправильно. Вы жестко прописываете ссылку, а надо либо через {{ route(‘<имя роута>‘) }}. Тут же можете посмотреть статью «Laravel: Именованные группы роутов». Или App::getLocale()/<ссылка на нужную страницу>
Огромное спасибо, привычка из Angular JS, что стэйты уже имеют свои имена))
Тут же им явно нужно задавать, спасибо еще раз. Кручу дальше, а то с фронта надо расти куда-то)))
Не за что. Удачи в освоении Laravel )
Спасибо!
Подскажите, может у кого получилось сделать такую задачку:
Перевести элементы вызываемые из базы в форму селект
{!! Form::select(‘posts’, $posts, 1,[‘class’ => ‘form-control’]) !!}
Перевести элементы в контроллере и передать их уже переведенными.
Спасибо все работает через цикл внутри контроллера, я думал это не возможно, а на самом деле все норм