Laravel-adminに言語切替を追加する

# 概要
Laravel-adminの管理画面で
<img width="891" alt="lang.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431996/27901c33-4af8-1422-abbe-638be894d6b0.png">
このような言語切替ボタンを実装してみました．

# 環境
Laravel 5.8
Laravel-admin 1.7.2

# 実装手順
### 言語切替機能の追加
[こちらの記事](https://qiita.com/kumamon_engineer/items/4a83344744db605e3e52)を参考に言語切替機能を追加します．


最初にLaravelのデフォルトの言語を日本語にします．するとLaravel-adminの言語も切り替わります．

```php:config/app.php
'locale' => 'ja',  //もとはen
```

次にconfig/language.phpに以下を書きます：

```php:config/language.php
<?php

/**
 * 登録言語
 */
return [
    'ja' => 'Japanese',
    'en' => 'English',
];
```

その後，言語切り替え用のコントローラを

```console
php artisan make:controller LanguageController
```

で作成します．作成したコントローラに

```php:App\Http\Controllers\LanguageController

use Session;

class LanguageController extends Controller
{
    /**
     * 言語切替
     *
     * @param string $lang config/language.php のキー
     */
    public function switchLanguage($lang) {
        if(array_key_exists($lang,config('language'))) {  //登録されている言語の場合
            Session::put('applocale',$lang);
        }else {  //それ以外
            Session::put('applocale','ja');
        }

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

を追加します．言語切替ページとしてroutes/web.phpに

```php:routes/web.php
Route::get('/admin/lang/{lang}','LanguageController@switchLanguage');
```

を追加します．このページにアクセスすると言語が切り替わります．

最後にミドルウェアを追加します：

```console
php artisan make:middleware Language
```

でミドルウェアを作成し，Kernelに登録します

```php:App/Http/Kernel.php
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\Language::class,  //これを追加する
    ],
];
```

次に作成したミドルウェアに

```php:App/Http/Middleware/Language.php
use Session;
use App;

class Language
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (Session::has('applocale') && array_key_exists(Session::get('applocale'), config('language'))) {
            App::setLocale(Session::get('applocale'));
        }
        else {
            App::setLocale('ja');
        }
        return $next($request);
    }
}
```

を追加して，ロケーションが登録されるようにします．


### 翻訳ファイルの用意
Laravelには多言語用のメソッドとして

```php
__('メッセージ');
trans('messeage');
```

の2つが用意されています．```__()```は文章をそのままキーとして翻訳ファイルを定義するのに対し，```trans()```はresource/lang/ja/以下で定義する配列のキーを指定します．詳しくは[ドキュメント](https://readouble.com/laravel/5.5/ja/localization.html)を参照してください．

今回は```__()```を用いた実装をします．resource/langにen.jsonファイルを追加し

```json:resource/lang/en.json
{
    "タイトル" : "Title",
    "価格" : "Price",
    "ページ数" : "Page",
    "カテゴリー" : "Category",
    "著者" : "Authoer",
    "作成日時" : "Created at",
    "更新日時" : "Updated at"
}
```

 などと書きます．左が呼び出しのキーで，右が翻訳です．呼び出しは

```php:Admin\Controllers\BookController.php
protected function grid()
{
    $grid = new Grid(new Book);
    $grid->column('id','Id');
    $grid->column('title', __('タイトル'));
    $grid->column('price', __('価格'));
    $grid->column('page', __('ページ数'));
    $grid->column('category_id', __('カテゴリー'));
    $grid->column('author_id', __('著者'));
    $grid->column('created_at', __('作成日時'));
    $grid->column('updated_at', __('更新日時'));
    return $grid;
}
```

このようにします．実行結果は
<img width="845" alt="Book.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431996/70381c14-7928-5066-0c33-00a36cde146e.png">

このようになります．確かに日本語が英語に翻訳されています．

### 言語切替ボタンの追加
Laravel-adminのヘッダー部に言語切替ボタンを追加します．

まずbootstrap.phpに次を追加します：

```php:Admin/bootstrap.php
Admin::navbar(function (\Encore\Admin\Widgets\Navbar $navbar) {

    $navbar->right(view('admin.language',[
        'lang' => config('language'),
    ]));

});
```

これでナビゲーションバーの右側にviewで指定したbladeが追加されます．左側に追加したい場合は```left```を用います．

次にボタン用のbladeを用意します：

```html:resources/views/admin/language.blade.php
<li class="dropdown lang lang-switch" style="position:relative;">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="true">
        <span class="hidden-xs">Language</span>
    </a>
    <ul class="dropdown-menu" style="position: absolute; left:0px; min-width:180px;">
        <li class="lang-header">
        </li>
        <li class="lang-footer clearfix" style="display:flex; justify-content: left; flex-wrap:wrap;">
            @foreach ($lang as $key => $label)
                <div style="display:inline-block; padding-left:5px; padding-bottom:2px;">
                    <a href="/admin/lang/{{$key}}" class="btn btn-default btn-flat lang-change">{{$label}}</a>
                </div>
            @endforeach
        </li>
    </ul>
</li>
```

これで最初に示した画面が完成します．

### 言語切替時に画面全体をリロードする
Laravel-adminではページ遷移をpjaxで行っています．したがってヘッダーやサイドバーなどは，追加した言語切替ボタンをクリックしても元の言語のままとなってしまいます．そこで，言語切替時のみはpjaxによるページ遷移を行わないように設定します．

```javascript:public\vendor\laravel-admin\laravel-admin\laravel-admin.js
// 言語変更ボタンも例外にする
//もとは $(document).pjax('a:not(a[target="_blank"])', {
$(document).pjax('a:not(a[target="_blank"]):not(.lang-change)', {
    container: '#pjax-container'
});
```

これで言語切替時は通常のページ遷移が行われるようになります．

# 参考
- [Laravelで言語切替実装した時のメモ(多言語化)
](https://qiita.com/kumamon_engineer/items/4a83344744db605e3e52)
- [Laravel-admin 公式ドキュメント](https://laravel-admin.org/docs/#/)