From 3ecafc5973a62a4a5aba6fd51034f464869443e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 11:26:44 +0100 Subject: [PATCH 1/9] Move mysql_charset_map to common.inc.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It should be later removed (as it's IMHO not needed), but we move it out of select_lang.inc.php where it really doesn't belong. Signed-off-by: Michal Čihař --- libraries/common.inc.php | 29 +++++++++++++++++++++++++++++ libraries/select_lang.inc.php | 29 ----------------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/libraries/common.inc.php b/libraries/common.inc.php index fa4785387a..54eedbe0cf 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -1089,3 +1089,32 @@ if (! defined('PMA_MINIMUM_COMMON')) { include 'libraries/config/user_preferences.forms.php'; include_once 'libraries/config/page_settings.forms.php'; } + +/** + * @global array MySQL charsets map + */ +$GLOBALS['mysql_charset_map'] = array( + 'big5' => 'big5', + 'cp-866' => 'cp866', + 'euc-jp' => 'ujis', + 'euc-kr' => 'euckr', + 'gb2312' => 'gb2312', + 'gbk' => 'gbk', + 'iso-8859-1' => 'latin1', + 'iso-8859-2' => 'latin2', + 'iso-8859-7' => 'greek', + 'iso-8859-8' => 'hebrew', + 'iso-8859-8-i' => 'hebrew', + 'iso-8859-9' => 'latin5', + 'iso-8859-13' => 'latin7', + 'iso-8859-15' => 'latin1', + 'koi8-r' => 'koi8r', + 'shift_jis' => 'sjis', + 'tis-620' => 'tis620', + 'utf-8' => 'utf8', + 'windows-1250' => 'cp1250', + 'windows-1251' => 'cp1251', + 'windows-1252' => 'latin1', + 'windows-1256' => 'cp1256', + 'windows-1257' => 'cp1257', +); diff --git a/libraries/select_lang.inc.php b/libraries/select_lang.inc.php index 484c3a4182..faef272496 100644 --- a/libraries/select_lang.inc.php +++ b/libraries/select_lang.inc.php @@ -59,35 +59,6 @@ if (! empty($GLOBALS['cfg']['FilterLanguages'])) { unset($key, $val, $new_lang); } -/** - * @global array MySQL charsets map - */ -$GLOBALS['mysql_charset_map'] = array( - 'big5' => 'big5', - 'cp-866' => 'cp866', - 'euc-jp' => 'ujis', - 'euc-kr' => 'euckr', - 'gb2312' => 'gb2312', - 'gbk' => 'gbk', - 'iso-8859-1' => 'latin1', - 'iso-8859-2' => 'latin2', - 'iso-8859-7' => 'greek', - 'iso-8859-8' => 'hebrew', - 'iso-8859-8-i' => 'hebrew', - 'iso-8859-9' => 'latin5', - 'iso-8859-13' => 'latin7', - 'iso-8859-15' => 'latin1', - 'koi8-r' => 'koi8r', - 'shift_jis' => 'sjis', - 'tis-620' => 'tis620', - 'utf-8' => 'utf8', - 'windows-1250' => 'cp1250', - 'windows-1251' => 'cp1251', - 'windows-1252' => 'latin1', - 'windows-1256' => 'cp1256', - 'windows-1257' => 'cp1257', -); - /* * Do the work! */ From 39771f44c05e5e7c0d1a2f902cfbd52b7cdcac4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 13:45:13 +0100 Subject: [PATCH 2/9] Simplify code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For ages we set $GLOBALS['lang'] to language code, so it's safe to use it here. Signed-off-by: Michal Čihař --- libraries/Header.php | 2 +- libraries/core.lib.php | 2 +- test/theme.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/Header.php b/libraries/Header.php index 49c8df8740..d9f6114042 100644 --- a/libraries/Header.php +++ b/libraries/Header.php @@ -620,7 +620,7 @@ class Header */ private function _getHtmlStart() { - $lang = $GLOBALS['available_languages'][$GLOBALS['lang']][1]; + $lang = $GLOBALS['lang']; $dir = $GLOBALS['text_dir']; $retval = ""; diff --git a/libraries/core.lib.php b/libraries/core.lib.php index 47d3262ba3..16313b931f 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -246,7 +246,7 @@ function PMA_fatalError( } else { $error_header = 'Error'; } - $lang = $GLOBALS['available_languages'][$GLOBALS['lang']][1]; + $lang = $GLOBALS['lang']; $dir = $GLOBALS['text_dir']; // on fatal errors it cannot hurt to always delete the current session diff --git a/test/theme.php b/test/theme.php index 0edf10fa47..421f56681b 100644 --- a/test/theme.php +++ b/test/theme.php @@ -16,7 +16,7 @@ chdir('..'); require_once './libraries/common.inc.php'; $GLOBALS['pmaThemeImage'] = '../' . $GLOBALS['pmaThemeImage']; -$lang_iso_code = $GLOBALS['available_languages'][$GLOBALS['lang']][1]; +$lang_iso_code = $GLOBALS['lang']; // start output header('Content-Type: text/html; charset=utf-8'); From fd045a94e71611098a1db3d392bcee8aeee017ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 11:22:11 +0100 Subject: [PATCH 3/9] Initial implementation of LanguageManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LanguageManager is responsible for choosing correct language and Language class wraps invididual locales, allows matching and their activation. Issue #11847 Signed-off-by: Michal Čihař --- libraries/Language.php | 175 +++++++++ libraries/LanguageManager.php | 687 ++++++++++++++++++++++++++++++++++ libraries/vendor_config.php | 5 + test/classes/LanguageTest.php | 217 +++++++++++ 4 files changed, 1084 insertions(+) create mode 100644 libraries/Language.php create mode 100644 libraries/LanguageManager.php create mode 100644 test/classes/LanguageTest.php diff --git a/libraries/Language.php b/libraries/Language.php new file mode 100644 index 0000000000..c40b5b9bd1 --- /dev/null +++ b/libraries/Language.php @@ -0,0 +1,175 @@ +code = $code; + $this->name = $name; + $this->native = $native; + if (strpos($regex, '[-_]') === false) { + $regex = str_replace('|', '([-_][[:alpha:]]{2,3})?|', $regex); + } + $this->regex = $regex; + } + + /** + * Returns native name for language + * + * @return string + */ + public function getNativeName() + { + return $this->native; + } + + /** + * Returns English name for language + * + * @return string + */ + public function getEnglishName() + { + return $this->name; + } + + /** + * Returns verbose name for language + * + * @return string + */ + public function getName() + { + if (! empty($this->native)) { + return $this->native . ' - ' . $this->name; + } else { + return $this->name; + } + } + + /** + * Returns language code + * + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * Checks whether language is currently active. + * + * @return bool + */ + public function isActive() + { + return $GLOBALS['lang'] == $this->code; + } + + /** + * Checks whether language matches HTTP header Accept-Language. + * + * @param string $header Header content + * + * @return bool + */ + public function matchesAcceptLanguage($header) + { + $pattern = '/^(' + . addcslashes($this->regex, '/') + . ')(;q=[0-9]\\.[0-9])?$/i'; + return preg_match($pattern, $header); + } + + /** + * Checks whether language matches HTTP header User-Agent + * + * @param string $header Header content + * + * @return bool + */ + public function matchesUserAgent($header) + { + $pattern = '/(\(|\[|;[[:space:]])(' + . addcslashes($this->regex, '/') + . ')(;|\]|\))/i'; + return preg_match($pattern, $header); + } + + /** + * Checks whether langauge is RTL + * + * @return bool + */ + public function isRTL() + { + return in_array($this->code, array('ar', 'fa', 'he', 'ur')); + } + + /** + * Activates given translation + * + * @return bool + */ + public function activate() + { + $GLOBALS['lang'] = $this->code; + + // Set locale + _setlocale(LC_MESSAGES, $this->code); + _bindtextdomain('phpmyadmin', LOCALE_PATH); + _bind_textdomain_codeset('phpmyadmin', 'UTF-8'); + _textdomain('phpmyadmin'); + + /* Text direction for language */ + if ($this->isRTL()) { + $GLOBALS['text_dir'] = 'rtl'; + } else { + $GLOBALS['text_dir'] = 'ltr'; + } + + /* TCPDF */ + $GLOBALS['l'] = array(); + + /* TCPDF settings */ + $GLOBALS['l']['a_meta_charset'] = 'UTF-8'; + $GLOBALS['l']['a_meta_dir'] = $GLOBALS['text_dir']; + $GLOBALS['l']['a_meta_language'] = $this->code; + + /* TCPDF translations */ + $GLOBALS['l']['w_page'] = __('Page number:'); + + /* Show possible warnings from langauge selection */ + LanguageManager::getInstance()->showWarnings(); + } +} diff --git a/libraries/LanguageManager.php b/libraries/LanguageManager.php new file mode 100644 index 0000000000..7c4b31c5a9 --- /dev/null +++ b/libraries/LanguageManager.php @@ -0,0 +1,687 @@ + array( + 'Afrikaans', + '', + 'af|afrikaans', + ), + 'ar' => array( + 'Arabic', + 'العربية', + 'ar|arabic', + ), + 'az' => array( + 'Azerbaijani', + 'Azərbaycanca', + 'az|azerbaijani', + ), + 'bn' => array( + 'Bangla', + 'বাংলা', + 'bn|bangla', + ), + 'be' => array( + 'Belarusian', + 'Беларуская', + 'be|belarusian', + ), + 'be@latin' => array( + 'Belarusian (latin)', + 'Biełaruskaja', + 'be[-_]lat|be@latin|belarusian latin', + ), + 'bg' => array( + 'Bulgarian', + 'Български', + 'bg|bulgarian', + ), + 'bs' => array( + 'Bosnian', + 'Bosanski', + 'bs|bosnian', + ), + 'br' => array( + 'Breton', + 'Brezhoneg', + 'br|breton', + ), + 'brx' => array( + 'Bodo', + 'बड़ो', + 'brx|bodo', + ), + 'ca' => array( + 'Catalan', + 'Català', + 'ca|catalan', + ), + 'ckb' => array( + 'Sorani', + 'سۆرانی', + 'ckb|sorani', + ), + 'cs' => array( + 'Czech', + 'Čeština', + 'cs|czech', + ), + 'cy' => array( + 'Welsh', + 'Cymraeg', + 'cy|welsh', + ), + 'da' => array( + 'Danish', + 'Dansk', + 'da|danish', + ), + 'de' => array( + 'German', + 'Deutsch', + 'de|german', + ), + 'el' => array( + 'Greek', + 'Ελληνικά', + 'el|greek', + ), + 'en' => array( + 'English', + '', + 'en|english', + ), + 'en_gb' => array( + 'English (United Kingdom)', + '', + 'en[_-]gb|english (United Kingdom)', + ), + 'eo' => array( + 'Esperanto', + 'Esperanto', + 'eo|esperanto', + ), + 'es' => array( + 'Spanish', + 'Español', + 'es|spanish', + ), + 'et' => array( + 'Estonian', + 'Eesti', + 'et|estonian', + ), + 'eu' => array( + 'Basque', + 'Euskara', + 'eu|basque', + ), + 'fa' => array( + 'Persian', + 'فارسی', + 'fa|persian', + ), + 'fi' => array( + 'Finnish', + 'Suomi', + 'fi|finnish', + ), + 'fr' => array( + 'French', + 'Français', + 'fr|french', + ), + 'fy' => array( + 'Frisian', + 'Frysk', + 'fy|frisian', + ), + 'gl' => array( + 'Galician', + 'Galego', + 'gl|galician', + ), + 'gu' => array( + 'Gujarati', + 'ગુજરાતી', + 'gu|gujarati', + ), + 'he' => array( + 'Hebrew', + 'עברית', + 'he|hebrew', + ), + 'hi' => array( + 'Hindi', + 'हिन्दी', + 'hi|hindi', + ), + 'hr' => array( + 'Croatian', + 'Hrvatski', + 'hr|croatian', + ), + 'hu' => array( + 'Hungarian', + 'Magyar', + 'hu|hungarian', + ), + 'hy' => array( + 'Armenian', + 'Հայերէն', + 'hy|armenian', + ), + 'ia' => array( + 'Interlingua', + '', + 'ia|interlingua', + ), + 'id' => array( + 'Indonesian', + 'Bahasa Indonesia', + 'id|indonesian', + ), + 'it' => array( + 'Italian', + 'Italiano', + 'it|italian', + ), + 'ja' => array( + 'Japanese', + '日本語', + 'ja|japanese', + ), + 'ko' => array( + 'Korean', + '한국어', + 'ko|korean', + ), + 'ka' => array( + 'Georgian', + 'ქართული', + 'ka|georgian', + ), + 'kk' => array( + 'Kazakh', + 'Қазақ', + 'kk|kazakh', + ), + 'km' => array( + 'Khmer', + 'ខ្មែរ', + 'km|khmer', + ), + 'kn' => array( + 'Kannada', + 'ಕನ್ನಡ', + 'kn|kannada', + ), + 'ksh' => array( + 'Colognian', + 'Kölsch', + 'ksh|colognian', + ), + 'ky' => array( + 'Kyrgyz', + 'Кыргызча', + 'ky|kyrgyz', + ), + 'li' => array( + 'Limburgish', + 'Lèmbörgs', + 'li|limburgish', + ), + 'lt' => array( + 'Lithuanian', + 'Lietuvių', + 'lt|lithuanian', + ), + 'lv' => array( + 'Latvian', + 'Latviešu', + 'lv|latvian', + ), + 'mk' => array( + 'Macedonian', + 'Macedonian', + 'mk|macedonian', + ), + 'ml' => array( + 'Malayalam', + 'Malayalam', + 'ml|malayalam', + ), + 'mn' => array( + 'Mongolian', + 'Монгол', + 'mn|mongolian', + ), + 'ms' => array( + 'Malay', + 'Bahasa Melayu', + 'ms|malay', + ), + 'ne' => array( + 'Nepali', + 'नेपाली', + 'ne|nepali', + ), + 'nl' => array( + 'Dutch', + 'Nederlands', + 'nl|dutch', + ), + 'nb' => array( + 'Norwegian', + 'Norsk', + 'nb|norwegian', + ), + 'pa' => array( + 'Punjabi', + 'ਪੰਜਾਬੀ', + 'pa|punjabi', + ), + 'pl' => array( + 'Polish', + 'Polski', + 'pl|polish', + ), + 'pt_br' => array( + 'Brazilian Portuguese', + 'Português', + 'pt[-_]br|brazilian portuguese', + ), + 'pt' => array( + 'Portuguese', + 'Português', + 'pt|portuguese', + ), + 'ro' => array( + 'Romanian', + 'Română', + 'ro|romanian', + ), + 'ru' => array( + 'Russian', + 'Русский', + 'ru|russian', + ), + 'si' => array( + 'Sinhala', + 'සිංහල', + 'si|sinhala', + ), + 'sk' => array( + 'Slovak', + 'Slovenčina', + 'sk|slovak', + ), + 'sl' => array( + 'Slovenian', + 'Slovenščina', + 'sl|slovenian', + ), + 'sq' => array( + 'Slbanian', + 'Shqip', + 'sq|albanian', + ), + 'sr@latin' => array( + 'Serbian (latin)', + 'Srpski', + 'sr[-_]lat|sr@latin|serbian latin', + ), + 'sr' => array( + 'Serbian', + 'Српски', + 'sr|serbian', + ), + 'sv' => array( + 'Swedish', + 'Svenska', + 'sv|swedish', + ), + 'ta' => array( + 'Tamil', + 'தமிழ்', + 'ta|tamil', + ), + 'te' => array( + 'Telugu', + 'తెలుగు', + 'te|telugu', + ), + 'th' => array( + 'Thai', + 'ภาษาไทย', + 'th|thai', + ), + 'tk' => array( + 'Turkmen', + 'Türkmençe', + 'tk|turkmen', + ), + 'tr' => array( + 'Turkish', + 'Türkçe', + 'tr|turkish', + ), + 'tt' => array( + 'Tatarish', + 'Tatarça', + 'tt|tatarish', + ), + 'ug' => array( + 'Uyghur', + 'ئۇيغۇرچە', + 'ug|uyghur', + ), + 'uk' => array( + 'Ukrainian', + 'Українська', + 'uk|ukrainian', + ), + 'ur' => array( + 'Urdu', + 'اُردوُ', + 'ur|urdu', + ), + 'uz@latin' => array( + 'Uzbek (latin)', + 'O‘zbekcha', + 'uz[-_]lat|uz@latin|uzbek-latin', + ), + 'uz' => array( + 'Uzbek (cyrillic)', + 'Ўзбекча', + 'uz[-_]cyr|uz@cyrillic|uzbek-cyrillic', + ), + 'vi' => array( + 'Vietnamese', + 'Tiếng Việt', + 'vi|vietnamese', + ), + 'vls' => array( + 'Flemish', + 'West-Vlams', + 'vls|flemish', + ), + 'zh_tw' => array( + 'Chinese traditional', + '中文', + 'zh[-_](tw|hk)|chinese traditional', + ), + // only TW and HK use traditional Chinese while others (CN, SG, MY) + // use simplified Chinese + 'zh_cn' => array( + 'Chinese simplified', + '中文', + 'zh(?![-_](tw|hk))([-_][[:alpha:]]{2,3})?|chinese simplified', + ), + ); + + private $_available_locales; + private $_available_languages; + private $_lang_failed_cfg; + private $_lang_failed_cookie; + private $_lang_failed_request; + private static $instance; + + /** + * Returns LanguageManager singleton + * + * @return LanguageManager + */ + public static function getInstance() + { + if (self::$instance === NULL) { + self::$instance = new LanguageManager; + } + return self::$instance; + } + + /** + * Returns list of available locales + * + * @return array + */ + public function listLocaleDir() + { + $result = array('en'); + + /* Check for existing directory */ + if (!is_dir(LOCALE_PATH)) { + return $result; + } + + /* Open the directory */ + $handle = @opendir(LOCALE_PATH); + /* This can happen if the kit is English-only */ + if ($handle === false) { + return $result; + } + + /* Process all files */ + while (false !== ($file = readdir($handle))) { + $path = LOCALE_PATH + . '/' . $file + . '/LC_MESSAGES/phpmyadmin.mo'; + if ($file != "." + && $file != ".." + && file_exists($path) + ) { + $result[] = $file; + } + } + /* Close the handle */ + closedir($handle); + + return $result; + } + + /** + * Returns (cached) list of all available locales + * + * @return array of strings + */ + public function availableLocales() + { + if (! $this->_available_locales) { + + if (empty($GLOBALS['cfg']['FilterLanguages'])) { + $this->_available_locales = $this->listLocaleDir(); + } else { + $this->_available_locales = preg_grep( + '@' . $GLOBALS['cfg']['FilterLanguages'] . '@', + $this->listLocaleDir() + ); + } + } + return $this->_available_locales; + } + + /** + * Returns (cached) list of all available languages + * + * @return array of Language objects + */ + public function availableLanguages() + { + if (! $this->_available_languages) { + $this->_available_languages = array(); + + foreach($this->availableLocales() as $lang) { + $lang = strtolower($lang); + if (isset($this::$_language_data[$lang])) { + $data = $this::$_language_data[$lang]; + $this->_available_languages[$lang] = new Language( + $lang, + $data[0], + $data[1], + $data[2] + ); + } else { + $this->_available_languages[$lang] = new Language( + $lang, + ucfirst($lang), + ucfirst($lang), + $lang + ); + } + } + } + return $this->_available_languages; + } + + /** + * Returns (cached) list of all available languages sorted + * by name + * + * @return array of Language objects + */ + public function sortedLanguages() + { + $this->availableLanguages(); + uasort($this->_available_languages, function($a, $b) + { + return strcmp($a->name, $b->name); + } + ); + return $this->_available_languages; + } + + /** + * Return Language object for given code + * + * @param string $code Language code + * + * @return object|false Language object or false on failure + */ + public function getLanguage($code) + { + $langs = $this->availableLanguages(); + if (isset($langs[$code])) { + return $langs[$code]; + } + return false; + } + + /** + * Activates language based on configuration, user preferences or + * browser + * + * @return Language + */ + public function selectLanguage() + { + $langs = $this->availableLanguages(); + + // check forced language + if (! empty($GLOBALS['cfg']['Lang'])) { + if (isset($langs[$GLOBALS['cfg']['Lang']])) { + return $langs[$GLOBALS['cfg']['Lang']]; + } + $this->_lang_failed_cfg = true; + } + + // Don't use REQUEST in following code as it might be confused by cookies + // with same name. Check user requested language (POST) + if (! empty($_POST['lang'])) { + if (isset($langs[$_POST['lang']])) { + return $langs[$_POST['lang']]; + } + $this->_lang_failed_request = true; + } + + // check user requested language (GET) + if (! empty($_GET['lang'])) { + if (isset($langs[$_GET['lang']])) { + return $langs[$_GET['lang']]; + } + $this->_lang_failed_request = true; + } + + // check previous set language + if (! empty($_COOKIE['pma_lang'])) { + if (isset($langs[$_COOKIE['pma_lang']])) { + return $langs[$_COOKIE['pma_lang']]; + } + $this->_lang_failed_cookie = true; + } + + // try to find out user's language by checking its HTTP_ACCEPT_LANGUAGE variable; + // prevent XSS + $accepted_languages = PMA_getenv('HTTP_ACCEPT_LANGUAGE'); + if ($accepted_languages && false === mb_strpos($accepted_languages, '<')) { + foreach (explode(',', $accepted_languages) as $header) { + foreach ($langs as $language) { + if ($language->matchesAcceptLanguage($header)) { + return $language; + } + } + } + } + + // try to find out user's language by checking its HTTP_USER_AGENT variable + $user_agent = PMA_getenv('HTTP_USER_AGENT'); + if (! empty($user_agent)) { + foreach ($langs as $language) { + if ($language->matchesUserAgent($user_agent)) { + return $language; + } + } + } + + // Didn't catch any valid lang : we use the default settings + if (isset($langs[$GLOBALS['cfg']['DefaultLang']])) { + return $langs[$GLOBALS['cfg']['DefaultLang']]; + } + + // Fallback to English + return $langs['en']; + } + + /** + * Displays warnings about invalid languages. This needs to be postponed + * to show messages at time when language is initialized. + * + * @return void + */ + public function showWarnings() + { + // now, that we have loaded the language strings we can send the errors + if ($this->_lang_failed_cfg + || $this->_lang_failed_cookie + || $this->_lang_failed_request + ) { + trigger_error( + __('Ignoring unsupported language code.'), + E_USER_ERROR + ); + } + } +} diff --git a/libraries/vendor_config.php b/libraries/vendor_config.php index 70871509b6..54bd4bb205 100644 --- a/libraries/vendor_config.php +++ b/libraries/vendor_config.php @@ -89,6 +89,11 @@ define('PHPSECLIB_INC_DIR', './libraries/phpseclib/'); */ define('SQL_PARSER_AUTOLOAD', './libraries/sql-parser/autoload.php'); +/** + * Path to files with compiled locales (*.mo) + */ +define('LOCALE_PATH', './locale/'); + /** * Avoid referring to nonexistent files (causes warnings when open_basedir * is used) diff --git a/test/classes/LanguageTest.php b/test/classes/LanguageTest.php new file mode 100644 index 0000000000..f86c736c4f --- /dev/null +++ b/test/classes/LanguageTest.php @@ -0,0 +1,217 @@ +markTestSkipped('Missing compiled locales.'); + } + $this->manager = new LanguageManager(); + } + + /** + * Test language filtering + * + * @return void + */ + public function testAvailable() + { + $GLOBALS['cfg']['FilterLanguages'] = 'cs'; + + $langs = $this->manager->availableLocales(); + + $this->assertEquals(1, count($langs)); + $this->assertContains('cs', $langs); + $GLOBALS['cfg']['FilterLanguages'] = ''; + } + + /** + * Test no language filtering + * + * @return void + */ + public function testAllAvailable() + { + $GLOBALS['cfg']['FilterLanguages'] = ''; + + $langs = $this->manager->availableLocales(); + + $this->assertContains('cs', $langs); + $this->assertContains('en', $langs); + } + + /** + * Test whether listing locales works + * + * @return void + */ + public function testList() + { + $langs = $this->manager->listLocaleDir(); + $this->assertContains('cs', $langs); + $this->assertContains('en', $langs); + } + + /** + * Test for getting available languages + * + * @return void + */ + public function testLanguages() + { + $langs = $this->manager->availableLanguages(); + $this->assertGreaterThan(1, count($langs)); + + /* Ensure we have name for every language */ + foreach($langs as $lang) { + $this->assertNotEquals($lang->getCode(), strtolower($lang->getEnglishName())); + } + } + + /** + * Test for getting available sorted languages + * + * @return void + */ + public function testSortedLanguages() + { + $langs = $this->manager->sortedLanguages(); + $this->assertGreaterThan(1, count($langs)); + } + + /** + * Test getting language by code + * + * @return void + */ + public function testGet() + { + $lang = $this->manager->getLanguage('cs'); + $this->assertNotEquals(false, $lang); + $this->assertEquals('Czech', $lang->getEnglishName()); + $this->assertEquals('Čeština', $lang->getNativeName()); + } + + /** + * Test language selection + * + * @param string $lang Value for forced language + * @param string $post Value for language in POST + * @param string $get Value for language in GET + * @param string $cookie Value for language in COOKIE + * @param string $accept Value for HTTP Accept-Language header + * @param string $agent Value for HTTP User-Agent header + * @param string $default Value for default language + * @param string $expect Expected language name + * + * @return void + * + * @dataProvider selectDataProvider + */ + public function testSelect($lang, $post, $get, $cookie, $accept, $agent, $default, $expect) + { + $GLOBALS['cfg']['Lang'] = $lang; + $_POST['lang'] = $post; + $_GET['lang'] = $get; + $_COOKIE['pma_lang'] = $cookie; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $accept; + $_SERVER['HTTP_USER_AGENT'] = $agent; + $GLOBALS['cfg']['DefaultLang'] = $default; + + $lang = $this->manager->selectLanguage(); + + $this->assertEquals($expect, $lang->getEnglishName()); + + $GLOBALS['cfg']['Lang'] = ''; + $_POST['lang'] = ''; + $_GET['lang'] = ''; + $_COOKIE['pma_lang'] = ''; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = ''; + $_SERVER['HTTP_USER_AGENT'] = ''; + $GLOBALS['cfg']['DefaultLang'] = 'en'; + } + + /** + * Data provider for language selection test. + * + * @return array Test parameters. + */ + public function selectDataProvider() + { + return array( + array('cs', 'en', '', '' ,'' ,'', '', 'Czech'), + array('', 'cs', '', '' ,'' ,'', '', 'Czech'), + array('', 'cs', 'en', '' ,'' ,'', '', 'Czech'), + array('', '', 'cs', '' ,'' ,'', '', 'Czech'), + array('', '', '', '' ,'cs,en-US;q=0.7,en;q=0.3' ,'', '', 'Czech'), + array( + '', '', '', '', '', + 'Mozilla/5.0 (Linux; U; Android 2.2.2; tr-tr; GM FOX)', + '', 'Turkish' + ), + array('', '', '', '' ,'' ,'', 'cs', 'Czech'), + array('', '', '', '' ,'' ,'', '', 'English'), + ); + } + + /** + * Test for setting and parsing locales + * + * @param string $locale locale name + * + * @return void + * + * @group large + * @dataProvider listLocales + */ + public function testGettext($locale) + { + /* We should be able to set the language */ + $this->manager->getLanguage($locale)->activate(); + + /* Grab some texts */ + $this->assertContains('%s', _ngettext('%s table', '%s tables', 10)); + $this->assertContains('%s', _ngettext('%s table', '%s tables', 1)); + } + + /** + * Data provider to generate list of available locales. + * + * @return array with arrays of available locales + */ + public function listLocales() + { + $ret = array(); + foreach (LanguageManager::getInstance()->availableLanguages() as $language) { + $ret[] = array($language->getCode()); + } + return $ret; + } +} From 342c9a25b54675a631a535dc27c8edd2fdaac3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 13:33:10 +0100 Subject: [PATCH 4/9] Switch languge selection to LanguageManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #11847 Signed-off-by: Michal Čihař --- libraries/common.inc.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/common.inc.php b/libraries/common.inc.php index 54eedbe0cf..0680cf472b 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -41,6 +41,7 @@ use PMA\libraries\Tracker; use PMA\libraries\Response; use PMA\libraries\TypesMySQL; use PMA\libraries\Util; +use PMA\libraries\LanguageManager; /** * block attempts to directly run this script @@ -473,10 +474,16 @@ if (PMA_isValid($_REQUEST['sql_query'])) { /******************************************************************************/ /* loading language file LABEL_loading_language_file */ +/** + * Load gettext functions. + */ +require_once GETTEXT_INC; + /** * lang detection is done here */ -require './libraries/select_lang.inc.php'; +$language = LanguageManager::getInstance()->selectLanguage(); +$language->activate(); // Defines the cell alignment values depending on text direction if ($GLOBALS['text_dir'] == 'ltr') { From 19f9e830ebbb3bf296c56d46dd8857b515550eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 13:40:55 +0100 Subject: [PATCH 5/9] Remove no longer needed code for language selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #11847 Signed-off-by: Michal Čihař --- libraries/select_lang.inc.php | 135 ----- libraries/select_lang.lib.php | 467 ------------------ test/classes/HeaderTest.php | 1 - test/classes/MenuTest.php | 1 - .../plugin/auth/AuthenticationCookieTest.php | 1 - .../common/PMA_checkParameters_test.php | 3 - test/libraries/core/PMA_fatalError_test.php | 1 - .../core/PMA_headerLocation_test.php | 1 - .../core/PMA_warnMissingExtension_test.php | 3 - .../select_lang/PMA_langDetails_test.php | 195 -------- .../select_lang/PMA_langList_test.php | 76 --- .../select_lang/PMA_langName_test.php | 57 --- .../select_lang/locale_gettext_test.php | 59 --- 13 files changed, 1000 deletions(-) delete mode 100644 libraries/select_lang.inc.php delete mode 100644 libraries/select_lang.lib.php delete mode 100644 test/libraries/select_lang/PMA_langDetails_test.php delete mode 100644 test/libraries/select_lang/PMA_langList_test.php delete mode 100644 test/libraries/select_lang/PMA_langName_test.php delete mode 100644 test/libraries/select_lang/locale_gettext_test.php diff --git a/libraries/select_lang.inc.php b/libraries/select_lang.inc.php deleted file mode 100644 index faef272496..0000000000 --- a/libraries/select_lang.inc.php +++ /dev/null @@ -1,135 +0,0 @@ - $val) { - if (preg_match('@' . $GLOBALS['cfg']['FilterLanguages'] . '@', $key)) { - $new_lang[$key] = $val; - } - } - if (count($new_lang) > 0) { - $GLOBALS['available_languages'] = $new_lang; - } - unset($key, $val, $new_lang); -} - -/* - * Do the work! - */ - -if (! PMA_langCheck()) { - // fallback language - $fall_back_lang = 'en'; - $line = __LINE__; - if (! PMA_langSet($fall_back_lang)) { - trigger_error( - 'phpMyAdmin-ERROR: invalid lang code: ' - . __FILE__ . '#' . $line . ', check hard coded fall back language.', - E_USER_WARNING - ); - // stop execution - // and tell the user that his chosen language is invalid - PMA_fatalError( - 'Could not load any language, ' - . 'please check your language settings and folder.' - ); - } -} - -// Set locale -_setlocale(LC_MESSAGES, $GLOBALS['lang']); -_bindtextdomain('phpmyadmin', $GLOBALS['lang_path']); -_bind_textdomain_codeset('phpmyadmin', 'UTF-8'); -_textdomain('phpmyadmin'); - -/** - * Messages for phpMyAdmin. - * - * These messages are here for easy transition to Gettext. - * You should not add any messages here, use instead gettext directly - * in your template/PHP file. - */ - -if (! function_exists('__')) { - PMA_fatalError('Bad invocation!'); -} - -/* Text direction for language */ -if (in_array($GLOBALS['lang'], array('ar', 'fa', 'he', 'ur'))) { - $GLOBALS['text_dir'] = 'rtl'; -} else { - $GLOBALS['text_dir'] = 'ltr'; -} - -/* TCPDF */ -$GLOBALS['l'] = array(); - -/* TCPDF settings */ -$GLOBALS['l']['a_meta_charset'] = 'UTF-8'; -$GLOBALS['l']['a_meta_dir'] = $GLOBALS['text_dir']; -$GLOBALS['l']['a_meta_language'] = $GLOBALS['lang']; - -/* TCPDF translations */ -$GLOBALS['l']['w_page'] = __('Page number:'); - - -// now, that we have loaded the language strings we can send the errors -if ($GLOBALS['lang_failed_cfg'] - || $GLOBALS['lang_failed_cookie'] - || $GLOBALS['lang_failed_request'] -) { - trigger_error( - __('Ignoring unsupported language code.'), - E_USER_ERROR - ); -} -unset( - $line, $fall_back_lang, $GLOBALS['lang_failed_cfg'], - $GLOBALS['lang_failed_cookie'], $GLOBALS['lang_failed_request'] -); diff --git a/libraries/select_lang.lib.php b/libraries/select_lang.lib.php deleted file mode 100644 index f5e259d875..0000000000 --- a/libraries/select_lang.lib.php +++ /dev/null @@ -1,467 +0,0 @@ - $value) { - // $envType = 1 for the 'HTTP_ACCEPT_LANGUAGE' environment variable, - // 2 for the 'HTTP_USER_AGENT' one - $expr = $value[0]; - if (mb_strpos($expr, '[-_]') === false) { - $expr = str_replace('|', '([-_][[:alpha:]]{2,3})?|', $expr); - } - $pattern1 = '/^(' . addcslashes($expr, '/') . ')(;q=[0-9]\\.[0-9])?$/i'; - $pattern2 = '/(\(|\[|;[[:space:]])(' . addcslashes($expr, '/') - . ')(;|\]|\))/i'; - if (($envType == 1 && preg_match($pattern1, $str)) - || ($envType == 2 && preg_match($pattern2, $str)) - ) { - if (PMA_langSet($lang)) { - return true; - } - } - } - - return false; -} // end of the 'PMA_langDetect()' function - - -/** - * All the supported languages have to be listed in the array below. - * 1. The key must be the "official" ISO 639 language code and, if required, - * the dialect code. It can also contain some information about the - * charset (see the Russian case). - * 2. The first of the values associated to the key is used in a regular - * expression to find some keywords corresponding to the language inside two - * environment variables. - * These values contain: - * - the "official" ISO language code and, if required, the dialect code - * too ('bu' for Bulgarian, 'fr([-_][[:alpha:]]{2})?' for all French - * dialects, 'zh[-_]tw' for Chinese traditional...), the dialect has to - * be specified first; - * - the '|' character (it means 'OR'); - * - the full language name. - * 3. The second value associated to the key is the language code as defined by - * the RFC1766. - * 4. The third value is its native name in html entities or UTF-8. - * - * Beware that the sorting order (first values associated to keys by - * alphabetical reverse order in the array) is important: 'zh-tw' (chinese - * traditional) must be detected before 'zh' (chinese simplified) for - * example. - * - * @param string $lang language - * - * @return array - */ -function PMA_langDetails($lang) -{ - switch ($lang) { - case 'af': - return array('af|afrikaans', 'af', ''); - case 'ar': - return array( - 'ar|arabic', - 'ar', - 'العربية' - ); - case 'az': - return array('az|azerbaijani', 'az', 'Azərbaycanca'); - case 'bn': - return array('bn|bangla', 'bn', 'বাংলা'); - case 'be': - return array( - 'be|belarusian', - 'be', - 'Беларуская' - ); - case 'be@latin': - return array('be[-_]lat|belarusian latin', 'be-lat', 'Biełaruskaja'); - case 'bg': - return array( - 'bg|bulgarian', - 'bg', - 'Български' - ); - case 'bs': - return array('bs|bosnian', 'bs', 'Bosanski'); - case 'br': - return array('br|breton', 'br', 'Brezhoneg'); - case 'brx': - return array('brx|bodo', 'brx', 'बड़ो'); - case 'ca': - return array('ca|catalan', 'ca', 'Català'); - case 'ckb': - return array('ckb', 'ckb', 'سۆرانی'); - case 'cs': - return array('cs|czech', 'cs', 'Čeština'); - case 'cy': - return array('cy|welsh', 'cy', 'Cymraeg'); - case 'da': - return array('da|danish', 'da', 'Dansk'); - case 'de': - return array('de|german', 'de', 'Deutsch'); - case 'el': - return array( - 'el|greek', - 'el', - 'Ελληνικά' - ); - case 'en': - return array('en|english', 'en', ''); - case 'en_GB': - return array('en[_-]gb|english (United Kingdom)', 'en-gb', ''); - case 'eo': - return array('eo|esperanto', 'eo', 'Esperanto'); - case 'es': - return array('es|spanish', 'es', 'Español'); - case 'et': - return array('et|estonian', 'et', 'Eesti'); - case 'eu': - return array('eu|basque', 'eu', 'Euskara'); - case 'fa': - return array('fa|persian', 'fa', 'فارسی'); - case 'fi': - return array('fi|finnish', 'fi', 'Suomi'); - case 'fr': - return array('fr|french', 'fr', 'Français'); - case 'fy': - return array('fy|frisian', 'fy', 'Frysk'); - case 'gl': - return array('gl|galician', 'gl', 'Galego'); - case 'gu': - return array('gu|gujarati', 'gu', 'ગુજરાતી'); - case 'he': - return array('he|hebrew', 'he', 'עברית'); - case 'hi': - return array('hi|hindi', 'hi', 'हिन्दी'); - case 'hr': - return array('hr|croatian', 'hr', 'Hrvatski'); - case 'hu': - return array('hu|hungarian', 'hu', 'Magyar'); - case 'hy': - return array('hy|armenian', 'hy', 'Հայերէն'); - case 'ia': - return array('ia|interlingua', 'ia', 'Interlingua'); - case 'id': - return array('id|indonesian', 'id', 'Bahasa Indonesia'); - case 'it': - return array('it|italian', 'it', 'Italiano'); - case 'ja': - return array('ja|japanese', 'ja', '日本語'); - case 'ko': - return array('ko|korean', 'ko', '한국어'); - case 'ka': - return array( - 'ka|georgian', - 'ka', - 'ქართული' - ); - case 'kk': - return array('kk|kazakh', 'kk', 'Қазақ'); - case 'km': - return array('km|khmer', 'km', 'ខ្មែរ'); - case 'kn': - return array('kn|kannada', 'kn', 'ಕನ್ನಡ'); - case 'ksh': - return array('ksh|colognian', 'ksh', 'Kölsch'); - case 'ky': - return array('ky|kyrgyz', 'ky', 'Кыргызча'); - case 'li': - return array('li|limburgish', 'li', 'Lèmbörgs'); - case 'lt': - return array('lt|lithuanian', 'lt', 'Lietuvių'); - case 'lv': - return array('lv|latvian', 'lv', 'Latviešu'); - case 'mk': - return array('mk|macedonian', 'mk', 'Macedonian'); - case 'ml': - return array('ml|malayalam', 'ml', 'Malayalam'); - case 'mn': - return array( - 'mn|mongolian', - 'mn', - 'Монгол' - ); - case 'ms': - return array('ms|malay', 'ms', 'Bahasa Melayu'); - case 'ne': - return array('ne|nepali', 'ne', 'नेपाली'); - case 'nl': - return array('nl|dutch', 'nl', 'Nederlands'); - case 'nb': - return array('nb|norwegian', 'nb', 'Norsk'); - case 'pa': - return array('pa|punjabi', 'pa', 'ਪੰਜਾਬੀ'); - case 'pl': - return array('pl|polish', 'pl', 'Polski'); - case 'pt_BR': - return array('pt[-_]br|brazilian portuguese', 'pt-BR', 'Português'); - case 'pt': - return array('pt|portuguese', 'pt', 'Português'); - case 'ro': - return array('ro|romanian', 'ro', 'Română'); - case 'ru': - return array( - 'ru|russian', - 'ru', - 'Русский' - ); - case 'si': - return array('si|sinhala', 'si', 'සිංහල'); - case 'sk': - return array('sk|slovak', 'sk', 'Slovenčina'); - case 'sl': - return array('sl|slovenian', 'sl', 'Slovenščina'); - case 'sq': - return array('sq|albanian', 'sq', 'Shqip'); - case 'sr@latin': - return array('sr[-_]lat|serbian latin', 'sr-lat', 'Srpski'); - case 'sr': - return array( - 'sr|serbian', - 'sr', - 'Српски' - ); - case 'sv': - return array('sv|swedish', 'sv', 'Svenska'); - case 'ta': - return array('ta|tamil', 'ta', 'தமிழ்'); - case 'te': - return array('te|telugu', 'te', 'తెలుగు'); - case 'th': - return array( - 'th|thai', - 'th', - 'ภาษาไทย' - ); - case 'tk': - return array('tk|turkmen', 'tk', 'türkmençe'); - case 'tr': - return array('tr|turkish', 'tr', 'Türkçe'); - case 'tt': - return array('tt|tatarish', 'tt', 'Tatarça'); - case 'ug': - return array('ug|uyghur', 'ug', 'ئۇيغۇرچە'); - case 'uk': - return array( - 'uk|ukrainian', - 'uk', - 'Українська' - ); - case 'ur': - return array('ur|urdu', 'ur', 'اُردوُ'); - case 'uz@latin': - return array('uz[-_]lat|uzbek-latin', 'uz-lat', 'O‘zbekcha'); - case 'uz': - return array( - 'uz[-_]cyr|uzbek-cyrillic', - 'uz-cyr', - 'Ўзбекча' - ); - case 'vi': - return array('vi|vietnamese', 'vi', 'Tiếng Việt'); - case 'vls': - return array('vls|flemish', 'vls', 'West-Vlams'); - case 'zh_TW': - return array( - 'zh[-_](tw|hk)|chinese traditional', - 'zh-TW', - '中文' - ); - case 'zh_CN': - // only TW and HK use traditional Chinese while others (CN, SG, MY) - // use simplified Chinese - return array( - 'zh(?![-_](tw|hk))([-_][[:alpha:]]{2,3})?|chinese simplified', - 'zh', - '中文' - ); - } - return array("$lang|$lang", $lang, $lang); -} - -/** - * Returns list of languages supported by phpMyAdmin - * - * @return array - */ -function PMA_langList() -{ - /* We can always speak English */ - $result = array('en' => PMA_langDetails('en')); - - /* Check for existing directory */ - if (!is_dir($GLOBALS['lang_path'])) { - return $result; - } - - /* Open the directory */ - $handle = @opendir($GLOBALS['lang_path']); - /* This can happen if the kit is English-only */ - if ($handle === false) { - return $result; - } - - /* Process all files */ - while (false !== ($file = readdir($handle))) { - $path = $GLOBALS['lang_path'] . '/' . $file . '/LC_MESSAGES/phpmyadmin.mo'; - if ($file != "." - && $file != ".." - && file_exists($path) - ) { - $result[$file] = PMA_langDetails($file); - } - } - /* Close the handle */ - closedir($handle); - - return $result; -} diff --git a/test/classes/HeaderTest.php b/test/classes/HeaderTest.php index 2a4d6a3b7f..5385f327a7 100644 --- a/test/classes/HeaderTest.php +++ b/test/classes/HeaderTest.php @@ -16,7 +16,6 @@ require_once 'libraries/core.lib.php'; require_once 'libraries/database_interface.inc.php'; require_once 'libraries/url_generating.lib.php'; require_once 'libraries/vendor_config.php'; -require_once 'libraries/select_lang.inc.php'; require_once 'libraries/relation.lib.php'; require_once 'libraries/js_escape.lib.php'; require_once 'test/PMATestCase.php'; diff --git a/test/classes/MenuTest.php b/test/classes/MenuTest.php index 9a9cdd22b1..3376ad6153 100644 --- a/test/classes/MenuTest.php +++ b/test/classes/MenuTest.php @@ -17,7 +17,6 @@ require_once 'libraries/core.lib.php'; require_once 'libraries/database_interface.inc.php'; require_once 'libraries/url_generating.lib.php'; require_once 'libraries/vendor_config.php'; -require_once 'libraries/select_lang.inc.php'; require_once 'libraries/relation.lib.php'; require_once 'test/PMATestCase.php'; diff --git a/test/classes/plugin/auth/AuthenticationCookieTest.php b/test/classes/plugin/auth/AuthenticationCookieTest.php index bc32e801e5..693ae3a651 100644 --- a/test/classes/plugin/auth/AuthenticationCookieTest.php +++ b/test/classes/plugin/auth/AuthenticationCookieTest.php @@ -16,7 +16,6 @@ require_once 'libraries/config.default.php'; require_once 'libraries/js_escape.lib.php'; require_once 'libraries/sanitizing.lib.php'; require_once 'libraries/database_interface.inc.php'; -require_once 'libraries/select_lang.inc.php'; require_once 'libraries/plugins/auth/AuthenticationCookie.php'; require_once 'test/PMATestCase.php'; diff --git a/test/libraries/common/PMA_checkParameters_test.php b/test/libraries/common/PMA_checkParameters_test.php index 1e73e60541..038590133b 100644 --- a/test/libraries/common/PMA_checkParameters_test.php +++ b/test/libraries/common/PMA_checkParameters_test.php @@ -14,9 +14,6 @@ use PMA\libraries\Theme; require_once 'libraries/core.lib.php'; - - -require_once 'libraries/select_lang.inc.php'; require_once 'libraries/sanitizing.lib.php'; /** diff --git a/test/libraries/core/PMA_fatalError_test.php b/test/libraries/core/PMA_fatalError_test.php index 757b9a003a..9e99b17b34 100644 --- a/test/libraries/core/PMA_fatalError_test.php +++ b/test/libraries/core/PMA_fatalError_test.php @@ -19,7 +19,6 @@ require_once 'libraries/vendor_config.php'; require_once 'libraries/core.lib.php'; require_once 'libraries/js_escape.lib.php'; -require_once 'libraries/select_lang.inc.php'; require_once 'libraries/sanitizing.lib.php'; require_once 'libraries/url_generating.lib.php'; diff --git a/test/libraries/core/PMA_headerLocation_test.php b/test/libraries/core/PMA_headerLocation_test.php index b10c3f1988..2bdd2497c5 100644 --- a/test/libraries/core/PMA_headerLocation_test.php +++ b/test/libraries/core/PMA_headerLocation_test.php @@ -15,7 +15,6 @@ use PMA\libraries\Theme; require_once 'libraries/vendor_config.php'; require_once 'libraries/core.lib.php'; require_once 'libraries/js_escape.lib.php'; -require_once 'libraries/select_lang.inc.php'; require_once 'libraries/sanitizing.lib.php'; require_once 'libraries/url_generating.lib.php'; diff --git a/test/libraries/core/PMA_warnMissingExtension_test.php b/test/libraries/core/PMA_warnMissingExtension_test.php index f362b580b8..a9cceda152 100644 --- a/test/libraries/core/PMA_warnMissingExtension_test.php +++ b/test/libraries/core/PMA_warnMissingExtension_test.php @@ -14,9 +14,6 @@ use PMA\libraries\Theme; require_once 'libraries/vendor_config.php'; require_once 'libraries/core.lib.php'; -require_once 'libraries/select_lang.inc.php'; - - require_once 'libraries/js_escape.lib.php'; require_once 'libraries/sanitizing.lib.php'; diff --git a/test/libraries/select_lang/PMA_langDetails_test.php b/test/libraries/select_lang/PMA_langDetails_test.php deleted file mode 100644 index 609cbe1404..0000000000 --- a/test/libraries/select_lang/PMA_langDetails_test.php +++ /dev/null @@ -1,195 +0,0 @@ -assertEquals(array($a, $b, $c), PMA_langDetails($d)); - } -} diff --git a/test/libraries/select_lang/PMA_langList_test.php b/test/libraries/select_lang/PMA_langList_test.php deleted file mode 100644 index 98fc4f04ec..0000000000 --- a/test/libraries/select_lang/PMA_langList_test.php +++ /dev/null @@ -1,76 +0,0 @@ - PMA_langDetails('en')); - - $this->assertEquals($expected, PMA_langList()); - } - - /** - * Test for PMA_langList - * - * @return void - */ - function testLangListWithDir() - { - $GLOBALS['lang_path'] = './locale/'; - $expected = array('en' => PMA_langDetails('en')); - - $handle = @opendir($GLOBALS['lang_path']); - if ($handle === false) { - $this->markTestSkipped("Cannot open file with locales"); - } - - while (false !== ($file = readdir($handle))) { - $path = $GLOBALS['lang_path'] . '/' . $file - . '/LC_MESSAGES/phpmyadmin.mo'; - if ($file != "." && $file != ".." && file_exists($path)) { - $expected[$file] = PMA_langDetails($file); - } - } - - $this->assertEquals($expected, PMA_langList()); - } - - /** - * Test for PMA_langList - * - * @return void - */ - function testLangListWithWrongDir() - { - $GLOBALS['lang_path'] = '/root/'; - $expected = array('en' => PMA_langDetails('en')); - - $this->assertEquals($expected, PMA_langList()); - } -} diff --git a/test/libraries/select_lang/PMA_langName_test.php b/test/libraries/select_lang/PMA_langName_test.php deleted file mode 100644 index 5cf727e967..0000000000 --- a/test/libraries/select_lang/PMA_langName_test.php +++ /dev/null @@ -1,57 +0,0 @@ -assertEquals($result, PMA_languageName($test)); - } -} diff --git a/test/libraries/select_lang/locale_gettext_test.php b/test/libraries/select_lang/locale_gettext_test.php deleted file mode 100644 index 08cbad1c6b..0000000000 --- a/test/libraries/select_lang/locale_gettext_test.php +++ /dev/null @@ -1,59 +0,0 @@ -assertTrue(PMA_langSet($locale)); - - /* Bind locales */ - _setlocale(LC_MESSAGES, $GLOBALS['lang']); - _bind_textdomain_codeset('phpmyadmin', 'UTF-8'); - _textdomain('phpmyadmin'); - - /* Grab some texts */ - $this->assertContains('%s', _ngettext('%s table', '%s tables', 10)); - $this->assertContains('%s', _ngettext('%s table', '%s tables', 1)); - } - - /** - * Data provider to generate list of available locales. - * - * @return array with arrays of available locales - */ - public function listLocales() - { - $ret = array(); - foreach ($GLOBALS['available_languages'] as $key => $val) { - $ret[] = array($key); - } - return $ret; - } -} From bd779eeaea3f4ec95646d1608fa3dc1ba7208958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 14:07:43 +0100 Subject: [PATCH 6/9] Implement language selection using LanguageManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #11847 Signed-off-by: Michal Čihař --- libraries/Language.php | 12 +++++++++++ libraries/LanguageManager.php | 2 +- libraries/display_select_lang.lib.php | 31 ++++++--------------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/libraries/Language.php b/libraries/Language.php index c40b5b9bd1..1704cd8a9d 100644 --- a/libraries/Language.php +++ b/libraries/Language.php @@ -86,6 +86,18 @@ class Language return $this->code; } + /** + * Compare function used for sorting + * + * @param Language $other Other object to compare + * + * @return int same as strcmp + */ + public function cmp($other) + { + return strcmp($this->name, $other->name); + } + /** * Checks whether language is currently active. * diff --git a/libraries/LanguageManager.php b/libraries/LanguageManager.php index 7c4b31c5a9..cce10d1a2b 100644 --- a/libraries/LanguageManager.php +++ b/libraries/LanguageManager.php @@ -568,7 +568,7 @@ class LanguageManager $this->availableLanguages(); uasort($this->_available_languages, function($a, $b) { - return strcmp($a->name, $b->name); + return $a->cmp($b); } ); return $this->_available_languages; diff --git a/libraries/display_select_lang.lib.php b/libraries/display_select_lang.lib.php index 1318c8b10d..295894e574 100644 --- a/libraries/display_select_lang.lib.php +++ b/libraries/display_select_lang.lib.php @@ -5,20 +5,7 @@ * * @package PhpMyAdmin */ - -/** - * Compares the names of two languages. - * Used by uasort in PMA_getLanguageSelectorHtml() - * - * @param array $a The first language being compared - * @param array $b The second language being compared - * - * @return int the sorted array - */ -function PMA_languageCmp($a, $b) -{ - return strcmp($a[1], $b[1]); -} +use PMA\libraries\LanguageManager; /** * Returns HTML code for the language selector @@ -32,13 +19,12 @@ function PMA_languageCmp($a, $b) */ function PMA_getLanguageSelectorHtml($use_fieldset = false, $show_doc = true) { - global $lang; - $retval = ''; + $available_languages = LanguageManager::getInstance()->sortedLanguages(); // Display language selection only if there // is more than one language to choose from - if (count($GLOBALS['available_languages']) > 1) { + if (count($available_languages) > 1) { $retval .= '
'; $_form_params = array( @@ -66,18 +52,15 @@ function PMA_getLanguageSelectorHtml($use_fieldset = false, $show_doc = true) $retval .= '