Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.56% covered (warning)
80.56%
29 / 36
69.23% covered (warning)
69.23%
9 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
LocaleSettings
80.56% covered (warning)
80.56%
29 / 36
69.23% covered (warning)
69.23%
9 / 13
21.65
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 browserLanguageDetectionEnabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isRightToLeftLocale
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUserLocale
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getDefaultLocale
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEnabledLocales
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFallbackLocales
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRightToLeftLocales
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 parseDefaultLocale
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 parseFallbackLocales
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 parseRightToLeftLocales
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 markLocaleInitialized
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isLocaleInitialized
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * VuFind Locale Settings
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2018,
9 * Copyright (C) Leipzig University Library <info@ub.uni-leipzig.de> 2018.
10 * Copyright (C) The National Library of Finland 2023.
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 version 2,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24 *
25 * @category VuFind
26 * @package  I18n\Locale
27 * @author   Demian Katz <demian.katz@villanova.edu>
28 * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
29 * @author   Ere Maijala <ere.maijala@helsinki.fi>
30 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
31 * @link     https://vufind.org Main Site
32 */
33
34namespace VuFind\I18n\Locale;
35
36use Laminas\Config\Config;
37
38use function array_key_exists;
39use function in_array;
40
41/**
42 * VuFind Locale Settings
43 *
44 * @category VuFind
45 * @package  I18n\Locale
46 * @author   Demian Katz <demian.katz@villanova.edu>
47 * @author   Sebastian Kehr <kehr@ub.uni-leipzig.de>
48 * @author   Ere Maijala <ere.maijala@helsinki.fi>
49 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
50 * @link     https://vufind.org Main Site
51 */
52class LocaleSettings
53{
54    /**
55     * Default locale (code)
56     *
57     * @var string
58     */
59    protected $defaultLocale;
60
61    /**
62     * Associative (code => description) array of enabled locales.
63     *
64     * @var array
65     */
66    protected $enabledLocales;
67
68    /**
69     * Prioritized array of locales to use when strings are missing from the
70     * primary language file.
71     *
72     * @var string[]
73     */
74    protected $fallbackLocales;
75
76    /**
77     * Array of locales that use right-to-left formatting.
78     *
79     * @var string[]
80     */
81    protected $rightToLeftLocales;
82
83    /**
84     * Array of locales that have been initialized.
85     *
86     * @var string[]
87     */
88    protected $initializedLocales = [];
89
90    /**
91     * Should we use auto-detect language based on browser settings?
92     *
93     * @var bool
94     */
95    protected $browserDetectLanguage;
96
97    /**
98     * Constructor
99     *
100     * @param Config $config Configuration object
101     */
102    public function __construct(Config $config)
103    {
104        $this->enabledLocales = $config->Languages ? $config->Languages->toArray()
105            : [];
106        $this->browserDetectLanguage
107            = (bool)($config->Site->browserDetectLanguage ?? true);
108        $this->defaultLocale = $this->parseDefaultLocale($config);
109        $this->fallbackLocales = $this->parseFallbackLocales($config);
110        $this->rightToLeftLocales = $this->parseRightToLeftLocales($config);
111    }
112
113    /**
114     * Should we use auto-detect language based on browser settings?
115     *
116     * @return bool
117     */
118    public function browserLanguageDetectionEnabled(): bool
119    {
120        return $this->browserDetectLanguage;
121    }
122
123    /**
124     * Identify whether a particular locale uses right-to-left layout.
125     *
126     * @param string $locale Locale to check
127     *
128     * @return bool
129     */
130    public function isRightToLeftLocale(string $locale): bool
131    {
132        return in_array($locale, $this->rightToLeftLocales);
133    }
134
135    /**
136     * Get the current active locale.
137     *
138     * @return string
139     */
140    public function getUserLocale(): string
141    {
142        if (!class_exists(\Locale::class)) {
143            error_log('Locale class is missing; please enable intl extension.');
144            return $this->getDefaultLocale();
145        }
146        return \Locale::getDefault();
147    }
148
149    /**
150     * Get default locale.
151     *
152     * @return string
153     */
154    public function getDefaultLocale(): string
155    {
156        return $this->defaultLocale;
157    }
158
159    /**
160     * Get an associative (code => description) array of enabled locales.
161     *
162     * @return array
163     */
164    public function getEnabledLocales(): array
165    {
166        return $this->enabledLocales;
167    }
168
169    /**
170     * Get a prioritized array of locales to use when strings are missing from the
171     * primary language file.
172     *
173     * @return string[]
174     */
175    public function getFallbackLocales(): array
176    {
177        return $this->fallbackLocales;
178    }
179
180    /**
181     * Get an array of locales that use right-to-left formatting.
182     *
183     * @return string[]
184     */
185    public function getRightToLeftLocales(): array
186    {
187        return $this->rightToLeftLocales;
188    }
189
190    /**
191     * Extract and validate default locale from configuration.
192     *
193     * @param Config $config Configuration
194     *
195     * @return string
196     * @throws \Exception
197     */
198    protected function parseDefaultLocale(Config $config): string
199    {
200        $locale = $config->Site->language ?? null;
201        if (empty($locale)) {
202            throw new \Exception('Default locale not configured!');
203        }
204        if (!array_key_exists($locale, $this->enabledLocales)) {
205            throw new \Exception("Configured default locale '$locale' not enabled!");
206        }
207        return $locale;
208    }
209
210    /**
211     * Parses the configured language fallbacks.
212     *
213     * @param Config $config Configuration
214     *
215     * @return string[]
216     */
217    protected function parseFallbackLocales(Config $config): array
218    {
219        $value = trim($config->Site->fallback_languages ?? '', ',');
220        $languages = $value ? array_map('trim', explode(',', $value)) : [];
221        return array_unique(
222            [
223                ...$languages,
224                $config->Site->language,
225                'en',
226            ]
227        );
228    }
229
230    /**
231     * Parses the right-to-left language configuration.
232     *
233     * @param Config $config Configuration
234     *
235     * @return string[]
236     */
237    protected function parseRightToLeftLocales(Config $config): array
238    {
239        $value = trim($config->LanguageSettings->rtl_langs ?? '', ',');
240        return $value ? array_map('trim', explode(',', $value)) : [];
241    }
242
243    /**
244     * Mark a locale as initialized.
245     *
246     * @param string $locale Locale code
247     *
248     * @return void
249     */
250    public function markLocaleInitialized($locale)
251    {
252        $this->initializedLocales[] = $locale;
253    }
254
255    /**
256     * Is the locale already initialized?
257     *
258     * @param string $locale Locale code
259     *
260     * @return bool
261     */
262    public function isLocaleInitialized($locale)
263    {
264        return in_array($locale, $this->initializedLocales);
265    }
266}