Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Страницы 1
Привет!
Решил накатать статейку с кодом, как прикрутил локализации к L5.
ТЗ:
1) Адреса вида site.com/en/any-segment?any=argument определяют локализацию
2) Адрес без указания локализации уводит на ссылку с указанием локали, это СЕО-затычка, чтобы небыло двух одинаковых страниц по разным языкам.
3) Смена длкали через ссылку site.com/jp/set-language (language вместо locale понятней обывателю)
Побочный (не сильно приятный) эффект:
Все ссылки приходится генерить в шаблонах и в коде рукаами вида Request::secure( '/'.$locale )
(Возможно когда-нить поправлю код ядра, либо напишу какой-нить враппер, но я ленивый )
Реализация:
1. Установить пакет
"mcamara/laravel-localization": "1.0.*",
2. Исправить существующие файлы:
Публикуем конфиг нового пакета
/config/laravellocalization.php
Исправляем конфиг таким обазом (раскомментировать), чтобы включить язык 'en' и 'ru'
Отключаем:
'useAcceptLanguageHeader' => false, // мы используем наше значение конфига /config/app.php: locale=>en)
'useSessionLocale' => false, // мы берём локаль из адреса
'useCookieLocale' => false, // - отключаем чтобы не перебивало, когда меняем локаль (пояснение в конце)
/config/app.php
'locale' => 'en'
/app/Http/routes.php
Route::group(
[
'prefix' => LaravelLocalization::setLocale(),
'middleware' => 'setlanguage'
],
function()
{
// HomeController
Route::get( 'home', [ 'as' => 'home', 'uses' => 'HomeController@getIndex' ] );
Route::get( '/', [ 'as' => 'home', 'uses' => 'HomeController@getIndex' ] );
Route::get( 'about', [ 'as' => 'about', 'uses' => 'HomeController@getAbout' ] );
// SettingsController
Route::get( 'set-language', [ 'as' => 'set-language', 'uses' => 'SettingsController@setLocale' ] );
// AuthController
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
}
);
/app/Http/Kernel.php
protected $routeMiddleware = [
// существующий код...
// лосле локализаций переопределяем локаль
'setlanguage' => 'App\Http\Middleware\SetLanguage',
3. Добавить новые файлы
/app/Http/Middleware/SetLanguage.php
<?php namespace App\Http\Middleware;
use Closure;
use Auth;
use LaravelLocalization;
use Config;
use Redirect;
class SetLanguage
{
public function handle($request, Closure $next)
{
$addrLocale = $request->segment(1);
$locales = LaravelLocalization::getSupportedLocales();
$locales = array_keys( $locales );
$defaultLocale = Config::get('app.locale');
if ( !Auth::guest() )
{
// ставим локаль из настроек пользователя, если она разрешена
$userLocale = Auth::user()->locale;
if ( in_array( $userLocale, $locales ) )
{
LaravelLocalization::setLocale($userLocale);
}
}
else
{
// ставим локаль из адреса, если она разрешена
if ( in_array( $addrLocale, $locales ) )
{
LaravelLocalization::setLocale($addrLocale);
}
else
{
// иначе отправляем на адрес с локалью по умолчанию
return Redirect::secure( '/'.$defaultLocale );
}
}
return $next($request);
}
}
/app/Http/Controllers/SettingsController.php
<?php namespace App\Http\Controllers;
use View;
use Request;
use Config;
use Auth;
use Redirect;
use LaravelLocalization;
use URL;
class SettingsController extends Controller
{
public function __construct()
{
// во всех конструкторах необходимо кинуть локаль и список поддерживаемых локалей в шаблонизатор, чтобы реализовать переключатель языка. Для примера бросил здесь, но лучше где-нить в Controller::constructor'е
View::share( 'locale', Lang::getLocale() );
View::share( 'locales', LaravelLocalization::getSupportedLocales() );
}
public function setLocale()
{
$addrLOCALE = Request::segment(1);
$cfgLOCALE = Config::get('app.locale');
$segments = Request::segments();
$locales = LaravelLocalization::getSupportedLocales();
$locales = array_keys( $locales );
$setLocale = null;
if ( in_array( $addrLOCALE, $locales ) )
{
// локаль в адресе действительна
// ставим её
$setLocale = $addrLOCALE;
}
else
{
// локаль в адресе НЕ действительна
// ставим дефолтную
$setLocale = $cfgLOCALE;
}
if ( Auth::check() )
{
// пользователь авторизован
// сохраняем в пользователя
$user = Auth::getUser();
$user->locale = $setLocale;
$user->save();
}
// ставим локаль в адрес
if ( !empty( $segments ) && $segments[1] == 'set-language' )
{
// ПОПЫТКА (!) уйти туда же откуда и пришли, заменив язык в адресе
// TODO: не совсем уместно, но на уровне REST'a проблем возникнуть не должно
$lc = implode('|',$locales);
$back = URL::previous();
$back = preg_replace( "#/([".$lc."].)#iu", "/{$setLocale}", $back );
return Redirect::secure( $back );
}
else
{
// простой переход на главную страницу
return Redirect::secure( '/'.$setLocale );
}
}
}
/resources/lang/en/*
остаётся как есть
/resources/lang/ru/*
копируем 'en' и переводим руками
========================
Шаблон переключателя локали
@if(!empty( $locales ))
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
<i class="fa fa-cog"></i>
{{trans('nav.sitelanguage')}}
</a>
<ul class="dropdown-menu" role="menu">
@foreach($locales AS $lc=>$ln)
<li class="@if($locale==$lc) active @endif">
<a href="/{{$lc}}/set-language">
<i class="fa @if($locale==$lc) fa-check-square-o @else fa-square-o @endif"></i>
<span class="">{{$ln['native']}}</span>
</a>
</li>
@endforeach
</ul>
</li>
@endif
При этом если установите css-спрайт с флагами, то сможете заменить голову меню на [Флаг] [Имя Языка] чтобы было красиво
Как-то так...
Пробуйте !
ПС:
1) если включить определение хедеров браузера - можно отказаться от определения дефолтного языка, однако потеряете возможность менять язык -- оно перебивает конфиг (во всяком случае у меня)
2) по такому же принципу можно менять шкурки, но значения хранить например в куках
Отвечу на вопросы, приму достойную и добрую критику.
Изменено hzone (17.02.2015 17:44:19)
Не в сети
а что мешает сделать папки ru, eng и т.д., и там писать текст в виде констант/переменных? так же проще))) и при выборе языка просто бери текст из той папки, откуда нужно))) ИМХО
тем более, что в laravel это прекрасно реализовано)))
а что мешает сделать папки ru, eng и т.д., и там писать текст в виде констант/переменных? так же проще))) и при выборе языка просто бери текст из той папки, откуда нужно))) ИМХО
ничего не мешает.
вы видимо поторопились с выводами, - прочтите ещё раз "ТЗ" из первого поста.
если лень, то кратко, - цель определять и переключать, а не использовать, что является уже побочным действием определения и переключения локали.
Не в сети
А если вдруг мне надо еще и http://prntscr.com/9ev94r , то мне придется еще продублировать все руты без префикса?
Эту группу фронтовых рутов необходимо повесить в самый конец файла /app/Http/routes.php
Туда же и локализованные 404
Route::group(
[
'prefix' => {lang?},
'middleware' => 'lang'
],
function()
{
// HomeController
Route::get( 'home', [ 'as' => 'home', 'uses' => 'HomeController@getIndex' ] );
Route::get( '/', [ 'as' => 'home', 'uses' => 'HomeController@getIndex' ] );
Route::get( 'about', [ 'as' => 'about', 'uses' => 'HomeController@getAbout' ] );
// SettingsController
Route::get( 'set-language', [ 'as' => 'set-language', 'uses' => 'SettingsController@setLocale' ] );
// AuthController
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
}
);
/app/Http/Kernel.php
protected $routeMiddleware = [
// существующий код...
// лосле локализаций переопределяем локаль
'lang' => \App\Http\Middleware\Locale::class,
/app/Http/Middleware/Locale.php
<?php
namespace App\Http\Middleware;
use Closure;
use App;
use Request;
use Illuminate\Contracts\Cookie\QueueingFactory as CookieJar;
class Locale
{
protected $cookies;
public function __construct(CookieJar $cookies)
{
$this->cookies = $cookies;
}
public function handle($request, Closure $next)
{
$server = $request->server;
$lang = $request->segment(1);
$cookie_lang = Request::cookie('lang');
$response = $next($request);
foreach ($this->cookies->getQueuedCookies() as $cookie) {
$response->headers->setCookie($cookie);
}
if($lang === 'ru' || $lang === 'en' || $lang === 'ua'){
$response->withCookie(cookie('lang', $lang));
App::setLocale($lang);
return $response;
}
if($cookie_lang){
return redirect( url( $cookie_lang . $server->get('REQUEST_URI') ) );
} else {
return redirect( url( App::getLocale() . $server->get('REQUEST_URI') ) );
}
}
}
здравствуйте . я установил Mcamara 1.0 Laravel 5.1 ,как будто все работает нормально ,никакой ошибок нету просто язык не изменяется..
Я делал так и все работает!
/app/Http/Middleware/Locale.php
<?php
namespace App\Http\Middleware;
use App;
use Closure;
use Request;
use Illuminate\Contracts\Cookie\QueueingFactory as CookieJar;
class Locale
{
protected $languages = ['ru', 'uk', 'en'];
protected $cookies;
public function __construct(CookieJar $cookies)
{
$this->cookies = $cookies;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$lang = $request->segment(1);
if(in_array($lang, $this->languages)) {
\App::setLocale($lang);
$this->cookies->queue(cookie('lang', $lang));
return $next($request);
}
$server = $request->server;
$cookie_lang = Request::cookie('lang');
if($cookie_lang){
return redirect( url( $cookie_lang . $server->get('REQUEST_URI') ) );
} else {
return redirect( url( App::getLocale() . $server->get('REQUEST_URI') ) );
}
}
}
зависит ещё от версии лары... первый пост заточен под 5.1...
скоро напишу пост для 5.3, когда потребуется на работе сделать подобный финт.
может будет попроще
Не в сети
Страницы 1