3
votes

I'm trying to implement easy multi-language routing based on locale in Laravel 5.6.28, but have stuck with redirect after language change.

I would like to immediately redirect users to proper route based on changed locale whenever they changing it from form select on page.

I also made two middleware classes:
1. SetLocale - For set locale if not set using HTTP_ACCEPT_LANGUAGE or considering first segment of reqeust (locale exactly).
2. LocaleRedirect - For compare user and request locales and redirect if they didn't match.

For example, if route was '/en/blog/stackoverflow'
After changing locale it should be '/gr/blog/stackoverflow'
But redirect does not occur. What I did wrong?
Many thanks.

Locales:

'locales' => [
        'en' => 'English',
        'es' => 'Spanish',
        'gr' => 'Greek'
    ]

Page:

{!! Form::open(['route' => 'language.change']) !!}
    Language:
    {!! Form::select('lang', config('translatable.locales'), app()->getLocale(), ['id' => 'language-select']); !!}
{!! Form::close() !!}

<script>
    $(function () {
        $('#language-select').on('change', function () {
            $(this).closest('form').submit();
        });
    });
</script>

Routes:

Route::post('language/change', 'LanguageController@postChangeLanguage')->name('language.change');

Route::group([
    'prefix' => '{locale}',
    'middleware' => ['setlocale', 'locale-redirect'],
    'where' => ['locale' => implode('|', array_keys(config('translatable.locales')))]
], function () {
    Route::get('page', function ($locale) {
        return view(Helper::getLocaleView($locale, 'page'));
    });

    Route::get('home', function ($locale) {
        return view(Helper::getLocaleView($locale, 'home'));
    });
});

Route::get('/', function () {
    return redirect()->to('en/home');
});

LanguageController:

class LanguageController extends Controller
{
    public function postChangeLanguage(Request $request)
    {
        $changeLang = $request->input('lang');
        $userLang = app()->getLocale();

        if ($userLang !== $changeLang && array_key_exists($changeLang, config('translatable.locales')))
        {
            session(['locale' => $changeLang]);
            app()->setLocale($changeLang);
        }

        return redirect()->back();
    }
}

SetLocale middleware:

class SetLocale
{
    public function handle($request, Closure $next)
    {
        if ($request->method() === 'GET')
        {
            $requestLocale = $request->segment(1);

            if (array_key_exists($requestLocale, config('translatable.locales')))
            {
                session(['locale' => $requestLocale]);
            }
            else if (!session()->has('locale'))
            {
                $browserLanguage = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);

                if (array_key_exists($browserLanguage, config('translatable.locales')))
                {
                    session(['locale' => $browserLanguage]);
                }
                else
                {
                    session(['locale' => config('translatable.fallback_locale')]);
                }
            }

            app()->setLocale(session('locale'));
        }

        return $next($request);
    }
}

LocaleRedirect middleware:

class LocaleRedirect
{
    public function handle($request, Closure $next)
    {
        $requestLocale = $request->segment(1);
        $userLocale = session('locale');

        if ($requestLocale !== $userLocale)
        {
            $segments = $request->segments();
            array_shift($segments);
            array_unshift($segments, $userLocale);

            return redirect()->to(implode('/', $segments));
        }

        return $next($request);
    }
}
2
Did you map setlocale and locale-redirect to the correct classes in the App\Http\Kernel under $routeMiddleware?Azeame
@Azeame Yes, it is mapped properly.Khasky

2 Answers

3
votes

I came up with workaround, LocaleRedirect middleware not needed anymore.

class LanguageController extends Controller
{
    public function postChangeLanguage(Request $request)
    {
        $changeLang = $request->input('lang');
        $userLang = session('locale');

        if ($userLang !== $changeLang && array_key_exists($changeLang, config('translatable.locales')))
        {
            session(['locale' => $changeLang]);
            app()->setLocale($changeLang);

            $segments = str_replace(url('/'), '', url()->previous());
            $segments = array_filter(explode('/', $segments));
            array_shift($segments);
            array_unshift($segments, $changeLang);

            return redirect()->to(implode('/', $segments));
        }

        return redirect()->back();
    }
}
0
votes

I solved by edit @khasky answer to be public solution

   public function changeLanguage(Request $request)
    {
        $changeLang = $request->lang;
        $userLang = session('locale');

        session(['locale' => $changeLang]);
        app()->setLocale($changeLang);

        $segments = str_replace(url('/'), '', url()->previous());
        $segments = array_filter(explode('/', $segments));
        array_shift($segments);
        array_unshift($segments, $changeLang);

        return redirect()->to(implode('/', $segments));

    }