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 $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 $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; } }