Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 30.08.2021 06:06:24

Запретить смену языка для одного контроллера

Такие у меня routes:

/**
 * Frontend pages of site
 */
Route::multilingual('/', 'IndexController@index')->name('index');



/**
 * Authentication
 */
Route::get('login', 'Auth\LoginController@show');
Route::post('login', 'Auth\LoginController@login');
Route::get('logout', 'Auth\LoginController@logout')->name('auth.logout');

Route::group(['middleware' => ['registration', 'guest']], function () {
    Route::get('register', 'Auth\RegisterController@show');
    Route::post('register', 'Auth\RegisterController@register');
});



и т.д.

Первый из них - это для морды сайта,
а остальные - для дашборда, профиля, авторизации/регистрации и т.п.

Управлением языком первого роута занимается отдельный пакет, который позволяет отдавать контент под префиксами (папками) - наподобие "site.com/faq" (для буржуйской версии) и "site.com/ru/faq" (для русской версии).

А управление языком остальных роутов (не морды сайта, а по сути уже всей части user-area) осуществляется уже через осознанный выбор самих пользователей - без префиксов-папок для языков. Согласитесь, было бы странно иметь пути "site.com/dashboard" и "site.com/ru/dashboard". Тут уже в дело вступают Куки (лучше конечно Сессии, но надо чтобы смена языка работала еще до фактической аутентификации пользователя - по сути на страницах самой авторизации/регистрации/восстановления пароля... А плодить сессии под КАЖДОГО просто посетителя как-то не комильфо). И для реализации такого функционала прямо в конце `routes/web.php` (знаю, bad practice) прописано следующее:

Route::get('lang/{locale}', function ($locale) {
    if (!in_array($locale, locales())) {
        abort(400);
    }
    Cookie::queue( Cookie::forever('lang', $locale) ); 
    return back();
});

// Вот этот кусок кода надо как-то изолировать от применения к первому роуту:   <-------------------------
if (Request::hasCookie('lang')) {
    $lang = Cookie::get('lang');
    if (in_array($lang, locales()))
        locale($lang);
    else
        Cookie::queue( Cookie::forget('lang') );
}

И оно работает... И не пришлось лишних и внешних package'й создавать, инициализировать их и т.д., только нагружая систему.
Однако эта реализация пересекается с тем отдельным переводчиком у первого роута. И превалирует над ним. В итоге и по "site.com/faq", и по "site.com/ru/faq" одинаково отображается английский язык. Или русский. Смотря какой выбран (сохранен в куки).

Как мне изолировать куки-язычность от первого роута? Я бы прописал в контроллере - но их там тьма тьмущая, а у первого роута наоборот - только один контроллер. Не прописывать же везде в каждом роуте один и тот же код? Иначе нарушается принцип DRY (don't repeat yourself) и вообще код должен быть в одном едином месте. И тут он реально должен быть в каком-нибудь единственном месте (а не "в одном месте..." smile)

Как быть?

Изменено Fullstack (30.08.2021 06:11:54)

Не в сети

#2 30.08.2021 10:38:59

Re: Запретить смену языка для одного контроллера

Ничего не знаю про пакет, который ты используешь. Но:
Мне кажется ты смешиваешь локализацию пользовательского интерфейса и локализацию контента. Страницы, которые ты помещаешь в Route::multilingual, вероятно должны выдавать контент на том или ином языке, независимо от того, какой язык является предпочтительным для пользователя, т.е. на каком языке пишутся меню и служебные сообщения. Не обязательно им совпадать!
Исходя из этого, твои два метода выбора языка должны устанавливать разные переменные внутри приложения и ты сможешь использовать их в разных в приложении независимо.


There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Не в сети

#3 30.08.2021 18:20:49

Re: Запретить смену языка для одного контроллера

Страницы, которые ты помещаешь в Route::multilingual, вероятно должны выдавать контент на том или ином языке, независимо от того, какой язык является предпочтительным для пользователя

Верно. Этот контент иденксируется поисковиками, поэтому он должен быть разным, в зависимости от первой части URI (/page, /ru/page, /de/page) (за что и отвечает вышеупомянутый компонент), и разные меню сайта в том числе должны быть на языке, указанном в начале пути роута. А весь пользовательский интерфейс уже в зависимости от выбранного языка самим пользователем (с помощью иконок с флагами, которые успешно ставят нужный язык через роут /lang/{$locale} в Куки).

И вот эту часть кода, устанавливающую язык из Куков:

if (Request::hasCookie('lang')) {
    $lang = Cookie::get('lang');
    if (in_array($lang, locales()))
        locale($lang);
    else
        Cookie::queue( Cookie::forget('lang') );
}

мне надо как-то изолировать от первого роута, который отвечает за фронтовые страницы самого сайта (информацию о сайте), а на всех остальных роутах уже использовать применение выбранного языка Куками, с помощью кода выше.

По сути мне надо вставить код чтения Куки и применения языка в какую-то часть Laravel, где будет проверка - не первый ли это роут (который называется index).

Изменено Fullstack (30.08.2021 18:24:57)

Не в сети

#4 30.08.2021 19:36:47

Re: Запретить смену языка для одного контроллера

В общем не нашел какой-нибудь уже существующий класс или функцию для вставки кода чтения Кук, поэтому создал middleware:

> php artisan make:middleware UserLang

<?php

namespace Vanguard\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cookie;

class UserLang
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if ($request->hasCookie('lang')) {
            $lang = Cookie::get('lang');
            if (in_array($lang, locales()))
                locale($lang);
            else
                Cookie::queue( Cookie::forget('lang') );
        }

        return $next($request);
    }
}

Зарегистрировал его в $routeMiddleware в app/Http/Kernel.php и в роутере заключил пользовательскую часть в группу с использованием этого Middleware. Не знаю о правильности этого решения, Laravel для меня во многом тёмный лес, поэтому если можно сделать лучше, я только рад услышать

Не в сети

Подвал раздела