Files
lotteryLaravel/app/Http/Middleware/NegotiateLotteryLocale.php

78 lines
2.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* 【API 语言协商中间件】
*
* - 挂载位置bootstrap/app.php 中对 api 分组 prepend所有 /api/* 请求都会先执行本中间件。
* - 职责:解析客户端语言 → 写入 $request->attributes['lottery_locale'] → 调用 app()->setLocale()
* 便于 trans()、LotteryMessage 及后续按 zh/en/ne 选库表文案列时使用。
*
* 【协商顺序】① 请求头 X-Locale必须为 config 支持的 zh/en/ne 之一);② Accept-Language 首选项;③ fallback。
*
* 【与前端】浏览器或 App 可直接带 X-Locale或仅靠 Accept-Language无需前端维护文案 JSON。
*/
class NegotiateLotteryLocale
{
public function handle(Request $request, Closure $next): Response
{
$locale = $this->resolveLocale($request);
// attribute 名称固定为 lottery_locale与 Request::lotteryLocale() 宏一致
$request->attributes->set('lottery_locale', $locale);
app()->setLocale($locale);
return $next($request);
}
/** 综合 X-Locale 与 Accept-Language得到最终语言代码 */
private function resolveLocale(Request $request): string
{
/** @var list<string> $supported */
$supported = array_values(array_unique(config('lottery.locales.supported', ['en', 'zh', 'ne'])));
$fallback = (string) config('lottery.locales.fallback', 'en');
$header = strtolower(trim((string) $request->header('X-Locale', '')));
if ($header !== '' && in_array($header, $supported, true)) {
return $header;
}
return $this->fromAcceptLanguage((string) $request->header('Accept-Language', ''), $supported, $fallback);
}
/**
* 解析标准 Accept-Language可带权重 q=),只认主语言段 zh / en / ne。
*
* @param list<string> $supported config('lottery.locales.supported')
*/
private function fromAcceptLanguage(string $header, array $supported, string $fallback): string
{
if ($header === '') {
return $fallback;
}
foreach (explode(',', $header) as $part) {
$code = strtolower(trim(explode(';', trim($part), 2)[0] ?? ''));
if ($code === '') {
continue;
}
$primary = explode('-', $code, 2)[0] ?? $code;
if ($primary === 'zh' && in_array('zh', $supported, true)) {
return 'zh';
}
if ($primary === 'ne' && in_array('ne', $supported, true)) {
return 'ne';
}
if ($primary === 'en' && in_array('en', $supported, true)) {
return 'en';
}
}
return $fallback;
}
}