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

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

- [認証](https://readouble.com/laravel/6.0/ja/authentication.html)
- [メール確認](https://readouble.com/laravel/6.0/ja/verification.html)

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

## 前提
- 認証したいのは User
- メール認証が送れるとこまでは自力で
- メール送れる状態（ [mailtrap](https://mailtrap.io/)とかでもいいすよ）

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

## 2. UserモデルでOverride
- sendEmailVerificationNotification
- sendPasswordResetNotification

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

```PHP: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. 日本語化
本丸！日本語化していきます。

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

```PHP: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('身に覚えがない場合は何もしないでくださいね。怪しいので。');
    }

```
```PHP: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('身に覚えがない場合は何もしないでくださいね。怪しいので。');
    }
```

**結果はこちら**
微妙に残ります。これはテンプレートに直に書かれてる部分が残ってる影響です。
![Screen Shot 2019-10-31 at 13.01.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202027/b93f77c2-ffe7-bc13-1bea-8249cb950678.png)


## mailのテンプレートを日本語化
[ここ](https://readouble.com/laravel/6.0/ja/notifications.html#customizing-the-templates)にもありますが、notification で使ってるデフォルトのテンプレートをコピーできます。

```shell: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.
```

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

```PHP: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

```

## 晴れて日本語化
![Screen Shot 2019-10-31 at 13.18.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202027/316357fc-81e8-dd26-9eea-ea3ef7d2f92c.png)

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

## 追伸
Githubでの[pull request](https://github.com/KathySamurai/laravel-adventure/pull/2/files)を載せるので参考までにどうぞ