SetLocale.php 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Illuminate\Support\Facades\App;
  6. use Illuminate\Support\Facades\Cookie;
  7. use Symfony\Component\HttpFoundation\Response;
  8. class SetLocale
  9. {
  10. /**
  11. * Handle an incoming request.
  12. *
  13. * @param Closure(Request): (Response) $next
  14. */
  15. public function handle(Request $request, Closure $next): Response
  16. {
  17. // 支持的语言(Laravel 推荐小写 + 标准化)
  18. $supportedLocales = array_keys(config('mint.languages'));
  19. $defaultLocale = config('app.locale', 'en');
  20. // 1️⃣ URL 参数 ?lang=
  21. $locale = $request->query('lang');
  22. // 2️⃣ Cookie
  23. if (! $locale) {
  24. $locale = Cookie::get('language');
  25. }
  26. // 3️⃣ 浏览器语言
  27. if (! $locale) {
  28. $locale = $this->getBrowserLocale($request, $supportedLocales);
  29. }
  30. // 4️⃣ 校验
  31. if (! in_array($locale, $supportedLocales, true)) {
  32. $locale = $defaultLocale;
  33. }
  34. // 5️⃣ 应用语言
  35. App::setLocale($locale);
  36. // 6️⃣ 持久化(可选)
  37. session()->put('locale', $locale);
  38. Cookie::queue('language', $locale, 60 * 24 * 365); // 1 年
  39. return $next($request);
  40. }
  41. /**
  42. * 从 Accept-Language 头中解析浏览器语言
  43. */
  44. protected function getBrowserLocale(Request $request, array $supportedLocales): string
  45. {
  46. $acceptLanguage = $request->header('Accept-Language');
  47. if (! $acceptLanguage) {
  48. return config('app.locale', 'en');
  49. }
  50. // zh-CN,zh;q=0.9,en;q=0.8
  51. $languages = array_map(
  52. fn ($lang) => strtolower(trim(explode(';', $lang)[0])),
  53. explode(',', $acceptLanguage)
  54. );
  55. foreach ($languages as $lang) {
  56. // zh-cn → zh-hans / zh-hant
  57. if (str_starts_with($lang, 'zh')) {
  58. return str_contains($lang, 'hant') ? 'zh-hant' : 'zh-hans';
  59. }
  60. if (in_array($lang, $supportedLocales, true)) {
  61. return $lang;
  62. }
  63. }
  64. return config('app.locale', 'en');
  65. }
  66. }