Passed
Push — master ( a94cfc...298752 )
by Maurício
10:31
created

Loader::listLocales()   C

Complexity

Conditions 12
Paths 83

Size

Total Lines 77
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 77
rs 6.9666
ccs 43
cts 43
cp 1
cc 12
nc 83
nop 1
crap 12

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
    Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
7
    Copyright (c) 2009 Danilo Segan <[email protected]>
8
    Copyright (c) 2016 Michal Čihař <[email protected]>
9
10
    This file is part of MoTranslator.
11
12
    This program is free software; you can redistribute it and/or modify
13
    it under the terms of the GNU General Public License as published by
14
    the Free Software Foundation; either version 2 of the License, or
15
    (at your option) any later version.
16
17
    This program is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
22
    You should have received a copy of the GNU General Public License along
23
    with this program; if not, write to the Free Software Foundation, Inc.,
24
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
*/
26
27
namespace PhpMyAdmin\MoTranslator;
28
29
use PhpMyAdmin\MoTranslator\Cache\CacheFactoryInterface;
30
use PhpMyAdmin\MoTranslator\Cache\InMemoryCache;
31
32
use function array_push;
33
use function file_exists;
34
use function getenv;
35
use function in_array;
36
use function preg_match;
37
use function sprintf;
38
39
class Loader
40
{
41
    /**
42
     * Loader instance.
43
     *
44
     * @static
45
     * @var Loader
46
     */
47
    private static $instance = null;
48
49
    /**
50
     * Factory to return a factory responsible for returning a `CacheInterface`
51
     *
52
     * @static
53
     * @var CacheFactoryInterface|null
54
     */
55
    private static $cacheFactory = null;
56
57
    /**
58
     * Default gettext domain to use.
59
     *
60
     * @var string
61
     */
62
    private $defaultDomain = '';
63
64
    /**
65
     * Configured locale.
66
     *
67
     * @var string
68
     */
69
    private $locale = '';
70
71
    /**
72
     * Loaded domains.
73
     *
74
     * @var array<string,array<string,Translator>>
75
     */
76
    private $domains = [];
77
78
    /**
79
     * Bound paths for domains.
80
     *
81
     * @var array<string,string>
82
     */
83
    private $paths = ['' => './'];
84
85
    /**
86
     * Returns the singleton Loader object.
87
     *
88
     * @return Loader object
89
     */
90 84
    public static function getInstance(): Loader
91
    {
92 84
        if (self::$instance === null) {
93 14
            self::$instance = new self();
94
        }
95
96 84
        return self::$instance;
97
    }
98
99
    /**
100
     * Loads global localization functions.
101
     */
102 28
    public static function loadFunctions(): void
103
    {
104 28
        require_once __DIR__ . '/functions.php';
105 4
    }
106
107
    /**
108
     * Figure out all possible locale names and start with the most
109
     * specific ones.  I.e. for sr_CS.UTF-8@latin, look through all of
110
     * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
111
     *
112
     * @param string $locale Locale code
113
     *
114
     * @return string[] list of locales to try for any POSIX-style locale specification
115
     */
116 294
    public static function listLocales(string $locale): array
117
    {
118 294
        $localeNames = [];
119
120 294
        if ($locale) {
121
            if (
122 280
                preg_match(
123
                    '/^(?P<lang>[a-z]{2,3})' // language code
124
                    . '(?:_(?P<country>[A-Z]{2}))?' // country code
125
                    . '(?:\\.(?P<charset>[-A-Za-z0-9_]+))?' // charset
126 40
                    . '(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/', // @ modifier
127 40
                    $locale,
128 40
                    $matches
129
                )
130
            ) {
131 266
                $lang = $matches['lang'] ?? null;
132 266
                $country = $matches['country'] ?? null;
133 266
                $charset = $matches['charset'] ?? null;
134 266
                $modifier = $matches['modifier'] ?? null;
135
136 266
                if ($modifier) {
137 70
                    if ($country) {
138 28
                        if ($charset) {
139 28
                            array_push(
140 4
                                $localeNames,
141 28
                                sprintf('%s_%s.%s@%s', $lang, $country, $charset, $modifier)
142
                            );
143
                        }
144
145 28
                        array_push(
146 4
                            $localeNames,
147 28
                            sprintf('%s_%s@%s', $lang, $country, $modifier)
148
                        );
149 42
                    } elseif ($charset) {
150 14
                        array_push(
151 2
                            $localeNames,
152 14
                            sprintf('%s.%s@%s', $lang, $charset, $modifier)
153
                        );
154
                    }
155
156 70
                    array_push(
157 10
                        $localeNames,
158 70
                        sprintf('%s@%s', $lang, $modifier)
159
                    );
160
                }
161
162 266
                if ($country) {
163 140
                    if ($charset) {
164 42
                        array_push(
165 6
                            $localeNames,
166 42
                            sprintf('%s_%s.%s', $lang, $country, $charset)
167
                        );
168
                    }
169
170 140
                    array_push(
171 20
                        $localeNames,
172 140
                        sprintf('%s_%s', $lang, $country)
173
                    );
174 140
                } elseif ($charset) {
175 28
                    array_push(
176 4
                        $localeNames,
177 28
                        sprintf('%s.%s', $lang, $charset)
178
                    );
179
                }
180
181 266
                if ($lang !== null) {
182
                    array_push($localeNames, $lang);
183
                }
184
            }
185 280
186 14
            // If the locale name doesn't match POSIX style, just include it as-is.
187
            if (! in_array($locale, $localeNames)) {
188
                array_push($localeNames, $locale);
189
            }
190 294
        }
191
192
        return $localeNames;
193
    }
194
195
    /**
196 14
     * Sets factory responsible for composing a `CacheInterface`
197
     */
198 14
    public static function setCacheFactory(?CacheFactoryInterface $cacheFactory): void
199 2
    {
200
        self::$cacheFactory = $cacheFactory;
201
    }
202
203
    /**
204
     * Returns Translator object for domain or for default domain.
205
     *
206 154
     * @param string $domain Translation domain
207
     */
208 154
    public function getTranslator(string $domain = ''): Translator
209 84
    {
210
        if (empty($domain)) {
211
            $domain = $this->defaultDomain;
212 154
        }
213 126
214
        if (! isset($this->domains[$this->locale])) {
215
            $this->domains[$this->locale] = [];
216 154
        }
217 140
218 112
        if (! isset($this->domains[$this->locale][$domain])) {
219
            if (isset($this->paths[$domain])) {
220 28
                $base = $this->paths[$domain];
221
            } else {
222
                $base = './';
223 140
            }
224
225 140
            $localeNames = $this->listLocales($this->locale);
226 140
227 140
            $filename = '';
228 140
            foreach ($localeNames as $locale) {
229 98
                $filename = $base . '/' . $locale . '/LC_MESSAGES/' . $domain . '.mo';
230
                if (file_exists($filename)) {
231
                    break;
232
                }
233
            }
234
235 140
            // We don't care about invalid path, we will get fallback
236 140
            // translator here
237 14
            $moParser = new MoParser($filename);
238
            if (self::$cacheFactory instanceof CacheFactoryInterface) {
239 126
                $cache = self::$cacheFactory->getInstance($moParser, $this->locale, $domain);
240
            } else {
241
                $cache = new InMemoryCache($moParser);
242 140
            }
243
244
            $this->domains[$this->locale][$domain] = new Translator($cache);
245 154
        }
246
247
        return $this->domains[$this->locale][$domain];
248
    }
249
250
    /**
251
     * Sets the path for a domain.
252
     *
253
     * @param string $domain Domain name
254 154
     * @param string $path   Path where to find locales
255
     */
256 154
    public function bindtextdomain(string $domain, string $path): void
257 22
    {
258
        $this->paths[$domain] = $path;
259
    }
260
261
    /**
262
     * Sets the default domain.
263
     *
264 140
     * @param string $domain Domain name
265
     */
266 140
    public function textdomain(string $domain): void
267 20
    {
268
        $this->defaultDomain = $domain;
269
    }
270
271
    /**
272
     * Sets a requested locale.
273
     *
274
     * @param string $locale Locale name
275
     *
276 154
     * @return string Set or current locale
277
     */
278 154
    public function setlocale(string $locale): string
279 154
    {
280
        if (! empty($locale)) {
281
            $this->locale = $locale;
282 154
        }
283
284
        return $this->locale;
285
    }
286
287
    /**
288
     * Detects currently configured locale.
289
     *
290
     * It checks:
291
     *
292
     * - global lang variable
293
     * - environment for LC_ALL, LC_MESSAGES and LANG
294
     *
295 28
     * @return string with locale name
296
     */
297 28
    public function detectlocale(): string
298 14
    {
299
        if (isset($GLOBALS['lang'])) {
300
            return $GLOBALS['lang'];
301 14
        }
302 14
303 14
        $locale = getenv('LC_ALL');
304
        if ($locale !== false) {
305
            return $locale;
306 14
        }
307 14
308 14
        $locale = getenv('LC_MESSAGES');
309
        if ($locale !== false) {
310
            return $locale;
311 14
        }
312 14
313 14
        $locale = getenv('LANG');
314
        if ($locale !== false) {
315
            return $locale;
316 14
        }
317
318
        return 'en';
319
    }
320
}
321