the browser-facing portion of osu!
at master 2.9 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6/** 7 * This is a port of HttpAcceptLanguage::Parser from the http_accept_language gem 8 * https://github.com/iain/http_accept_language/blob/v2.1.1/lib/http_accept_language/parser.rb. 9 */ 10 11namespace App\Libraries\AcceptHttpLanguage; 12 13use InvalidArgumentException; 14 15class Parser 16{ 17 public static function parseHeader(?string $header): array 18 { 19 if (!present($header)) { 20 return []; 21 } 22 23 $header = preg_replace('/\s+/', '', $header); 24 $header = explode(',', $header); 25 try { 26 $mappings = array_map(function ($language) { 27 $exploded = explode(';q=', $language); 28 $locale = strtolower($exploded[0]); 29 $quality = (float) ($exploded[1] ?? 1.0); 30 if (!preg_match('/^[a-z\-0-9]+|\*$/i', $locale)) { 31 throw new InvalidArgumentException('Not correctly formatted'); 32 } 33 34 if ($locale === '*') { 35 $locale = null; // Ignore wildcards 36 } 37 38 return [$locale, $quality]; 39 }, $header); 40 } catch (InvalidArgumentException $_e) { 41 return []; 42 } 43 44 usort($mappings, function ($left, $right) { 45 return $right[1] <=> $left[1]; 46 }); 47 48 return array_reject_null(array_map(fn ($mapping) => $mapping[0], $mappings)); 49 } 50 51 private array $availableLanguages; 52 53 public function __construct(?array $availableLanguages = null) 54 { 55 $this->availableLanguages = $availableLanguages ?? $GLOBALS['cfg']['app']['available_locales']; 56 } 57 58 /** 59 * Returns the first of the user preferred languages that is 60 * also found in available languages. Finds best fit by matching on 61 * primary language first and secondarily on region. If no matching region is 62 * found, return the first language in the group matching that primary language. 63 * 64 * Example: 65 * 66 * request.language_region_compatible($header) 67 */ 68 public function languageRegionCompatibleFor(?string $header): ?string 69 { 70 foreach (static::parseHeader($header) as $preferred) { 71 $preferredLanguage = explode('-', $preferred, 2)[0] ?? null; 72 73 $langGroup = array_values(array_filter( 74 $this->availableLanguages, 75 // en 76 fn ($available) => $preferredLanguage === explode('-', $available, 2)[0] ?? null, 77 )); 78 79 foreach ($langGroup as $lang) { 80 if ($lang === $preferred) { 81 return $lang; 82 } 83 } 84 85 if (isset($langGroup[0])) { 86 return $langGroup[0]; 87 } 88 } 89 90 return null; 91 } 92}