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