1 |
<?php |
2 |
/** |
3 |
*/ |
4 |
|
5 |
define('G_VHOST', $_SERVER['SERVER_NAME']); |
6 |
|
7 |
// languages for home |
8 |
$langs = array( |
9 |
'ast' => 'Asturianu', |
10 |
'ca' => 'Català', |
11 |
'cs' => 'Čeština', |
12 |
'de' => 'Deutsch', |
13 |
'el' => 'Ελληνικά', |
14 |
'en' => 'English', |
15 |
'eo' => 'Esperanto', |
16 |
'es' => 'Español', |
17 |
'et' => 'Eesti', |
18 |
'fi' => 'Suomeksi', |
19 |
'fr' => 'Français', |
20 |
'id' => 'Bahasa Indonesia', |
21 |
'it' => 'Italiano', |
22 |
'lv' => 'Latviešu', |
23 |
'nb' => 'Bokmål', |
24 |
'nl' => 'Nederlands', |
25 |
'pl' => 'Polski', |
26 |
'pt' => 'Português', |
27 |
'pt-br' => 'Português do Brasil', |
28 |
'ro' => 'Română', |
29 |
'ru' => 'Русский', |
30 |
'sl' => 'Slovenščina', |
31 |
'tr' => 'Türkçe', |
32 |
'uk' => 'Українська', |
33 |
'ur' => 'اردو', |
34 |
'zh-cn' => '简体中文', |
35 |
'zh-tw' => '正體中文' |
36 |
); |
37 |
|
38 |
// TODO (rda) define fallback languages for each language |
39 |
// for instance, pt-br could fallback on pt and pt on pt-br (but without |
40 |
// a cycle) then on es, etc. |
41 |
$i18n_fallback_rules = array( |
42 |
'pt-br' => 'pt', |
43 |
'pt' => 'pt-br' |
44 |
); |
45 |
|
46 |
$domains_lang = array( |
47 |
'mageia.fr' => 'fr', |
48 |
'mageia.it' => 'it', |
49 |
'mageia.ro' => 'ro', |
50 |
); |
51 |
|
52 |
/** |
53 |
* Redirect to a localized path, depending on incoming TLD. |
54 |
* Only manages redirections to main home path. |
55 |
* |
56 |
* @param string $tld |
57 |
* @param array $domains_lang |
58 |
* @param string $vhost |
59 |
* |
60 |
* @return void |
61 |
*/ |
62 |
function tld_redirect($tld, $domains_lang, $vhost) |
63 |
{ |
64 |
domain_redirect('mageia.' . $tld, $domains_lang, $vhost); |
65 |
} |
66 |
|
67 |
/** |
68 |
* Redirect to a localized path, depending on incoming full domain. |
69 |
* Only manages redirections to main home path. |
70 |
* |
71 |
* @param string $host |
72 |
* @param array $domains_lang |
73 |
* @param string $vhost |
74 |
* |
75 |
* @return void |
76 |
*/ |
77 |
function domain_redirect($host, $domains_lang, $vhost) |
78 |
{ |
79 |
$host = str_replace('www.', '', $host); |
80 |
|
81 |
if (array_key_exists($host, $domains_lang)) { |
82 |
$path = $domains_lang[$host] . '/'; |
83 |
header ('HTTP/1.1 301 Moved Permanently'); |
84 |
} else { |
85 |
$path = '?langs'; |
86 |
} |
87 |
header(sprintf('Location: %s://%s/%s', 'http', $vhost, $path)); |
88 |
die; |
89 |
} |
90 |
|
91 |
|
92 |
/** |
93 |
* Redirect to a localized path, after browser Accept-Language prefs. |
94 |
* Return the path. |
95 |
* Do not exit the process. |
96 |
* |
97 |
* @param array $langs list of languages |
98 |
* @param string $page optional path to which we want to redirect |
99 |
* @param string $default_locale |
100 |
* @param string $force_accept_language replace remote browser HTTP_ACCEPT_LANGUAGE request header |
101 |
* @param boolean $do_redirect |
102 |
* |
103 |
* @return string |
104 |
*/ |
105 |
function relocate($langs, $page = '', $default_locale = 'en', $force_accept_language = null, $do_redirect = true) |
106 |
{ |
107 |
require_once 'localeDetection.class.php'; |
108 |
|
109 |
$locale = new ChooseLocale(array_keys($langs), $force_accept_language); |
110 |
$locale->setDefaultLocale($default_locale); |
111 |
|
112 |
$relocate = sprintf('/%s/%s', $locale->getCompatibleLocale(), $page); |
113 |
$relocate = str_replace('//', '/', $relocate); |
114 |
|
115 |
if ('cli' != PHP_SAPI && do_redirect) { |
116 |
header('Location: ' . $relocate); |
117 |
} |
118 |
|
119 |
return $relocate; |
120 |
} |
121 |
|
122 |
|
123 |
/** |
124 |
* Create string pt_br from string pt-br and alike but leave the rest as is |
125 |
* Return string. |
126 |
* Do not exit the process. |
127 |
* |
128 |
* @param string $locale which we want to change |
129 |
* @param boolean $version_of_locale_uppercase optional, true if we want second part in uppercase (pt_BR) |
130 |
* |
131 |
* @return string |
132 |
*/ |
133 |
function locale_hyphen_underscore($locale, $version_of_locale_uppercase = false) |
134 |
{ |
135 |
preg_match("/(..)(-)(..)/", $locale, $parsed_locale); |
136 |
if(isset($parsed_locale[3])) { |
137 |
return $parsed_locale[1] . '_' . ($version_of_locale_uppercase ? strtoupper($parsed_locale[3]) : $parsed_locale[3]); |
138 |
} else { |
139 |
return $locale; |
140 |
} |
141 |
} |
142 |
|
143 |
|
144 |
/** |
145 |
*/ |
146 |
function show_langs($langs) |
147 |
{ |
148 |
header('Content-Type: text/html; charset=utf-8'); |
149 |
$count = count($langs); |
150 |
$s = <<<S |
151 |
<!DOCTYPE html> |
152 |
<html lang="en"> |
153 |
<head> |
154 |
<charset="utf-8"> |
155 |
<meta name="robots" content="noindex,nosnippet"> |
156 |
<title>Mageia</title> |
157 |
</head> |
158 |
<body> |
159 |
<p><a href="/">Mageia.org</a> is currently available in {$count} languages:</p> |
160 |
<ul> |
161 |
S; |
162 |
foreach ($langs as $k => $v) { |
163 |
$s .= sprintf('<li><a href="/%s/" hreflang="%s">%s</a></li>', |
164 |
$k, $k, $v); |
165 |
} |
166 |
echo $s, '</ul><hr />', |
167 |
'<p>If you would like to help improving this Web site or its translations, ', |
168 |
'check out our <a href="/langs/report.php">translation report page</a> ', |
169 |
'<a href="https://wiki.mageia.org/en/Web_team">Web</a> and ', |
170 |
'<a href="https://wiki.mageia.org/en/Internationalisation_Team_(i18n)">localization</a> teams!</p>', |
171 |
'<p>Your browser Accept-Language is: ', $_SERVER['HTTP_ACCEPT_LANGUAGE'], '.</p>', |
172 |
'<hr /></body></html>'; |
173 |
} |
174 |
|
175 |
|
176 |
/** |
177 |
* Class regrouping basic methods for i18n strings in their current forms. |
178 |
* |
179 |
*/ |
180 |
class i18n |
181 |
{ |
182 |
/** |
183 |
* @param string $request_uri |
184 |
* |
185 |
* @return string |
186 |
*/ |
187 |
public static function get_language_from_url($request_uri) |
188 |
{ |
189 |
$l = explode('/', $request_uri); |
190 |
return $l[1]; |
191 |
} |
192 |
|
193 |
/** |
194 |
* Return language strings in $strings that match $lang, |
195 |
* and merge with pre-loaded strings matching $fallback_lang. |
196 |
* |
197 |
* @param array $strings array('fr' => array(strings...), 'en' => array(...)) |
198 |
* @param string $lang |
199 |
* @param string $fallback_lang |
200 |
* |
201 |
* @return array |
202 |
*/ |
203 |
public static function get_strings($strings, $lang, $fallback_rules = null) |
204 |
{ |
205 |
$use_lang = self::get_fallback_language($lang, array_keys($strings), $fallback_rules); |
206 |
|
207 |
return array_merge($strings['en'], $strings[$use_lang]); |
208 |
} |
209 |
|
210 |
/** |
211 |
* Return a language we know we have support for, or a fallback language. |
212 |
* |
213 |
* Important note: this is supposed to be used only once in a row; do not |
214 |
* chain this method over itself as you may end up with an infinite loop |
215 |
* (depends on $fallback_rules contents). |
216 |
* |
217 |
* TODO (rda) implement this into an object, so we can check several langs |
218 |
* in a row for a same document, with several fallback hops, without a cycle. |
219 |
* |
220 |
* @param string $lang language we wish to use |
221 |
* @param array $known_langs list of languages we support |
222 |
* @param mixed $fallback_rules |
223 |
* |
224 |
* @return string |
225 |
*/ |
226 |
public static function get_fallback_language($lang, $known_langs, $fallback_rules = null) |
227 |
{ |
228 |
$ret = 'en'; |
229 |
|
230 |
if (in_array($lang, $known_langs)) { |
231 |
$ret = $lang; |
232 |
} |
233 |
else { |
234 |
if (is_string($fallback_rules)) { |
235 |
$ret = $fallback_rules; |
236 |
} |
237 |
elseif (is_array($fallback_rules) |
238 |
&& array_key_exists($lang, $fallback_rules)) { |
239 |
|
240 |
$ret = $fallback_rules[$lang]; |
241 |
} |
242 |
|
243 |
if (!in_array($ret, $known_langs)) |
244 |
$ret = 'en'; |
245 |
} |
246 |
|
247 |
return $ret; |
248 |
} |
249 |
|
250 |
/** |
251 |
* Get a translated string to output. |
252 |
* |
253 |
* Use it when you need to capture the string to output. |
254 |
* |
255 |
* Examples: |
256 |
* |
257 |
* echo _t("Hello."), _t("How are you?"); |
258 |
* |
259 |
* |
260 |
* @param string $s string to localize |
261 |
* @param array $opt translated strings list |
262 |
* @param string $post string suffix. Useful to prevent non-breaking lines. |
263 |
* |
264 |
* @return null|string |
265 |
*/ |
266 |
public static function _t($s = null, $opt = null, $post = ' ') |
267 |
{ |
268 |
return self::_d($s, $opt) . $post; |
269 |
} |
270 |
|
271 |
/** |
272 |
* Lookup for translated string for $s |
273 |
* in global array $_t (yes, ugly) |
274 |
* OR in $opt param. |
275 |
* |
276 |
* $_t or $opt is the list of string for the current locale. |
277 |
* |
278 |
* Use it when you need to get the exact, char-specific translation text. |
279 |
* |
280 |
* Examples: |
281 |
* |
282 |
* _d('http://mageia.org/en/'); |
283 |
* _d('http://blog.mageia.org/en/feed'); |
284 |
* |
285 |
* @param string $s |
286 |
* @param array $opt |
287 |
* |
288 |
* @return string |
289 |
* |
290 |
* FIXME Yes, it's terribly wrong/evil to rely on an unknown global $_t. |
291 |
* Solution? rethink the whole i18n thing in an integrated one. |
292 |
*/ |
293 |
public static function _d($s = null, $opt = null) |
294 |
{ |
295 |
if ($s == '') |
296 |
return null; |
297 |
|
298 |
if (!is_null($opt)) { |
299 |
$_t = $opt; |
300 |
} else { |
301 |
global $_t; |
302 |
} |
303 |
|
304 |
$ret = array_key_exists($s, $_t) ? $_t[$s] : $s; |
305 |
|
306 |
return trim(str_replace(array('{ok}', '{OK}', '{Ok}', '{oK}'), '', $ret)); |
307 |
} |
308 |
|
309 |
/** |
310 |
* Output a localized string $s, with optional $args. |
311 |
* |
312 |
* Use it when you need to just output a string. |
313 |
* |
314 |
* Examples: |
315 |
* |
316 |
* _e("Hello"); |
317 |
* _e("Hello %d %d", array(1, 2)); |
318 |
* |
319 |
* @param string $s |
320 |
* @param array $args |
321 |
* |
322 |
* @return null |
323 |
*/ |
324 |
public static function _e($s = null, $args = null) |
325 |
{ |
326 |
if (is_array($args)) |
327 |
echo vsprintf(_t($s), $args); |
328 |
else |
329 |
echo self::_t($s); |
330 |
} |
331 |
|
332 |
/** |
333 |
* Output a localized string $s, sprintf'ed with $args, HTML-wrapped in $tag. |
334 |
* |
335 |
* Use it when you need to wrap your text is HTML, and this is faster. |
336 |
* |
337 |
* Examples: |
338 |
* |
339 |
* _h("Hello"); |
340 |
* _h("Hello %s", array("Alice")); |
341 |
* _h("Title", null, "h1"); |
342 |
* |
343 |
* @param string $s string to echo |
344 |
* @param array $args optional params to $s |
345 |
* @param string $tag optional tag to wrap $s into |
346 |
* |
347 |
* @return null |
348 |
*/ |
349 |
public static function _h($s, $args = null, $tag = 'p') |
350 |
{ |
351 |
$s = self::_t($s); |
352 |
$s = is_array($args) ? vsprintf($s, $args) : $s; |
353 |
|
354 |
$close_tag = explode(' ', $tag); |
355 |
$close_tag = array_shift($close_tag); |
356 |
|
357 |
echo sprintf('<%s>%s</%s>', $tag, $s, $close_tag); |
358 |
} |
359 |
|
360 |
/** |
361 |
* Get all locales from given file. |
362 |
* |
363 |
* @param string $file |
364 |
* @param string $return_duplicates optional switch |
365 |
* |
366 |
* @return array |
367 |
*/ |
368 |
public static function _lang_return($file, $return_duplicates = false) |
369 |
{ |
370 |
$strings = array(); |
371 |
|
372 |
if (file_exists($file)) { |
373 |
$f = file($file); |
374 |
|
375 |
foreach ($f as $k => $v) { |
376 |
|
377 |
$C = substr($v, 0, 1); |
378 |
if ($C === '#') continue; |
379 |
|
380 |
if ($C === ';' && !empty($f[$k+1])) { |
381 |
$j = trim(substr($v, 1)); |
382 |
$j = str_replace(array("\'", "\""), array("'", '"'), $j); |
383 |
if ($return_duplicates && !empty($strings[$j])) { |
384 |
$duplicates[] = $j; |
385 |
} |
386 |
$strings[$j] = trim($f[$k+1]); |
387 |
} |
388 |
} |
389 |
if (!empty($duplicates)) { |
390 |
$strings['duplicates'] = $duplicates; |
391 |
} |
392 |
} |
393 |
|
394 |
return $strings; |
395 |
} |
396 |
|
397 |
/** |
398 |
* Load requested $locale, from $domain lang file, into global $_t array. |
399 |
* |
400 |
* @param string $locale |
401 |
* @param string $domain |
402 |
* |
403 |
* @return boolean |
404 |
* |
405 |
* @todo use i18n::get_fallback_language() or eq. |
406 |
*/ |
407 |
public static function _lang_load($locale, $domain) |
408 |
{ |
409 |
if ($locale == 'en') |
410 |
return true; |
411 |
|
412 |
$lang_file = sprintf('%s/langs/%s/%s.%s.lang', G_APP_ROOT, $locale, $domain, $locale); |
413 |
|
414 |
if (file_exists($lang_file)) { |
415 |
|
416 |
global $_t; |
417 |
if (!isset($_t) || !is_array($_t)) |
418 |
$_t = array(); |
419 |
|
420 |
$_t = array_merge($_t, self::_lang_return($lang_file)); |
421 |
|
422 |
return true; |
423 |
} |
424 |
|
425 |
return false; |
426 |
} |
427 |
|
428 |
} |
429 |
|
430 |
// shorthand helpers, to make legacy calls work. |
431 |
function _t($s = null, $opt = null, $post = ' ') { return i18n::_t($s, $opt, $post); } |
432 |
function _d($s = null, $opt = null) { return i18n::_d($s, $opt); } |
433 |
function _e($s = null, $args = null) { return i18n::_e($s, $args); } |
434 |
function _h($s = null, $args = null, $tag = 'p') { return i18n::_h($s, $args, $tag); } |
435 |
|
436 |
function _lang_load($locale, $domain) { return i18n::_lang_load($locale, $domain); } |