【Laravel】メール認証とパスワードリセットを日本語化


この記事の意図

Laravelには便利な認証機能がついてます。
とっても便利なのでおすすめです。

すごく親切なLaravelですが、なぜか日本語化してくれてません。なので日本語化します。
他にもQiitaであるんですが、メール認証とパスワードリセットがセットになってなかったので
セットで書くのが目的です。

前提

  • 認証したいのは User
  • メール認証が送れるとこまでは自力で
  • メール送れる状態( mailtrapとかでもいいすよ)

1. 通知を使う

デフォルトのメール認証やパスワードリセットはメールで来るんですが、実は機能としてはnotificationなるものを使ってます。なので、いまからいじるのはNotificationになります。

2. UserモデルでOverride

  • sendEmailVerificationNotification
  • sendPasswordResetNotification

という function を追加しています。(useを忘れないように)
理由は、これが実際にメールを送る function だからです。
これは、Authenticatableのtraitで書かれてて(たしか)、メール認証とパスワードリセット時に呼ばれます。ここをオーバーライドして独自の Notification を使うことで日本語化します。

User
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Notifications\VerifyEmail;    // <-- あとで作ります
use App\Notifications\ResetPassword; // <-- あとで作ります

class User extends Authenticatable implements MustVerifyEmail
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * ここを追加していますー
     * override
     *
     * @return void
     */
    public function sendEmailVerificationNotification()
    {
        $this->notify(new VerifyEmail);
    }

    /**
     * ここを追加していますー
     * override
     *
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new ResetPassword($token));
    }
}

3. Notificationをコピー

app/Notifications というフォルダをまず作ります。(どこでもいいちゃいいです。)
その配下に以下の2つをコピー

  • vendor/laravel/framework/src/Illuminate/Auth/Notifications/VerifyEmail.php
  • vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php

この2つが実際に送ってるやつらですね。
コピーしたらnamespaceを書き換えるのをお忘れなく。

4. 日本語化

本丸!日本語化していきます。

説明はしません。
コードをみてください。該当部分だけ載せますね。

App\Notifications\VerifyEmail
<?php
    /**
     * Build the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        $verificationUrl = $this->verificationUrl($notifiable);

        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl);
        }

        return (new MailMessage)
            ->greeting('こんにちは!')
            ->subject('メール認証をお願いします')
            ->line('ボタンを押して認証してね')
            ->action('メールを認証する', $verificationUrl)
            ->line('身に覚えがない場合は何もしないでくださいね。怪しいので。');
    }

App\Notifications\ResetPassword
    /**
     * Build the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $this->token);
        }

        return (new MailMessage)
            ->greeting('こんにちは!')
            ->subject('パスワードリセット用メールです')
            ->line('これはパスワードリセットの依頼があったのでおくっっています。')
            ->action('パスワードリセット', url(config('app.url').route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
            ->line('このリンクの有効期限は :count 分です。', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')])
            ->line('身に覚えがない場合は何もしないでくださいね。怪しいので。');
    }

結果はこちら
微妙に残ります。これはテンプレートに直に書かれてる部分が残ってる影響です。

mailのテンプレートを日本語化

ここにもありますが、notification で使ってるデフォルトのテンプレートをコピーできます。

ternimal
$ php artisan vendor:publish --tag=laravel-notifications
Copied Directory [/vendor/laravel/framework/src/Illuminate/Notifications/resources/views] To [/resources/views/vendor/notifications]
Publishing complete.
Publishing complete.

これでテンプートができたので、日本語化します。

resources/views/vendor/notifications/email.blade.php
@component('mail::message')
{{-- Greeting --}}
@if (! empty($greeting))
# {{ $greeting }}
@else
@if ($level === 'error')
# @lang('Whoops!')
@else
# @lang('Hello!')
@endif
@endif

{{-- Intro Lines --}}
@foreach ($introLines as $line)
{{ $line }}

@endforeach

{{-- Action Button --}}
@isset($actionText)
<?php
    switch ($level) {
        case 'success':
        case 'error':
            $color = $level;
            break;
        default:
            $color = 'primary';
    }
?>
@component('mail::button', ['url' => $actionUrl, 'color' => $color])
{{ $actionText }}
@endcomponent
@endisset

{{-- Outro Lines --}}
@foreach ($outroLines as $line)
{{ $line }}

@endforeach

{{-- Salutation --}}
@if (! empty($salutation))
{{ $salutation }}
@else
今後も{{ config('app.name') }}をよろしくです。
@endif

{{-- Subcopy --}}
@isset($actionText)
@slot('subcopy')
@lang(
    "もし \":actionText\" ボタンが動かない場合は、このURLをブラウザにコピぺしてください\n".
    ': [:actionURL](:actionURL)',
    [
        'actionText' => $actionText,
        'actionURL' => $actionUrl,
    ]
)
@endslot
@endisset
@endcomponent

晴れて日本語化

という感じで、少し面倒だったので
個人的な備忘録として残してみました。
では、また

追伸

Githubでのpull requestを載せるので参考までにどうぞ