SetLocale.php 2.2 KB

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