Laravel Локализация страниц email / reset password

Сделал перевод для приложения, все работает, но когда добавляешь регистрацию через подтверждение почты(implements MustVerifyEmail для модели User), после отправки формы регистрации, выдает исключение.

url
http://example.test/ru

Illuminate\Routing\Exceptions\UrlGenerationException
Missing required parameters for [Route: verification.notice] [URI: {locale}/email/verify].

Роуты

Route::get('/', fn() => redirect(route('home', app()->getLocale())));

// Verify
Route::get('/email/verify', 'Auth\VerificationController@show')->name('verification.notice');
Route::get('/email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify');
Route::get('/email/resend', 'Auth\VerificationController@resend')->name('verification.resend');

Route::group([
    'prefix'     => '{locale}',
    'middleware' => ['locale', 'verified']
], function () {
    Auth::routes(['verify' => true]);

    Route::get('/', 'HomeController@index')->name('home');
});

Если поместить блок роутов verify, то ничего не меняется.

upd

Сделал роуты по другому

Route::get('/', fn() => redirect(route('home', app()->getLocale())));

Auth::routes(['verify' => true]);


Route::group([
    'prefix'     => '{locale}',
    'middleware' => ['locale']
], function () {
    Route::get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
    Route::get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify');
    Route::get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');

    Route::get('/', 'HomeController@index')->name('home');
});

Route::group([
    'prefix'     => '{locale}',
    'middleware' => ['locale', 'verified']
], function () {
    Route::get('test', function () {
        return app()->getLocale();
    })->name('test');
});

теперь если зайти на роут test, url - email/verify и 404 ошибка, но если зайти на ru/email/verify то все нормально, теперь не знаю как настроить, чтобы автоматом перед /email/verify добавлялась локаль


Ответы (1 шт):

Автор решения: steamvis

Три дня "исследования" привели к выводу, что лучше поставить готовый пакет локализации. В итоге получилось сделать перевод для всех форм связанных с аутентификацией. так же письма восстановления пароля и подтверждения емейла
Пришлость переназначить дефолтные трейты от ларавел и несколько классов из вендора скопировать в проект


в middleware Authenticate изменить метод redirectTo

protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        return route('login', app()->getLocale());
    }
}

роуты

use Illuminate\Support\Facades\Route;

Route::get('/', fn() => redirect(route('home', app()->getLocale())));

Route::group([
    'prefix'     => '{locale}',
    'middleware' => ['locale']
], function () {
    Auth::routes(['verify' => true]);

    Route::get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
    Route::get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify');
    Route::post('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');

    Route::get('/', 'HomeController@index')->name('home');
});

Route::group([
    'prefix'     => '{locale}',
    'middleware' => ['locale', 'verified']
], function () {
    Route::get('test', function () {
        return app()->getLocale();
    })->name('test');
});

В папке app создал папку Notifications
В папке app создал папку Notifications

Скопировал в папку два класса с шаблонами писем из папки вендора vendor/laravel/framework/src/Illuminate/Auth/Notifications/ Скопировал в папку два класса с шаблонами писем из папки вендора

В классе LocaleResetPassword для метода toMail во второй конструкции if else добавил свойство locale

 if (static::$createUrlCallback) {
            $url = call_user_func(static::$createUrlCallback, $notifiable, $this->token);
        } else {
            $url = url(route('password.reset', [
                'locale' => app()->getLocale(),
                'token'  => $this->token,
                'email'  => $notifiable->getEmailForPasswordReset(),
            ], false));
        }

Тоже самое в классе LocaleVerifyEmail сделал в методе verificationUrl

 return URL::temporarySignedRoute(
            'verification.verify',
            Carbon::now()->addMinutes(60),
            [
                'locale' => app()->getLocale(),
                'id'     => $notifiable->getKey(),
                'hash'   => sha1($notifiable->getEmailForVerification()),
            ]
        );

Далее в моделе User переназначил методы отправки писем на свои

public function sendEmailVerificationNotification()
{
    $this->notify(new LocaleVerifyEmail());
}

public function sendPasswordResetNotification($token)
{
    $this->notify(new LocaleResetPassword($token));
}

Скопировал трейты laravel в app/Traits из вендора

vendor/laravel/ui/auth-backend/ResetsPasswords.php
vendor/laravel/ui/auth-backend/VerifiesEmails.php

Скопировал трейты laravel в app/Traits из вендора
В трейте LocaleResetsPasswords добавил свойство locale в методе showResetForm

public function showResetForm(Request $request, $token = null)
{
    return view('auth.passwords.reset')->with(
        ['token' => $token, 'email' => $request->email, 'locale' => app()->getLocale()]
    );
}

В трейте LocaleVerifiesEmails в методе verify, по непонятным мне причинам, из ссылки не парсился hash, пришлось немного поменять конструкцию

$hash = $request->request->get('hash');
if (!hash_equals((string)$hash, sha1($request->user()->getEmailForVerification()))) {
    throw new AuthorizationException;
}

Соответственно в контроллере ResetPasswordController меняем стандартный трейт на
use LocaleResetsPasswords;
В контроллере VerificationController меняем стандартный трейт на
use LocaleVerifiesEmails;

Создаем middleware EnsureEmailsVerified, опять идём в вендор и копируем код ларавельского middleware vendor/laravel/framework/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php Вставляем код в созданный нами и добавляем app()->getLocale()

public function handle($request, Closure $next, $redirectToRoute = null)
{
    if (!$request->user() ||
        ($request->user() instanceof MustVerifyEmail &&
            !$request->user()->hasVerifiedEmail())) {
        return $request->expectsJson()
            ? abort(403, 'Your email address is not verified.')
            : Redirect::route($redirectToRoute ?: 'verification.notice', app()->getLocale());
    }
    return $next($request);
}

Идём по пути app/Http/Kernel.php и в protected $routeMiddleware меняем

'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,

на middleware созданный нами

'verified' => App\Http\Middleware\EnsureEmailsVerified::class,

Теперь добавляем везде к роутам app()->getLocale(), а к шаблону с ссылками смены языка добавляем

@empty(Route::current()->token)
    @php($data = ['locale' => $locale, 'token' => Route::current()->token])
@else
    @php($data = ['locale' => $locale])
@endempty

у меня получилось так

@foreach($locales as $locale)
    @empty(Route::current()->token)
        @php($data = ['locale' => $locale, 'token' => Route::current()->token])
    @else
        @php($data = ['locale' => $locale])
    @endempty
    <li>
        <a href="{{ route(Route::currentRouteName(), $data) }}">{{ $locale }}</a>
    </li>
@endforeach

Теперь, если я ничего не забыл, переходя по страницам восстановления пароля, подтверждения емейла, можно менять языки и все будет работать

→ Ссылка