Completed
Push — master ( 29f185...9200bf )
by Michael
18s
created

Locale::getThemeClassFromDirname()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
c 1
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
namespace Xoops;
13
14
use Punic\Data;
15
use Punic\Exception\InvalidLocale;
16
use Xoops\Core\HttpRequest;
17
use Xmf\Request;
18
use Xoops\Core\Theme\XoopsTheme;
19
20
/**
21
 * Locale
22
 *
23
 * @author    trabis <[email protected]>
24
 * @copyright 2011-2015 XOOPS Project (http://xoops.org)
25
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
26
 */
27
class Locale
28
{
29
    const FALLBACK_LOCALE = 'en_US';
30
31
    protected static $currentLocale = null;
32
    protected static $currentTimeZone = null;
33
    protected static $defaultTimeZone = null;
34
    protected static $systemTimeZone = null;
35
    protected static $userLocales = array();
36
37
    /**
38
     * get the current active locale
39
     *
40
     * @return string current locale
41
     */
42 24
    public static function getCurrent()
43
    {
44
        // if none set, take the top of the user locales
45 24
        if (null === static::$currentLocale) {
46 1
            $localeArray = static::getUserLocales();
47 1
            static::$currentLocale = reset($localeArray);
48
        }
49 24
        return static::$currentLocale;
50
    }
51
52
    /**
53
     * Set the current locale
54
     *
55
     * @param string $locale local code
56
     *
57
     * @return void
58
     *
59
     * @throws InvalidLocale
60
     */
61 53
    public static function setCurrent($locale)
62
    {
63 53
        Data::setDefaultLocale($locale);
64 53
        static::$currentLocale = static::normalizeLocale($locale);
65 53
    }
66
67
    /**
68
     * Get the current timezone
69
     *
70
     * @return \DateTimeZone current timezone
71
     */
72 38
    public static function getTimeZone()
73
    {
74 38
        if (null === static::$currentTimeZone) {
75
            $xoops = \Xoops::getInstance();
76
            static::$currentTimeZone = static::getDefaultTimeZone();
77
            if ($xoops->isUser()) {
78
                $tz = $xoops->user->timezone();
79
                if (is_a($tz, '\DateTimeZone')) {
80
                    static::$currentTimeZone = $tz;
81
                } elseif (is_string($tz)) {
82
                    static::$currentTimeZone = static::newDateTimeZone($tz);
83
                }
84
            }
85
        }
86 38
        return static::$currentTimeZone;
87
    }
88
89
    /**
90
     * Set the current timezone
91
     *
92
     * @param \DateTimeZone $timeZone
93
     *
94
     * @return void
95
     */
96 53
    public static function setTimeZone(\DateTimeZone $timeZone)
97
    {
98 53
        static::$currentTimeZone = $timeZone;
99 53
    }
100
101
    /**
102
     * Instantiate a new DateTimeZone object for a timezone name, with fallback to UTC on error
103
     *
104
     * @param string $timeZoneName name of timezone
105
     *
106
     * @return \DateTimeZone
107
     */
108
    protected static function newDateTimeZone($timeZoneName)
109
    {
110
        try {
111
            $timeZone = new \DateTimeZone($timeZoneName);
112
        } catch (\Exception $e) {
113
            $timeZone = new \DateTimeZone('UTC');
114
        }
115
116
        return $timeZone;
117
    }
118
119
    /**
120
     * Get the default timezone as set in default_TZ config
121
     *
122
     * @return \DateTimeZone
123
     */
124 View Code Duplication
    public static function getDefaultTimeZone()
125
    {
126
        if (null === static::$defaultTimeZone) {
127
            $tz = \Xoops::getInstance()->getConfig('default_TZ');
128
            if (is_numeric($tz)) {
129
                $tz = 'UTC';
130
            }
131
            static::$defaultTimeZone = static::newDateTimeZone($tz);
132
        }
133
        return static::$defaultTimeZone;
134
    }
135
136
    /**
137
     * Get the server timezone as set in server_TZ config
138
     *
139
     * @return \DateTimeZone
140
     */
141 View Code Duplication
    public static function getSystemTimeZone()
142
    {
143
        if (null === static::$systemTimeZone) {
144
            $tz = \Xoops::getInstance()->getConfig('server_TZ');
145
            if (is_numeric($tz)) {
146
                $tz = 'UTC';
147
            }
148
            static::$systemTimeZone = static::newDateTimeZone($tz);
149
        }
150
        return static::$systemTimeZone;
151
    }
152
153
    /**
154
     * @param string $name     Name of language file to be loaded, without extension
155
     * @param mixed  $domain   string: Module dirname; global language file will be loaded if
156
     *                                 $domain is set to 'global' or not specified
157
     *                         array:  example; array('Frameworks/moduleclasses/moduleadmin')
158
     * @param string $language Language to be loaded, current language content will be loaded if not specified
159
     *
160
     * @return  boolean
161
     */
162 1
    public static function loadLanguage($name, $domain = '', $language = null)
163
    {
164 1
        if (empty($name)) {
165 1
            return false;
166
        }
167 1
        $language = empty($language) ? \XoopsLocale::getLegacyLanguage() : $language;
168
        // expanded domain to multiple categories, e.g. module:system, framework:filter, etc.
169 1 View Code Duplication
        if ((empty($domain) || 'global' === $domain)) {
170 1
            $path = '';
171
        } else {
172
            $path = (is_array($domain)) ? array_shift($domain) : "modules/{$domain}";
173
        }
174 1
        $xoops = \Xoops::getInstance();
175 1
        $fullPath = $xoops->path("{$path}/language/{$language}/{$name}.php");
176 1
        if (!$ret = \XoopsLoad::loadFile($fullPath)) {
177 1
            $fullPath2 = $xoops->path("{$path}/language/english/{$name}.php");
178 1
            $ret = \XoopsLoad::loadFile($fullPath2);
179
        }
180 1
        return $ret;
181
    }
182
183
    /**
184
     * @param string $domain       module dirname to load, if null will load global locale
185
     * @param string $forcedLocale Locale to be loaded, current language content will be loaded if not specified
186
     *
187
     * @return  boolean
188
     */
189 4
    public static function loadLocale($domain = null, $forcedLocale = null)
190
    {
191 4
        $xoops = \Xoops::getInstance();
192
        // expanded domain to multiple categories, e.g. module:system, framework:filter, etc.
193 4 View Code Duplication
        if ($domain === null) {
194 1
            $path = '';
195 1
            $domain = 'xoops';
196
        } else {
197 3
            $path = (is_array($domain)) ? array_shift($domain) : "modules/{$domain}";
198
        }
199 4
        if (null !== $forcedLocale) {
200
            try {
201
                Data::setDefaultLocale($locale);
202
            } catch (InvalidLocale $e) {
0 ignored issues
show
Bug introduced by
The class Punic\Exception\InvalidLocale does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
203
                return false;
204
            }
205
            $locales = [$forcedLocale];
206
            $locale = $forcedLocale;
207
        } else {
208 4
            $locales = self::getUserLocales();
209 4
            $locale = reset($locales);
210
            try {
211 4
                Data::setDefaultLocale($locale);
212
            } catch (InvalidLocale $e) {
0 ignored issues
show
Bug introduced by
The class Punic\Exception\InvalidLocale does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
213
                $locale = static::FALLBACK_LOCALE;
214
                array_shift($locales);
215
                array_unshift($locales, $locale);
216
                Data::setDefaultLocale($locale);
217
            }
218
        }
219 4
        foreach ($locales as $locale) {
220 4
            $fullPath = $xoops->path("{$path}/locale/{$locale}/locale.php");
221 4
            $fullPath2 = $xoops->path("{$path}/locale/{$locale}/{$locale}.php");
222 4 View Code Duplication
            if (\XoopsLoad::fileExists($fullPath)) {
223 4
                \XoopsLoad::addMap(array($domain . 'locale' => $fullPath));
224 4
                if (\XoopsLoad::fileExists($fullPath2)) {
225 4
                    \XoopsLoad::addMap(array(strtolower($domain . "locale{$locale}") => $fullPath2));
226
                }
227 4
                return true;
228
            }
229
        }
230
        return false;
231
    }
232
233
    /**
234
     * load locale for theme
235
     *
236
     * @param XoopsTheme $theme
237
     *
238
     * @return bool
239
     */
240 4
    public static function loadThemeLocale(XoopsTheme $theme)
241
    {
242 4
        $xoops = \Xoops::getInstance();
243 4
        $locales = self::getUserLocales();
244 4
        foreach ($locales as $locale) {
245 4
            $fullPath = $xoops->path($theme->resourcePath("locale/{$locale}/locale.php"));
246 4
            $fullPath2 = $xoops->path($theme->resourcePath("locale/{$locale}/{$locale}.php"));
247 4 View Code Duplication
            if (\XoopsLoad::fileExists($fullPath)) {
248 4
                \XoopsLoad::addMap(array(strtolower($theme->folderName . 'ThemeLocale') => $fullPath));
249 4
                if (\XoopsLoad::fileExists($fullPath2)) {
250 4
                    \XoopsLoad::addMap(array(strtolower($theme->folderName . "ThemeLocale{$locale}") => $fullPath2));
251
                }
252 4
                return true;
253
            }
254
        }
255
        return false;
256
    }
257
258
    /**
259
     * @return  boolean
260
     */
261 2
    public static function loadMailerLocale()
262
    {
263 2
        $xoops = \Xoops::getInstance();
264 2
        $locales = self::getUserLocales();
265 2
        foreach ($locales as $locale) {
266 2
            $fullPath = $xoops->path("locale/{$locale}/mailer.php");
267 2
            if (\XoopsLoad::fileExists($fullPath)) {
268 2
                \XoopsLoad::addMap(array(strtolower('XoopsMailerLocale') => $fullPath));
269 2
                return true;
270
            }
271
        }
272
        return false;
273
    }
274
275
    /**
276
     * @param string $key
277
     * @param string $dirname
278
     *
279
     * @return string
280
     */
281 3 View Code Duplication
    public static function translate($key, $dirname = 'xoops')
282
    {
283 3
        $class = self::getClassFromDirname($dirname);
284 3
        if (defined("$class::$key")) {
285 1
            return constant("$class::$key");
286 2
        } elseif (defined($key)) {
287
            return constant($key);
288
        }
289 2
        return $key;
290
    }
291
292
    /**
293
     * @param string $key
294
     * @param string $dirname
295
     *
296
     * @return string
297
     */
298 1 View Code Duplication
    public static function translateTheme($key, $dirname = '')
299
    {
300 1
        $class = self::getThemeClassFromDirname($dirname);
301
302 1
        if (defined("$class::$key")) {
303
            return constant("$class::$key");
304 1
        } elseif (defined($key)) {
305
            return constant($key);
306
        }
307 1
        return $key;
308
    }
309
310
    /**
311
     * @param string $dirname
312
     *
313
     * @return string
314
     */
315 3
    protected static function getClassFromDirname($dirname)
316
    {
317 3
        return ucfirst($dirname) . 'Locale';
318
    }
319
320
    /**
321
     * @param string $dirname
322
     *
323
     * @return string
324
     */
325 1
    protected static function getThemeClassFromDirname($dirname = '')
326
    {
327 1
        if (!$dirname) {
328 1
            $dirname = \Xoops::getInstance()->theme()->folderName;
329
        }
330 1
        return ucfirst($dirname) . 'ThemeLocale';
331
    }
332
333
    /**
334
     * getUserLocales()
335
     * Returns the user locales
336
     * Normally it returns an array like this:
337
     * 1. Forced language
338
     * 2. Language in $_GET['lang']
339
     * 3. Language in $_SESSION['lang']
340
     * 4. HTTP_ACCEPT_LANGUAGE
341
     * 5. Fallback language
342
     * Note: duplicate values are deleted.
343
     *
344
     * @return array with the user locales sorted by priority. Highest is best.
345
     */
346 10
    public static function getUserLocales()
0 ignored issues
show
Coding Style introduced by
getUserLocales uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
347
    {
348 10
        if (empty(self::$userLocales)) {
349
            // reset user_lang array
350
            $userLocales = array();
351
352
            // Highest priority: forced language
353
            //if ($this->forcedLang != NULL) {
354
            //    $userLocales[] = $this->forcedLang;
355
            //}
356
357
            // 2nd highest priority: GET parameter 'lang'
358
            $requestLocale = self::normalizeLocale(Request::getString('lang', ''));
359
            if (!empty($requestLocale)) {
360
                $userLocales[] = $requestLocale;
361
            }
362
363
            // 3rd highest priority: SESSION parameter 'lang'
364
            if (isset($_SESSION['lang']) && is_string($_SESSION['lang'])) {
365
                $userLocales[] = self::normalizeLocale($_SESSION['lang']);
366
            }
367
368
            // 4th highest priority: HTTP_ACCEPT_LANGUAGE
369
            $browserLocales = HttpRequest::getInstance()->getAcceptedLanguages();
370
            $browserLocales = array_keys($browserLocales);
371
            foreach ($browserLocales as $bloc) {
372
                $userLocales[] = self::normalizeLocale($bloc);
373
            }
374
375
            $configLocale = \Xoops::getInstance()->getConfig('locale');
376
            if (!empty($configLocale)) {
377
                $userLocales[] = $configLocale;
378
            }
379
380
            // Lowest priority: fallback
381
            $userLocales[] = static::FALLBACK_LOCALE;
382
383
            static::$userLocales = array_unique($userLocales);
384
        }
385 10
        return static::$userLocales;
386
    }
387
388
    /**
389
     * Convert a locale designation to a normal form ll_Ssss_CC, where
390
     *   ll   is language code
391
     *   Ssss is the script code, if specified
392
     *   CC   is the country code, if specified
393
     *
394
     * @param string $locale     locale code
395
     * @param string $separator  string to use to join locale parts
396
     * @param bool   $withScript include script if specified, always remove if false
397
     *
398
     * @return string normalized locale, or empty string on error
399
     */
400 69
    public static function normalizeLocale($locale, $separator = '_', $withScript = true)
401
    {
402
        try {
403 69
            $keys = Data::explodeLocale($locale);
404 69
            $key = strtolower($keys['language']);
405 69
            $key .= (empty($keys['script']) || false===$withScript) ?
406 69
                '' : $separator . ucfirst(strtolower($keys['script']));
407 69
            $key .= empty($keys['territory']) ? '' : $separator . strtoupper($keys['territory']);
408
        } catch (InvalidLocale $e) {
0 ignored issues
show
Bug introduced by
The class Punic\Exception\InvalidLocale does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
409
            $key = '';
410
        }
411
412 69
        return $key;
413
    }
414
415
    /**
416
     * Return a normalized form of a resource domain. A resource domain is always lowercase.
417
     *
418
     * @param string $domain resource domain (usually a module dirname)
419
     *
420
     * @return string normalized resource domain
421
     */
422 1
    public static function normalizeDomain($domain)
423
    {
424 1
        return strtolower($domain);
425
    }
426
}
427