Locale::httpAcceptLanguage()   B
last analyzed

Complexity

Conditions 9
Paths 3

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 41
rs 7.7084
c 0
b 0
f 0
cc 9
nc 3
nop 3
1
<?php namespace Fisharebest\Localization;
2
3
use DomainException;
4
use Fisharebest\Localization\Locale\LocaleInterface;
5
6
/**
7
 * Class Locale - Static functions to generate and compare locales.
8
 *
9
 * @author    Greg Roach <[email protected]>
10
 * @copyright (c) 2018 Greg Roach
11
 * @license   GPLv3+
12
 */
13
class Locale
14
{
15
    /**
16
     * Callback for PHP sort functions - allows lists of locales to be sorted.
17
     * Diacritics are removed and text is capitalized to allow fast/simple sorting.
18
     *
19
     * @param LocaleInterface $x
20
     * @param LocaleInterface $y
21
     *
22
     * @return int
23
     */
24
    public static function compare(LocaleInterface $x, LocaleInterface $y)
25
    {
26
        return strcmp($x->endonymSortable(), $y->endonymSortable());
27
    }
28
29
    /**
30
     * Create a locale from a language tag (or locale code).
31
     *
32
     * @param string $code
33
     *
34
     * @return LocaleInterface
35
     * @throws DomainException
36
     */
37
    public static function create($code)
38
    {
39
        $class = __NAMESPACE__ . '\Locale\Locale' . implode(array_map(function ($x) {
40
            return ucfirst(strtolower($x));
41
        }, preg_split('/[^a-zA-Z0-9]+/', $code)));
42
43
        if (class_exists($class)) {
44
            return new $class();
45
        } else {
46
            throw new DomainException($code);
47
        }
48
    }
49
50
    /**
51
     * Create a locale from a language tag (or locale code).
52
     *
53
     * @param string[]          $server    The $_SERVER array
54
     * @param LocaleInterface[] $available All locales supported by the application
55
     * @param LocaleInterface   $default   Locale to show in no matching locales
56
     *
57
     * @return LocaleInterface
58
     */
59
    public static function httpAcceptLanguage(array $server, array $available, LocaleInterface $default)
60
    {
61
        if (!empty($server['HTTP_ACCEPT_LANGUAGE'])) {
62
            $http_accept_language = strtolower(str_replace(' ', '', $server['HTTP_ACCEPT_LANGUAGE']));
63
            preg_match_all('/(?:([a-z][a-z0-9_-]+)(?:;q=([0-9.]+))?)/', $http_accept_language, $match);
64
            $preferences = array_map(function ($x) {
65
                return $x === '' ? 1.0 : (float) $x;
66
            }, array_combine($match[1], $match[2]));
67
68
            // Need a stable sort, as the original order is significant
69
            $preferences = array_map(function ($x) {
70
                static $n = 0;
71
72
                return array($x, --$n);
73
            }, $preferences);
74
            arsort($preferences);
75
            $preferences = array_map(function ($x) {
76
                return $x[0];
77
            }, $preferences);
78
79
            // If "de-DE" requested, but not "de", then add it at a lower priority
80
            foreach ($preferences as $code => $priority) {
81
                if (preg_match('/^([a-z]+)[^a-z]/', $code, $match) && !isset($preferences[$match[1]])) {
82
                    $preferences[$match[1]] = $priority * 0.5;
83
                }
84
            }
85
86
            foreach (array_keys($preferences) as $code) {
87
                try {
88
                    $locale = Locale::create($code);
89
                    if (in_array($locale, $available)) {
90
                        return $locale;
91
                    }
92
                } catch (DomainException $ex) {
93
                    // An unknown locale?  Ignore it.
94
                }
95
            }
96
        }
97
98
        return $default;
99
    }
100
}
101