]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/I18n.php
Try to find default lang for all supported locales
[galette.git] / galette / lib / Galette / Core / I18n.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * i18n handling
7 *
8 * PHP version 5
9 *
10 * Copyright © 2007-2018 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Core
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2007-2020 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Available since 0.7dev - 2007-07-06
35 */
36
37 namespace Galette\Core;
38
39 use Analog\Analog;
40
41 /**
42 * i18n handling
43 *
44 * @category Core
45 * @name i18n
46 * @package Galette
47 * @author Johan Cwiklinski <johan@x-tnd.be>
48 * @copyright 2007-2020 The Galette Team
49 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
50 * @link http://galette.tuxfamily.org
51 * @since Available since 0.7dev - 2007-07-06
52 */
53
54 class I18n
55 {
56 private $id;
57 private $longid;
58 private $name;
59 private $abbrev;
60
61 public const DEFAULT_LANG = 'fr_FR';
62
63 private $dir = 'lang/';
64 private $path;
65
66 private $rtl_langs = [
67 'ar',
68 'az',
69 'fa',
70 'he',
71 'ur'
72 ];
73
74 /**
75 * Default constructor.
76 * Initialize default language and set environment variables
77 *
78 * @param bool $lang true if there were a language change
79 *
80 * @return void
81 */
82 public function __construct($lang = false)
83 {
84 $this->path = GALETTE_ROOT . $this->dir;
85 $this->guessLangs();
86
87 if (!$lang) {
88 //try to determine user language
89 $dlang = self::DEFAULT_LANG;
90 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
91 $preferred_locales = array_reduce(
92 explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']),
93 function ($res, $el) {
94 list($l, $q) = array_merge(explode(';q=', $el), [1]);
95 $res[$l] = (float) $q;
96 return $res;
97 }, []);
98 arsort($preferred_locales);
99
100 foreach (array_keys($preferred_locales) as $preferred_locale) {
101 if (array_key_exists(str_replace('-', '_', $preferred_locale), $this->langs)) {
102 $dlang = str_replace('-', '_', $preferred_locale);
103 break;
104 }
105 }
106 }
107 $this->changeLanguage($dlang);
108 } else {
109 $this->load($lang);
110 }
111 }
112
113 /**
114 * Load language parameters
115 *
116 * @param string $id Identifier for requested language
117 *
118 * @return void
119 */
120 public function changeLanguage($id)
121 {
122 Analog::log('Trying to set locale to ' . $id, Analog::DEBUG);
123 $this->load($id);
124 $this->updateEnv();
125 }
126
127 /**
128 * Update environment according to locale.
129 * Mainly used at app initialization or at login
130 *
131 * @return void
132 */
133 public function updateEnv()
134 {
135 global $translator;
136
137 setlocale(LC_ALL, $this->getLongID());
138
139 if (
140 putenv("LANG=" . $this->getLongID())
141 or putenv("LANGUAGE=" . $this->getLongID())
142 or putenv("LC_ALL=" . $this->getLongID())
143 ) {
144 $textdomain = realpath(GALETTE_ROOT . 'lang');
145 //main translation domain
146 $domain = 'galette';
147 bindtextdomain($domain, $textdomain);
148 //set default translation domain and encoding
149 textdomain($domain);
150 bind_textdomain_codeset($domain, 'UTF-8');
151 }
152 if ($translator) {
153 $translator->setLocale($this->getLongID());
154 }
155 }
156
157 /**
158 * Load a language
159 *
160 * @param string $id identifier for the language to load
161 *
162 * @return void
163 */
164 private function load($id)
165 {
166 if (!isset($this->langs[$id])) {
167 $msg = 'Lang ' . $id . ' does not exist, switching to default.';
168 Analog::log($msg, Analog::WARNING);
169 $id = self::DEFAULT_LANG;
170 }
171 $lang = $this->langs[$id];
172 $this->id = $id;
173 $this->longid = $lang['long'];
174 $this->name = $lang['longname'];
175 $this->abbrev = $lang['shortname'];
176 }
177
178 /**
179 * List languages
180 *
181 * @return array list of all active languages
182 */
183 public function getList()
184 {
185 $result = array();
186 foreach (array_keys($this->langs) as $id) {
187 $result[] = new I18n((string)$id);
188 }
189
190 return $result;
191 }
192
193 /**
194 * List languages as simple array
195 *
196 * @return array
197 */
198 public function getArrayList()
199 {
200 $list = $this->getList();
201 $al = array();
202 foreach ($list as $l) {
203 //FIXME: should use mb with something like:
204 //$strlen = mb_strlen($string, $encoding);
205 //$firstChar = mb_substr($string, 0, 1, $encoding);
206 //$then = mb_substr($string, 1, $strlen - 1, $encoding);
207 //return mb_strtoupper($firstChar, $encoding) . $then;
208 $al[$l->getID()] = $l->getName();
209 }
210 return $al;
211 }
212
213 /**
214 * Gets language full name from its ID
215 *
216 * @param string $id the language identifier
217 *
218 * @return string name for specified identifier
219 */
220 public function getNameFromId($id)
221 {
222 if (isset($this->langs[$id])) {
223 return $this->langs[$id]['longname'];
224 } else {
225 return str_replace(
226 '%lang',
227 $id,
228 _T('Unknown lang (%lang)')
229 );
230 }
231 }
232
233 /**
234 * Get current id
235 *
236 * @return string current language identifier
237 */
238 public function getID()
239 {
240 return $this->id;
241 }
242
243 /**
244 * Get long identifier
245 *
246 * @return string current language long identifier
247 */
248 public function getLongID()
249 {
250 return $this->longid;
251 }
252
253 /**
254 * Get current name
255 *
256 * @return string current language name
257 */
258 public function getName()
259 {
260 return $this->name;
261 }
262
263 /**
264 * Get current abreviation
265 *
266 * @return string current language abreviation
267 */
268 public function getAbbrev()
269 {
270 return $this->abbrev;
271 }
272
273 /**
274 * Is a string seem to be UTF-8 one ?
275 *
276 * @param string $str string to analyze
277 *
278 * @return boolean
279 */
280 public static function seemUtf8($str)
281 {
282 return mb_check_encoding($str, 'UTF-8');
283 }
284
285 /**
286 * Guess available languages from directories
287 * that are present in the lang directory.
288 *
289 * Will store foud langs in class langs variable and return it.
290 *
291 * @return array
292 */
293 public function guessLangs()
294 {
295 $dir = new \DirectoryIterator($this->path);
296 $langs = [];
297 foreach ($dir as $fileinfo) {
298 if ($fileinfo->isDir() && !$fileinfo->isDot()) {
299 $lang = $fileinfo->getFilename();
300 $real_lang = str_replace('.utf8', '', $lang);
301 $parsed_lang = \Locale::parseLocale($lang);
302
303 $langs[$real_lang] = [
304 'long' => $lang,
305 'shortname' => $parsed_lang['language'] ?? '',
306 'longname' => ucfirst(
307 \Locale::getDisplayLanguage(
308 $lang,
309 $real_lang
310 )
311 )
312 ];
313 }
314 }
315 ksort($langs);
316 $this->langs = $langs;
317 return $this->langs;
318 }
319
320 /**
321 * Is current language RTL?
322 *
323 * @return boolean
324 */
325 public function isRTL()
326 {
327 return in_array(
328 $this->getAbbrev(),
329 $this->rtl_langs
330 );
331 }
332 }