加入切換語系的機制,加入紀錄網站狀態的全域物件及相關設定機制
This commit is contained in:
parent
deecddd2ec
commit
675fb36dc8
@ -35,11 +35,14 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\App\Http\Middleware\SetAppLanguage::class,
|
||||||
|
\App\Http\Middleware\SetSiteStates::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
'throttle:60,1',
|
'throttle:60,1',
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\App\Http\Middleware\SetSiteStates::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -79,5 +82,6 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\Illuminate\Auth\Middleware\Authorize::class,
|
\Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
\App\Http\Middleware\SetAppLanguage::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
106
app/Http/Middleware/SetAppLanguage.php
Normal file
106
app/Http/Middleware/SetAppLanguage.php
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設定網站語系
|
||||||
|
*
|
||||||
|
* Class SetAppLanguage
|
||||||
|
* @package App\Http\Middleware
|
||||||
|
*/
|
||||||
|
class SetAppLanguage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Cookie及Session存放Locale資訊的Key
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $cookieAndSessionKey = 'appLocale';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設定Locale時的參數Key
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $localeRequestKey = 'locale';
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
//取得所有語言清單
|
||||||
|
$availableLocales = (array)config('languages');
|
||||||
|
//要被回傳的Cookie
|
||||||
|
$setLocaleCookie = false;
|
||||||
|
//要被設定的語言
|
||||||
|
$setLocale = false;
|
||||||
|
//如果有Locale參數
|
||||||
|
if($request->get($this->localeRequestKey) !== null) {
|
||||||
|
//取得傳入的Locale值
|
||||||
|
$requestLocale = $request->get($this->localeRequestKey);
|
||||||
|
//如果有在語言清單內
|
||||||
|
if(array_key_exists($requestLocale, $availableLocales)) {
|
||||||
|
//設定session
|
||||||
|
$request->session()->put($this->cookieAndSessionKey, $requestLocale);
|
||||||
|
//設定要被回傳的Cookie及目標Locale
|
||||||
|
$setLocale = $setLocaleCookie = $requestLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//假如沒有目標Locale,再讀取Session、Cookie、瀏覽器的Locale
|
||||||
|
if(!$setLocale) {
|
||||||
|
$cookieLocale = $request->cookies->get($this->cookieAndSessionKey);
|
||||||
|
$sessionLocale = $request->session()->get($this->cookieAndSessionKey);
|
||||||
|
if(array_key_exists($sessionLocale, $availableLocales)) {
|
||||||
|
//設定要被回傳的Cookie及目標Locale
|
||||||
|
$setLocale = $sessionLocale;
|
||||||
|
if(!$cookieLocale) {
|
||||||
|
$setLocaleCookie = $sessionLocale;
|
||||||
|
}
|
||||||
|
} elseif(array_key_exists($cookieLocale, $availableLocales)) {
|
||||||
|
//設定Session及目標Locale
|
||||||
|
$request->session()->put($this->cookieAndSessionKey, $cookieLocale);
|
||||||
|
$setLocale = $cookieLocale;
|
||||||
|
} else {
|
||||||
|
//Session及Cookie都沒有Locale值時,讀取HTTP Header的資訊
|
||||||
|
$browserLocales = $request->server('HTTP_ACCEPT_LANGUAGE');
|
||||||
|
$browserLocales = preg_replace('/;q=0\.\d+/', '', $browserLocales);
|
||||||
|
$browserLocales = explode(',', $browserLocales);
|
||||||
|
$browserLocales = array_map(function($lang){
|
||||||
|
return strtolower($lang);
|
||||||
|
}, $browserLocales);
|
||||||
|
|
||||||
|
//與語言清單比對
|
||||||
|
$validBrowserLocales = array_intersect($browserLocales, array_keys($availableLocales));
|
||||||
|
|
||||||
|
if(!empty($validBrowserLocales)) {
|
||||||
|
//取得第一個瀏覽器Locale
|
||||||
|
$validBrowserLocale = head($validBrowserLocales);
|
||||||
|
//設定Session及目標Locale
|
||||||
|
$request->session()->put($this->cookieAndSessionKey, $validBrowserLocale);
|
||||||
|
$setLocale = $setLocaleCookie = $validBrowserLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($setLocale) {
|
||||||
|
//如果有目標Locale
|
||||||
|
app()->setLocale($setLocale);
|
||||||
|
} else {
|
||||||
|
//如果沒有目標Locale,則設定成預設語言
|
||||||
|
app()->setLocale(config('app.fallback_locale'));
|
||||||
|
}
|
||||||
|
|
||||||
|
//如果有Cookie,則帶入request
|
||||||
|
if($setLocaleCookie) {
|
||||||
|
return $next($request)->withCookie(cookie()->forever($this->cookieAndSessionKey, $setLocaleCookie));
|
||||||
|
} else {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Http/Middleware/SetSiteStates.php
Normal file
52
app/Http/Middleware/SetSiteStates.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Services\SiteStateService;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設定SiteStateService中的資料
|
||||||
|
*
|
||||||
|
* Class SetSiteStates
|
||||||
|
* @package App\Http\Middleware
|
||||||
|
*/
|
||||||
|
class SetSiteStates
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
$siteState = app(SiteStateService::class);
|
||||||
|
//是否網站後台,判斷route prefix
|
||||||
|
if($request->is(config('admin.route') . '/*')) {
|
||||||
|
$siteState->isAdminArea = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//所有可用語系及其原文名稱
|
||||||
|
$siteState->languagesWithLabel = config('languages');
|
||||||
|
|
||||||
|
//所有可用語系
|
||||||
|
$siteState->languages = array_keys($siteState->languagesWithLabel);
|
||||||
|
|
||||||
|
//所有其他可用語系,排除現在語系
|
||||||
|
$siteState->otherLanguages = collect($siteState->languages)->filter(function($locale){
|
||||||
|
return $locale !== app()->getLocale();
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
//所有語系的當前語言翻譯
|
||||||
|
foreach ($siteState->languages as $locale) {
|
||||||
|
$siteState->languageTranslations[$locale] = trans('languages.' . $locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//預設語系
|
||||||
|
$siteState->defaultLanguage = config('app.fallback_locale');
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
app/Presenters/UrlPresenter.php
Normal file
21
app/Presenters/UrlPresenter.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Presenters;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class UrlPresenter
|
||||||
|
{
|
||||||
|
private $request;
|
||||||
|
|
||||||
|
public function __construct(Request $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function appendLocale($locale)
|
||||||
|
{
|
||||||
|
$url = $this->request->fullUrlWithQuery(['locale' => $locale]);
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/Providers/SingletonServiceProvider.php
Normal file
39
app/Providers/SingletonServiceProvider.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Option;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化所有singleton class 的 instance
|
||||||
|
*
|
||||||
|
* Class SingletonServiceProvider
|
||||||
|
* @package App\Providers
|
||||||
|
*/
|
||||||
|
class SingletonServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
// Services
|
||||||
|
$this->app->alias(\App\Services\SiteStateService::class, 'SiteState');
|
||||||
|
$this->app->singleton(\App\Services\SiteStateService::class, function($app){
|
||||||
|
return new \App\Services\SiteStateService;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
64
app/Services/SiteStateService.php
Normal file
64
app/Services/SiteStateService.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 紀錄全域的網站狀態
|
||||||
|
*
|
||||||
|
* Class SiteStateService
|
||||||
|
* @package App\Services
|
||||||
|
*/
|
||||||
|
class SiteStateService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 是否為後台
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $isAdminArea = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有可用語系
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $languages = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有其他可用語系,排除現在語系
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $otherLanguages = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有可用語系及其原文名稱
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $languagesWithLabel = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有語系的當前語言翻譯
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $languageTranslations = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 預設語系
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $defaultLanguage = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得所有變數
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAll()
|
||||||
|
{
|
||||||
|
return get_object_vars($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -175,7 +175,7 @@ return [
|
|||||||
// App\Providers\BroadcastServiceProvider::class,
|
// App\Providers\BroadcastServiceProvider::class,
|
||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
|
App\Providers\SingletonServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
8
config/languages.php
Normal file
8
config/languages.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'en' => 'English',
|
||||||
|
'zh-tw' => '繁體中文',
|
||||||
|
'zh-cn' => '简体中文',
|
||||||
|
'ja' => '日本語',
|
||||||
|
'ko' => '한국어'
|
||||||
|
];
|
||||||
1
resources/js/admin/app.js
vendored
1
resources/js/admin/app.js
vendored
@ -1 +1,2 @@
|
|||||||
import './lib';
|
import './lib';
|
||||||
|
import '../app-common'
|
||||||
|
|||||||
4
resources/js/app-common.js
vendored
Normal file
4
resources/js/app-common.js
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
$('.logout-btn').on('click', e => {
|
||||||
|
e.preventDefault()
|
||||||
|
$('#logout-form').submit()
|
||||||
|
})
|
||||||
3
resources/js/app.js
vendored
3
resources/js/app.js
vendored
@ -1 +1,2 @@
|
|||||||
require('./bootstrap');
|
import './lib'
|
||||||
|
import './app-common'
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-nav ml-auto">
|
<ul class="nav navbar-nav ml-auto">
|
||||||
|
@component('components.languageDropdown')@endcomponent
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<button class="navbar-toggler aside-menu-toggler d-md-down-none" type="button" data-toggle="aside-menu-lg-show">
|
<button class="navbar-toggler aside-menu-toggler d-md-down-none" type="button" data-toggle="aside-menu-lg-show">
|
||||||
|
|||||||
9
resources/views/components/languageDropdown.blade.php
Normal file
9
resources/views/components/languageDropdown.blade.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@inject('url', App\Presenters\UrlPresenter)
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a href="#" class="nav-link btn-icon dropdown-toggle switch-language" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true">{{ app('SiteState')->languagesWithLabel[app()->getLocale()] }}</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-right">
|
||||||
|
@foreach (app('SiteState')->otherLanguages as $locale)
|
||||||
|
<a href="{{ $url->appendLocale($locale) }}" class="dropdown-item">{{ app('SiteState')->languagesWithLabel[$locale] }}</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
@ -26,24 +26,14 @@
|
|||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item">
|
||||||
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
|
<a class="nav-link logout-btn" href="#">{{ __('Logout') }}</a>
|
||||||
{{ Auth::user()->name }} <span class="caret"></span>
|
<form id="logout-form" action="{{ route('logout') }}" method="post" style="display: none;">
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
|
||||||
<a class="dropdown-item" href="{{ route('logout') }}"
|
|
||||||
onclick="event.preventDefault();
|
|
||||||
document.getElementById('logout-form').submit();">
|
|
||||||
{{ __('Logout') }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
|
|
||||||
@csrf
|
@csrf
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
@endguest
|
@endguest
|
||||||
|
@include('components.languageDropdown')
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user