Update SQL parser to 4.2.3
[phpmyadmin.git] / libraries / LanguageManager.php
blob30aab0d5b49a52b2e8447cf96f1740eb0128bd6f
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Hold the PMA\libraries\LanguageManager class
6 * @package PhpMyAdmin
7 */
8 namespace PMA\libraries;
10 use PMA\libraries\Language;
11 use PMA\libraries\URL;
13 /**
14 * Language selection manager
16 * @package PhpMyAdmin
18 class LanguageManager
20 /**
21 * @var array Definition data for languages
23 * Each member contains:
24 * - Language code
25 * - English language name
26 * - Native language name
27 * - Match regullar expression
28 * - MySQL locale
30 private static $_language_data = array(
31 'af' => array(
32 'af',
33 'Afrikaans',
34 '',
35 'af|afrikaans',
36 '',
38 'ar' => array(
39 'ar',
40 'Arabic',
41 '&#1575;&#1604;&#1593;&#1585;&#1576;&#1610;&#1577;',
42 'ar|arabic',
43 'ar_AE',
45 'az' => array(
46 'az',
47 'Azerbaijani',
48 'Az&#601;rbaycanca',
49 'az|azerbaijani',
50 '',
52 'bn' => array(
53 'bn',
54 'Bangla',
55 'বাংলা',
56 'bn|bangla',
57 '',
59 'be' => array(
60 'be',
61 'Belarusian',
62 '&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1072;&#1103;',
63 'be|belarusian',
64 'be_BY',
66 'be@latin' => array(
67 'be@latin',
68 'Belarusian (latin)',
69 'Bie&#0322;aruskaja',
70 'be[-_]lat|be@latin|belarusian latin',
71 '',
73 'bg' => array(
74 'bg',
75 'Bulgarian',
76 '&#1041;&#1098;&#1083;&#1075;&#1072;&#1088;&#1089;&#1082;&#1080;',
77 'bg|bulgarian',
78 'bg_BG',
80 'bs' => array(
81 'bs',
82 'Bosnian',
83 'Bosanski',
84 'bs|bosnian',
85 '',
87 'br' => array(
88 'br',
89 'Breton',
90 'Brezhoneg',
91 'br|breton',
92 '',
94 'brx' => array(
95 'brx',
96 'Bodo',
97 'बड़ो',
98 'brx|bodo',
99 '',
101 'ca' => array(
102 'ca',
103 'Catalan',
104 'Catal&agrave;',
105 'ca|catalan',
106 'ca_ES',
108 'ckb' => array(
109 'ckb',
110 'Sorani',
111 'سۆرانی',
112 'ckb|sorani',
115 'cs' => array(
116 'cs',
117 'Czech',
118 'Čeština',
119 'cs|czech',
120 'cs_CZ',
122 'cy' => array(
123 'cy',
124 'Welsh',
125 'Cymraeg',
126 'cy|welsh',
129 'da' => array(
130 'da',
131 'Danish',
132 'Dansk',
133 'da|danish',
134 'da_DK',
136 'de' => array(
137 'de',
138 'German',
139 'Deutsch',
140 'de|german',
141 'de_DE',
143 'el' => array(
144 'el',
145 'Greek',
146 '&Epsilon;&lambda;&lambda;&eta;&nu;&iota;&kappa;&#940;',
147 'el|greek',
150 'en' => array(
151 'en',
152 'English',
154 'en|english',
155 'en_US',
157 'en_gb' => array(
158 'en_GB',
159 'English (United Kingdom)',
161 'en[_-]gb|english (United Kingdom)',
162 'en_GB',
164 'eo' => array(
165 'eo',
166 'Esperanto',
167 'Esperanto',
168 'eo|esperanto',
171 'es' => array(
172 'es',
173 'Spanish',
174 'Espa&ntilde;ol',
175 'es|spanish',
176 'es_ES',
178 'et' => array(
179 'et',
180 'Estonian',
181 'Eesti',
182 'et|estonian',
183 'et_EE',
185 'eu' => array(
186 'eu',
187 'Basque',
188 'Euskara',
189 'eu|basque',
190 'eu_ES',
192 'fa' => array(
193 'fa',
194 'Persian',
195 '&#1601;&#1575;&#1585;&#1587;&#1740;',
196 'fa|persian',
199 'fi' => array(
200 'fi',
201 'Finnish',
202 'Suomi',
203 'fi|finnish',
204 'fi_FI',
206 'fil' => array(
207 'fil',
208 'Filipino',
209 'Pilipino',
210 'fil|filipino',
213 'fr' => array(
214 'fr',
215 'French',
216 'Fran&ccedil;ais',
217 'fr|french',
218 'fr_FR',
220 'fy' => array(
221 'fy',
222 'Frisian',
223 'Frysk',
224 'fy|frisian',
227 'gl' => array(
228 'gl',
229 'Galician',
230 'Galego',
231 'gl|galician',
232 'gl_ES',
234 'gu' => array(
235 'gu',
236 'Gujarati',
237 'ગુજરાતી',
238 'gu|gujarati',
239 'gu_IN',
241 'he' => array(
242 'he',
243 'Hebrew',
244 '&#1506;&#1489;&#1512;&#1497;&#1514;',
245 'he|hebrew',
246 'he_IL',
248 'hi' => array(
249 'hi',
250 'Hindi',
251 '&#2361;&#2367;&#2344;&#2381;&#2342;&#2368;',
252 'hi|hindi',
253 'hi_IN',
255 'hr' => array(
256 'hr',
257 'Croatian',
258 'Hrvatski',
259 'hr|croatian',
260 'hr_HR',
262 'hu' => array(
263 'hu',
264 'Hungarian',
265 'Magyar',
266 'hu|hungarian',
267 'hu_HU',
269 'hy' => array(
270 'hy',
271 'Armenian',
272 'Հայերէն',
273 'hy|armenian',
276 'ia' => array(
277 'ia',
278 'Interlingua',
280 'ia|interlingua',
283 'id' => array(
284 'id',
285 'Indonesian',
286 'Bahasa Indonesia',
287 'id|indonesian',
288 'id_ID',
290 'ig' => array(
291 'ig',
292 'Igbo',
293 'Asụsụ Igbo',
294 'ig|igbo',
297 'it' => array(
298 'it',
299 'Italian',
300 'Italiano',
301 'it|italian',
302 'it_IT',
304 'ja' => array(
305 'ja',
306 'Japanese',
307 '&#26085;&#26412;&#35486;',
308 'ja|japanese',
309 'ja_JP',
311 'ko' => array(
312 'ko',
313 'Korean',
314 '&#54620;&#44397;&#50612;',
315 'ko|korean',
316 'ko_KR',
318 'ka' => array(
319 'ka',
320 'Georgian',
321 '&#4325;&#4304;&#4320;&#4311;&#4323;&#4314;&#4312;',
322 'ka|georgian',
325 'kab' => array(
326 'kab',
327 'Kabylian',
328 'Taqbaylit',
329 'kab|kabylian',
332 'kk' => array(
333 'kk',
334 'Kazakh',
335 'Қазақ',
336 'kk|kazakh',
339 'km' => array(
340 'km',
341 'Khmer',
342 'ខ្មែរ',
343 'km|khmer',
346 'kn' => array(
347 'kn',
348 'Kannada',
349 'ಕನ್ನಡ',
350 'kn|kannada',
353 'ksh' => array(
354 'ksh',
355 'Colognian',
356 'Kölsch',
357 'ksh|colognian',
360 'ky' => array(
361 'ky',
362 'Kyrgyz',
363 'Кыргызча',
364 'ky|kyrgyz',
367 'li' => array(
368 'li',
369 'Limburgish',
370 'Lèmbörgs',
371 'li|limburgish',
374 'lt' => array(
375 'lt',
376 'Lithuanian',
377 'Lietuvi&#371;',
378 'lt|lithuanian',
379 'lt_LT',
381 'lv' => array(
382 'lv',
383 'Latvian',
384 'Latvie&scaron;u',
385 'lv|latvian',
386 'lv_LV',
388 'mk' => array(
389 'mk',
390 'Macedonian',
391 'Macedonian',
392 'mk|macedonian',
393 'mk_MK',
395 'ml' => array(
396 'ml',
397 'Malayalam',
398 'Malayalam',
399 'ml|malayalam',
402 'mn' => array(
403 'mn',
404 'Mongolian',
405 '&#1052;&#1086;&#1085;&#1075;&#1086;&#1083;',
406 'mn|mongolian',
407 'mn_MN',
409 'ms' => array(
410 'ms',
411 'Malay',
412 'Bahasa Melayu',
413 'ms|malay',
414 'ms_MY',
416 'ne' => array(
417 'ne',
418 'Nepali',
419 'नेपाली',
420 'ne|nepali',
423 'nb' => array(
424 'nb',
425 'Norwegian',
426 'Norsk',
427 'nb|norwegian',
428 'nb_NO',
430 'nl' => array(
431 'nl',
432 'Dutch',
433 'Nederlands',
434 'nl|dutch',
435 'nl_NL',
437 'pa' => array(
438 'pa',
439 'Punjabi',
440 'ਪੰਜਾਬੀ',
441 'pa|punjabi',
444 'pl' => array(
445 'pl',
446 'Polish',
447 'Polski',
448 'pl|polish',
449 'pl_PL',
451 'pt_br' => array(
452 'pt_BR',
453 'Brazilian Portuguese',
454 'Portugu&ecirc;s',
455 'pt[-_]br|brazilian portuguese',
456 'pt_BR',
458 'pt' => array(
459 'pt',
460 'Portuguese',
461 'Portugu&ecirc;s',
462 'pt|portuguese',
463 'pt_PT',
465 'ro' => array(
466 'ro',
467 'Romanian',
468 'Rom&acirc;n&#259;',
469 'ro|romanian',
470 'ro_RO',
472 'ru' => array(
473 'ru',
474 'Russian',
475 '&#1056;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;',
476 'ru|russian',
477 'ru_RU',
479 'si' => array(
480 'si',
481 'Sinhala',
482 '&#3523;&#3538;&#3458;&#3524;&#3517;',
483 'si|sinhala',
486 'sk' => array(
487 'sk',
488 'Slovak',
489 'Sloven&#269;ina',
490 'sk|slovak',
491 'sk_SK',
493 'sl' => array(
494 'sl',
495 'Slovenian',
496 'Sloven&scaron;&#269;ina',
497 'sl|slovenian',
498 'sl_SI',
500 'sq' => array(
501 'sq',
502 'Slbanian',
503 'Shqip',
504 'sq|albanian',
505 'sq_AL',
507 'sr@latin' => array(
508 'sr@latin',
509 'Serbian (latin)',
510 'Srpski',
511 'sr[-_]lat|sr@latin|serbian latin',
512 'sr_YU',
514 'sr' => array(
515 'sr',
516 'Serbian',
517 '&#1057;&#1088;&#1087;&#1089;&#1082;&#1080;',
518 'sr|serbian',
519 'sr_YU',
521 'sv' => array(
522 'sv',
523 'Swedish',
524 'Svenska',
525 'sv|swedish',
526 'sv_SE',
528 'ta' => array(
529 'ta',
530 'Tamil',
531 'தமிழ்',
532 'ta|tamil',
533 'ta_IN',
535 'te' => array(
536 'te',
537 'Telugu',
538 'తెలుగు',
539 'te|telugu',
540 'te_IN',
542 'th' => array(
543 'th',
544 'Thai',
545 '&#3616;&#3634;&#3625;&#3634;&#3652;&#3607;&#3618;',
546 'th|thai',
547 'th_TH',
549 'tk' => array(
550 'tk',
551 'Turkmen',
552 'Türkmençe',
553 'tk|turkmen',
556 'tr' => array(
557 'tr',
558 'Turkish',
559 'T&uuml;rk&ccedil;e',
560 'tr|turkish',
561 'tr_TR',
563 'tt' => array(
564 'tt',
565 'Tatarish',
566 'Tatar&ccedil;a',
567 'tt|tatarish',
570 'ug' => array(
571 'ug',
572 'Uyghur',
573 'ئۇيغۇرچە',
574 'ug|uyghur',
577 'uk' => array(
578 'uk',
579 'Ukrainian',
580 '&#1059;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072;',
581 'uk|ukrainian',
582 'uk_UA',
584 'ur' => array(
585 'ur',
586 'Urdu',
587 'اُردوُ',
588 'ur|urdu',
589 'ur_PK',
591 'uz@latin' => array(
592 'uz@latin',
593 'Uzbek (latin)',
594 'O&lsquo;zbekcha',
595 'uz[-_]lat|uz@latin|uzbek-latin',
598 'uz' => array(
599 'uz',
600 'Uzbek (cyrillic)',
601 '&#1038;&#1079;&#1073;&#1077;&#1082;&#1095;&#1072;',
602 'uz[-_]cyr|uz@cyrillic|uzbek-cyrillic',
605 'vi' => array(
606 'vi',
607 'Vietnamese',
608 'Tiếng Việt',
609 'vi|vietnamese',
610 'vi_VN',
612 'vls' => array(
613 'vls',
614 'Flemish',
615 'West-Vlams',
616 'vls|flemish',
619 'zh_tw' => array(
620 'zh_TW',
621 'Chinese traditional',
622 '&#20013;&#25991;',
623 'zh[-_](tw|hk)|chinese traditional',
624 'zh_TW',
626 // only TW and HK use traditional Chinese while others (CN, SG, MY)
627 // use simplified Chinese
628 'zh_cn' => array(
629 'zh_CN',
630 'Chinese simplified',
631 '&#20013;&#25991;',
632 'zh(?![-_](tw|hk))([-_][[:alpha:]]{2,3})?|chinese simplified',
633 'zh_CN',
637 private $_available_locales;
638 private $_available_languages;
639 private $_lang_failed_cfg;
640 private $_lang_failed_cookie;
641 private $_lang_failed_request;
642 private static $instance;
645 * Returns LanguageManager singleton
647 * @return LanguageManager
649 public static function getInstance()
651 if (self::$instance === NULL) {
652 self::$instance = new LanguageManager;
654 return self::$instance;
658 * Returns list of available locales
660 * @return array
662 public function listLocaleDir()
664 $result = array('en');
666 /* Check for existing directory */
667 if (!is_dir(LOCALE_PATH)) {
668 return $result;
671 /* Open the directory */
672 $handle = @opendir(LOCALE_PATH);
673 /* This can happen if the kit is English-only */
674 if ($handle === false) {
675 return $result;
678 /* Process all files */
679 while (false !== ($file = readdir($handle))) {
680 $path = LOCALE_PATH
681 . '/' . $file
682 . '/LC_MESSAGES/phpmyadmin.mo';
683 if ($file != "."
684 && $file != ".."
685 && @file_exists($path)
687 $result[] = $file;
690 /* Close the handle */
691 closedir($handle);
693 return $result;
697 * Returns (cached) list of all available locales
699 * @return array of strings
701 public function availableLocales()
703 if (! $this->_available_locales) {
705 if (empty($GLOBALS['cfg']['FilterLanguages'])) {
706 $this->_available_locales = $this->listLocaleDir();
707 } else {
708 $this->_available_locales = preg_grep(
709 '@' . $GLOBALS['cfg']['FilterLanguages'] . '@',
710 $this->listLocaleDir()
714 return $this->_available_locales;
718 * Checks whether there are some languages available
720 * @return boolean
722 public function hasChoice()
724 return count($this->availableLanguages()) > 1;
728 * Returns (cached) list of all available languages
730 * @return array of Language objects
732 public function availableLanguages()
734 if (! $this->_available_languages) {
735 $this->_available_languages = array();
737 foreach($this->availableLocales() as $lang) {
738 $lang = strtolower($lang);
739 if (isset($this::$_language_data[$lang])) {
740 $data = $this::$_language_data[$lang];
741 $this->_available_languages[$lang] = new Language(
742 $data[0],
743 $data[1],
744 $data[2],
745 $data[3],
746 $data[4]
748 } else {
749 $this->_available_languages[$lang] = new Language(
750 $lang,
751 ucfirst($lang),
752 ucfirst($lang),
753 $lang,
759 return $this->_available_languages;
763 * Returns (cached) list of all available languages sorted
764 * by name
766 * @return array of Language objects
768 public function sortedLanguages()
770 $this->availableLanguages();
771 uasort($this->_available_languages, function($a, $b)
773 return $a->cmp($b);
776 return $this->_available_languages;
780 * Return Language object for given code
782 * @param string $code Language code
784 * @return object|false Language object or false on failure
786 public function getLanguage($code)
788 $code = strtolower($code);
789 $langs = $this->availableLanguages();
790 if (isset($langs[$code])) {
791 return $langs[$code];
793 return false;
797 * Return currently active Language object
799 * @return object Language object
801 public function getCurrentLanguage()
803 return $this->_available_languages[strtolower($GLOBALS['lang'])];
807 * Activates language based on configuration, user preferences or
808 * browser
810 * @return Language
812 public function selectLanguage()
814 // check forced language
815 if (! empty($GLOBALS['cfg']['Lang'])) {
816 $lang = $this->getLanguage($GLOBALS['cfg']['Lang']);
817 if ($lang !== false) {
818 return $lang;
820 $this->_lang_failed_cfg = true;
823 // Don't use REQUEST in following code as it might be confused by cookies
824 // with same name. Check user requested language (POST)
825 if (! empty($_POST['lang'])) {
826 $lang = $this->getLanguage($_POST['lang']);
827 if ($lang !== false) {
828 return $lang;
830 $this->_lang_failed_request = true;
833 // check user requested language (GET)
834 if (! empty($_GET['lang'])) {
835 $lang = $this->getLanguage($_GET['lang']);
836 if ($lang !== false) {
837 return $lang;
839 $this->_lang_failed_request = true;
842 // check previous set language
843 if (! empty($_COOKIE['pma_lang'])) {
844 $lang = $this->getLanguage($_COOKIE['pma_lang']);
845 if ($lang !== false) {
846 return $lang;
848 $this->_lang_failed_cookie = true;
851 $langs = $this->availableLanguages();
853 // try to find out user's language by checking its HTTP_ACCEPT_LANGUAGE variable;
854 $accepted_languages = PMA_getenv('HTTP_ACCEPT_LANGUAGE');
855 if ($accepted_languages) {
856 foreach (explode(',', $accepted_languages) as $header) {
857 foreach ($langs as $language) {
858 if ($language->matchesAcceptLanguage($header)) {
859 return $language;
865 // try to find out user's language by checking its HTTP_USER_AGENT variable
866 $user_agent = PMA_getenv('HTTP_USER_AGENT');
867 if (! empty($user_agent)) {
868 foreach ($langs as $language) {
869 if ($language->matchesUserAgent($user_agent)) {
870 return $language;
875 // Didn't catch any valid lang : we use the default settings
876 if (isset($langs[$GLOBALS['cfg']['DefaultLang']])) {
877 return $langs[$GLOBALS['cfg']['DefaultLang']];
880 // Fallback to English
881 return $langs['en'];
885 * Displays warnings about invalid languages. This needs to be postponed
886 * to show messages at time when language is initialized.
888 * @return void
890 public function showWarnings()
892 // now, that we have loaded the language strings we can send the errors
893 if ($this->_lang_failed_cfg
894 || $this->_lang_failed_cookie
895 || $this->_lang_failed_request
897 trigger_error(
898 __('Ignoring unsupported language code.'),
899 E_USER_ERROR
906 * Returns HTML code for the language selector
908 * @param boolean $use_fieldset whether to use fieldset for selection
909 * @param boolean $show_doc whether to show documentation links
911 * @return string
913 * @access public
915 public function getSelectorDisplay($use_fieldset = false, $show_doc = true)
917 $_form_params = array(
918 'db' => $GLOBALS['db'],
919 'table' => $GLOBALS['table'],
922 // For non-English, display "Language" with emphasis because it's
923 // not a proper word in the current language; we show it to help
924 // people recognize the dialog
925 $language_title = __('Language')
926 . (__('Language') != 'Language' ? ' - <em>Language</em>' : '');
927 if ($show_doc) {
928 $language_title .= Util::showDocu('faq', 'faq7-2');
931 $available_languages = $this->sortedLanguages();
933 return Template::get('select_lang')->render(
934 array(
935 'language_title' => $language_title,
936 'use_fieldset' => $use_fieldset,
937 'available_languages' => $available_languages,
938 '_form_params' => $_form_params,