Completed
Push — master ( 6a08aa...2252e8 )
by William
03:47
created

Loader::listLocales()   B

Complexity

Conditions 11
Paths 43

Size

Total Lines 73
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 11

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
dl 0
loc 73
ccs 43
cts 43
cp 1
c 1
b 0
f 0
rs 7.3166
cc 11
nc 43
nop 1
crap 11

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
namespace PhpMyAdmin\MoTranslator;
27
28
use function array_push;
29
use function file_exists;
30
use function getenv;
31
use function in_array;
32
use function preg_match;
33
use function sprintf;
34
35
class Loader
36
{
37
    /**
38
     * Loader instance.
39
     *
40
     * @static
41
     * @var Loader
42
     */
43
    private static $instance;
44
45
    /**
46
     * Default gettext domain to use.
47
     *
48
     * @var string
49
     */
50
    private $defaultDomain = '';
51
52
    /**
53
     * Configured locale.
54
     *
55
     * @var string
56
     */
57
    private $locale = '';
58
59
    /**
60
     * Loaded domains.
61
     *
62
     * @var array
63
     */
64
    private $domains = [];
65
66
    /**
67
     * Bound paths for domains.
68
     *
69
     * @var array
70
     */
71
    private $paths = ['' => './'];
72
73
    /**
74
     * Returns the singleton Loader object.
75
     *
76
     * @return Loader object
77
     */
78 20
    public static function getInstance(): Loader
79
    {
80 20
        if (empty(self::$instance)) {
81 4
            self::$instance = new self();
82
        }
83
84 20
        return self::$instance;
85
    }
86
87
    /**
88
     * Loads global localizaton functions.
89
     */
90 8
    public static function loadFunctions(): void
91
    {
92 8
        require_once __DIR__ . '/functions.php';
93 8
    }
94
95
    /**
96
     * Figure out all possible locale names and start with the most
97
     * specific ones.  I.e. for sr_CS.UTF-8@latin, look through all of
98
     * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
99
     *
100
     * @param string $locale Locale code
101
     *
102
     * @return array list of locales to try for any POSIX-style locale specification
103
     */
104 80
    public static function listLocales(string $locale): array
105
    {
106 80
        $localeNames = [];
107
108 80
        if ($locale) {
109 76
            if (preg_match(
110
                '/^(?P<lang>[a-z]{2,3})'      // language code
111
                . '(?:_(?P<country>[A-Z]{2}))?'           // country code
112
                . '(?:\\.(?P<charset>[-A-Za-z0-9_]+))?'   // charset
113 76
                . '(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/', // @ modifier
114 76
                $locale,
115 76
                $matches
116
            )) {
117 72
                $lang = $matches['lang'] ?? null;
118 72
                $country = $matches['country'] ?? null;
119 72
                $charset = $matches['charset'] ?? null;
120 72
                $modifier = $matches['modifier'] ?? null;
121
122 72
                if ($modifier) {
123 20
                    if ($country) {
124 8
                        if ($charset) {
125 8
                            array_push(
126 8
                                $localeNames,
127 8
                                sprintf('%s_%s.%s@%s', $lang, $country, $charset, $modifier)
128
                            );
129
                        }
130
131 8
                        array_push(
132 8
                            $localeNames,
133 8
                            sprintf('%s_%s@%s', $lang, $country, $modifier)
134
                        );
135 12
                    } elseif ($charset) {
136 4
                        array_push(
137 4
                            $localeNames,
138 4
                            sprintf('%s.%s@%s', $lang, $charset, $modifier)
139
                        );
140
                    }
141
142 20
                    array_push(
143 20
                        $localeNames,
144 20
                        sprintf('%s@%s', $lang, $modifier)
145
                    );
146
                }
147
148 72
                if ($country) {
149 36
                    if ($charset) {
150 12
                        array_push(
151 12
                            $localeNames,
152 12
                            sprintf('%s_%s.%s', $lang, $country, $charset)
153
                        );
154
                    }
155
156 36
                    array_push(
157 36
                        $localeNames,
158 36
                        sprintf('%s_%s', $lang, $country)
159
                    );
160 40
                } elseif ($charset) {
161 8
                    array_push(
162 8
                        $localeNames,
163 8
                        sprintf('%s.%s', $lang, $charset)
164
                    );
165
                }
166
167 72
                array_push($localeNames, $lang);
168
            }
169
170
            // If the locale name doesn't match POSIX style, just include it as-is.
171 76
            if (! in_array($locale, $localeNames)) {
172 4
                array_push($localeNames, $locale);
173
            }
174
        }
175
176 80
        return $localeNames;
177
    }
178
179
    /**
180
     * Returns Translator object for domain or for default domain.
181
     *
182
     * @param string $domain Translation domain
183
     */
184 40
    public function getTranslator(string $domain = ''): Translator
185
    {
186 40
        if (empty($domain)) {
187 24
            $domain = $this->defaultDomain;
188
        }
189
190 40
        if (! isset($this->domains[$this->locale])) {
191 36
            $this->domains[$this->locale] = [];
192
        }
193
194 40
        if (! isset($this->domains[$this->locale][$domain])) {
195 36
            if (isset($this->paths[$domain])) {
196 28
                $base = $this->paths[$domain];
197
            } else {
198 8
                $base = './';
199
            }
200
201 36
            $localeNames = $this->listLocales($this->locale);
202
203 36
            $filename = '';
204 36
            foreach ($localeNames as $locale) {
205 36
                $filename = $base . '/' . $locale . '/LC_MESSAGES/' . $domain . '.mo';
206 36
                if (file_exists($filename)) {
207 30
                    break;
208
                }
209
            }
210
211
            // We don't care about invalid path, we will get fallback
212
            // translator here
213 36
            $this->domains[$this->locale][$domain] = new Translator($filename);
214
        }
215
216 40
        return $this->domains[$this->locale][$domain];
217
    }
218
219
    /**
220
     * Sets the path for a domain.
221
     *
222
     * @param string $domain Domain name
223
     * @param string $path   Path where to find locales
224
     */
225 40
    public function bindtextdomain(string $domain, string $path): void
226
    {
227 40
        $this->paths[$domain] = $path;
228 40
    }
229
230
    /**
231
     * Sets the default domain.
232
     *
233
     * @param string $domain Domain name
234
     */
235 40
    public function textdomain(string $domain): void
236
    {
237 40
        $this->defaultDomain = $domain;
238 40
    }
239
240
    /**
241
     * Sets a requested locale.
242
     *
243
     * @param string $locale Locale name
244
     *
245
     * @return string Set or current locale
246
     */
247 40
    public function setlocale(string $locale): string
248
    {
249 40
        if (! empty($locale)) {
250 40
            $this->locale = $locale;
251
        }
252
253 40
        return $this->locale;
254
    }
255
256
    /**
257
     * Detects currently configured locale.
258
     *
259
     * It checks:
260
     *
261
     * - global lang variable
262
     * - environment for LC_ALL, LC_MESSAGES and LANG
263
     *
264
     * @return string with locale name
265
     */
266 8
    public function detectlocale(): string
267
    {
268 8
        if (isset($GLOBALS['lang'])) {
269 4
            return $GLOBALS['lang'];
270
        }
271
272 4
        $locale = getenv('LC_ALL');
273 4
        if ($locale !== false) {
274 4
            return $locale;
275
        }
276
277 4
        $locale = getenv('LC_MESSAGES');
278 4
        if ($locale !== false) {
279 4
            return $locale;
280
        }
281
282 4
        $locale = getenv('LANG');
283 4
        if ($locale !== false) {
284 4
            return $locale;
285
        }
286
287 4
        return 'en';
288
    }
289
}
290