diff --git a/ChangeLog b/ChangeLog
index 9b052fb070..304fd48c36 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -32,6 +32,7 @@ phpMyAdmin - ChangeLog
- issue Handle empty TABLE_COMMENT
+ issue #11833 Drop support for old Internet Explorer versions
+ issue #11796 Use modals for displaying forms in db structure page
++ issue #11789 Show MySQL error messages in user language
4.5.4.0 (not yet released)
- issue #11724 live data edit of big sets is not working
@@ -56,6 +57,7 @@ phpMyAdmin - ChangeLog
- issue #11804 Misleading message for configuration storage
- issue #11772 Table pagination does nothing when session expired
- issue #11840 Index comments not working properly
+- issue #11791 Better handle local storage errors
4.5.3.1 (2015-12-25)
- issue #11774 Undefined offset 2
diff --git a/index.php b/index.php
index 09ee1c8104..14a6832ac2 100644
--- a/index.php
+++ b/index.php
@@ -231,7 +231,7 @@ echo '
' , __('Appearance settings') , '
';
echo ' ';
// Displays language selection combo
-if (empty($cfg['Lang']) && count($GLOBALS['available_languages']) > 1) {
+if (empty($cfg['Lang'])) {
echo '- ';
include_once 'libraries/display_select_lang.lib.php';
echo PMA\libraries\Util::getImage('s_lang.png') , " "
diff --git a/js/config.js b/js/config.js
index 2b173cf47d..61e4481296 100644
--- a/js/config.js
+++ b/js/config.js
@@ -711,7 +711,7 @@ AJAX.registerOnload('config.js', function () {
});
// detect localStorage state
- var ls_supported = window.localStorage || false;
+ var ls_supported = isStorageSupported('localStorage');
var ls_exists = ls_supported ? (window.localStorage.config || false) : false;
$('div.localStorage-' + (ls_supported ? 'un' : '') + 'supported').hide();
$('div.localStorage-' + (ls_exists ? 'empty' : 'exists')).hide();
@@ -811,7 +811,7 @@ function updatePrefsDate()
*/
function offerPrefsAutoimport()
{
- var has_config = (window.localStorage || false) && (window.localStorage.config || false);
+ var has_config = (isStorageSupported('localStorage')) && (window.localStorage.config || false);
var $cnt = $('#prefs_autoload');
if (!$cnt.length || !has_config) {
return;
diff --git a/js/messages.php b/js/messages.php
index d199b8f866..f8e31e2cfa 100644
--- a/js/messages.php
+++ b/js/messages.php
@@ -706,16 +706,13 @@ $js_messages['strConsoleDebugArgsSummary'] = __('%s argument(s) passed');
$js_messages['strConsoleDebugShowArgs'] = __('Show arguments');
$js_messages['strConsoleDebugHideArgs'] = __('Hide arguments');
$js_messages['strConsoleDebugTimeTaken'] = __('Time taken:');
-$js_messages['strNoLocalStorage'] = __(
- 'Your web browser does not support local storage of settings or the quota '
- . 'limit has been reached, some features may not work properly for you. In '
- . 'Safari, such problem is commonly caused by "Private Mode Browsing".'
-);
+$js_messages['strNoLocalStorage'] = __('There was a problem accessing your browser storage, some features may not work properly for you. It is likely that the browser doesn\'t support storage or the quota limit has been reached. In Firefox, corrupted storage can also cause such a problem, clearing your "Offline Website Data" might help. In Safari, such problem is commonly caused by "Private Mode Browsing".');
// For modals in db_structure.php
$js_messages['strCopyTablesTo'] = __('Copy tables to');
$js_messages['strAddPrefix'] = __('Add table prefix');
$js_messages['strReplacePrefix'] = __('Replace table with prefix');
$js_messages['strCopyPrefix'] = __('Copy table with prefix');
+
echo "var PMA_messages = new Array();\n";
foreach ($js_messages as $name => $js_message) {
PMA_printJsValue("PMA_messages['" . $name . "']", $js_message);
diff --git a/js/server_status_monitor.js b/js/server_status_monitor.js
index e6991cd529..bf891bc1b7 100644
--- a/js/server_status_monitor.js
+++ b/js/server_status_monitor.js
@@ -632,8 +632,10 @@ AJAX.registerOnload('server_status_monitor.js', function () {
} catch (err) {
alert(PMA_messages.strFailedBuildingGrid);
// If an exception is thrown, load default again
- window.localStorage.removeItem('monitorCharts');
- window.localStorage.removeItem('monitorSettings');
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.removeItem('monitorCharts');
+ window.localStorage.removeItem('monitorSettings');
+ }
rebuildGrid();
}
@@ -659,9 +661,11 @@ AJAX.registerOnload('server_status_monitor.js', function () {
$('a[href="#clearMonitorConfig"]').click(function (event) {
event.preventDefault();
- window.localStorage.removeItem('monitorCharts');
- window.localStorage.removeItem('monitorSettings');
- window.localStorage.removeItem('monitorVersion');
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.removeItem('monitorCharts');
+ window.localStorage.removeItem('monitorSettings');
+ window.localStorage.removeItem('monitorVersion');
+ }
$(this).hide();
rebuildGrid();
});
@@ -938,17 +942,20 @@ AJAX.registerOnload('server_status_monitor.js', function () {
var i;
/* Apply default values & config */
- if (window.localStorage) {
- if (window.localStorage.monitorCharts) {
+ if (isStorageSupported('localStorage')) {
+ if (typeof window.localStorage.monitorCharts !== 'undefined') {
runtime.charts = $.parseJSON(window.localStorage.monitorCharts);
}
- if (window.localStorage.monitorSettings) {
+ if (typeof window.localStorage.monitorSettings !== 'undefined') {
monitorSettings = $.parseJSON(window.localStorage.monitorSettings);
}
$('a[href="#clearMonitorConfig"]').toggle(runtime.charts !== null);
- if (runtime.charts !== null && monitorProtocolVersion != window.localStorage.monitorVersion) {
+ if (runtime.charts !== null
+ && typeof window.localStorage.monitorVersion !== 'undefined'
+ && monitorProtocolVersion != window.localStorage.monitorVersion
+ ) {
$('#emptyDialog').dialog({title: PMA_messages.strIncompatibleMonitorConfig});
$('#emptyDialog').html(PMA_messages.strIncompatibleMonitorConfigDescription);
@@ -2122,7 +2129,7 @@ AJAX.registerOnload('server_status_monitor.js', function () {
gridCopy[key].maxYLabel = elem.maxYLabel;
});
- if (window.localStorage) {
+ if (isStorageSupported('localStorage')) {
window.localStorage.monitorCharts = JSON.stringify(gridCopy);
window.localStorage.monitorSettings = JSON.stringify(monitorSettings);
window.localStorage.monitorVersion = monitorProtocolVersion;
diff --git a/libraries/DatabaseInterface.php b/libraries/DatabaseInterface.php
index 3384940f8c..0b094daeaa 100644
--- a/libraries/DatabaseInterface.php
+++ b/libraries/DatabaseInterface.php
@@ -8,6 +8,7 @@
namespace PMA\libraries;
use PMA\libraries\dbi\DBIExtension;
+use PMA\libraries\LanguageManager;
require_once './libraries/logging.lib.php';
require_once './libraries/util.lib.php';
@@ -1529,6 +1530,16 @@ class DatabaseInterface
self::QUERY_STORE
);
}
+
+ /* Locale for messages */
+ $locale = LanguageManager::getInstance()->getCurrentLanguage()->getMySQLLocale();
+ if (! empty($locale)) {
+ $this->query(
+ "SET lc_messages = '" . $locale . "';",
+ $link,
+ self::QUERY_STORE
+ );
+ }
}
/**
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/Language.php b/libraries/Language.php
new file mode 100644
index 0000000000..866c82b4c0
--- /dev/null
+++ b/libraries/Language.php
@@ -0,0 +1,200 @@
+code = $code;
+ $this->name = $name;
+ $this->native = $native;
+ if (strpos($regex, '[-_]') === false) {
+ $regex = str_replace('|', '([-_][[:alpha:]]{2,3})?|', $regex);
+ }
+ $this->regex = $regex;
+ $this->mysql = $mysql;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns MySQL locale code, can be empty
+ *
+ * @return string
+ */
+ public function getMySQLLocale()
+ {
+ return $this->mysql;
+ }
+
+ /**
+ * 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.
+ *
+ * @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..31fb6e2700
--- /dev/null
+++ b/libraries/LanguageManager.php
@@ -0,0 +1,783 @@
+ array(
+ 'Afrikaans',
+ '',
+ 'af|afrikaans',
+ '',
+ ),
+ 'ar' => array(
+ 'Arabic',
+ 'العربية',
+ 'ar|arabic',
+ 'ar_AE',
+ ),
+ 'az' => array(
+ 'Azerbaijani',
+ 'Azərbaycanca',
+ 'az|azerbaijani',
+ '',
+ ),
+ 'bn' => array(
+ 'Bangla',
+ 'বাংলা',
+ 'bn|bangla',
+ '',
+ ),
+ 'be' => array(
+ 'Belarusian',
+ 'Беларуская',
+ 'be|belarusian',
+ 'be_BY',
+ ),
+ 'be@latin' => array(
+ 'Belarusian (latin)',
+ 'Biełaruskaja',
+ 'be[-_]lat|be@latin|belarusian latin',
+ '',
+ ),
+ 'bg' => array(
+ 'Bulgarian',
+ 'Български',
+ 'bg|bulgarian',
+ 'bg_BG',
+ ),
+ 'bs' => array(
+ 'Bosnian',
+ 'Bosanski',
+ 'bs|bosnian',
+ '',
+ ),
+ 'br' => array(
+ 'Breton',
+ 'Brezhoneg',
+ 'br|breton',
+ '',
+ ),
+ 'brx' => array(
+ 'Bodo',
+ 'बड़ो',
+ 'brx|bodo',
+ '',
+ ),
+ 'ca' => array(
+ 'Catalan',
+ 'Català',
+ 'ca|catalan',
+ 'ca_ES',
+ ),
+ 'ckb' => array(
+ 'Sorani',
+ 'سۆرانی',
+ 'ckb|sorani',
+ '',
+ ),
+ 'cs' => array(
+ 'Czech',
+ 'Čeština',
+ 'cs|czech',
+ 'cs_CZ',
+ ),
+ 'cy' => array(
+ 'Welsh',
+ 'Cymraeg',
+ 'cy|welsh',
+ '',
+ ),
+ 'da' => array(
+ 'Danish',
+ 'Dansk',
+ 'da|danish',
+ 'da_DK',
+ ),
+ 'de' => array(
+ 'German',
+ 'Deutsch',
+ 'de|german',
+ 'de_DE',
+ ),
+ 'el' => array(
+ 'Greek',
+ 'Ελληνικά',
+ 'el|greek',
+ '',
+ ),
+ 'en' => array(
+ 'English',
+ '',
+ 'en|english',
+ 'en_US',
+ ),
+ 'en_gb' => array(
+ 'English (United Kingdom)',
+ '',
+ 'en[_-]gb|english (United Kingdom)',
+ 'en_GB',
+ ),
+ 'eo' => array(
+ 'Esperanto',
+ 'Esperanto',
+ 'eo|esperanto',
+ '',
+ ),
+ 'es' => array(
+ 'Spanish',
+ 'Español',
+ 'es|spanish',
+ 'es_ES',
+ ),
+ 'et' => array(
+ 'Estonian',
+ 'Eesti',
+ 'et|estonian',
+ 'et_EE',
+ ),
+ 'eu' => array(
+ 'Basque',
+ 'Euskara',
+ 'eu|basque',
+ 'eu_ES',
+ ),
+ 'fa' => array(
+ 'Persian',
+ 'فارسی',
+ 'fa|persian',
+ '',
+ ),
+ 'fi' => array(
+ 'Finnish',
+ 'Suomi',
+ 'fi|finnish',
+ 'fi_FI',
+ ),
+ 'fr' => array(
+ 'French',
+ 'Français',
+ 'fr|french',
+ 'fr_FR',
+ ),
+ 'fy' => array(
+ 'Frisian',
+ 'Frysk',
+ 'fy|frisian',
+ '',
+ ),
+ 'gl' => array(
+ 'Galician',
+ 'Galego',
+ 'gl|galician',
+ 'gl_ES',
+ ),
+ 'gu' => array(
+ 'Gujarati',
+ 'ગુજરાતી',
+ 'gu|gujarati',
+ 'gu_IN',
+ ),
+ 'he' => array(
+ 'Hebrew',
+ 'עברית',
+ 'he|hebrew',
+ 'he_IL',
+ ),
+ 'hi' => array(
+ 'Hindi',
+ 'हिन्दी',
+ 'hi|hindi',
+ 'hi_IN',
+ ),
+ 'hr' => array(
+ 'Croatian',
+ 'Hrvatski',
+ 'hr|croatian',
+ 'hr_HR',
+ ),
+ 'hu' => array(
+ 'Hungarian',
+ 'Magyar',
+ 'hu|hungarian',
+ 'hu_HU',
+ ),
+ 'hy' => array(
+ 'Armenian',
+ 'Հայերէն',
+ 'hy|armenian',
+ '',
+ ),
+ 'ia' => array(
+ 'Interlingua',
+ '',
+ 'ia|interlingua',
+ '',
+ ),
+ 'id' => array(
+ 'Indonesian',
+ 'Bahasa Indonesia',
+ 'id|indonesian',
+ 'id_ID',
+ ),
+ 'it' => array(
+ 'Italian',
+ 'Italiano',
+ 'it|italian',
+ 'it_IT',
+ ),
+ 'ja' => array(
+ 'Japanese',
+ '日本語',
+ 'ja|japanese',
+ 'ja_JP',
+ ),
+ 'ko' => array(
+ 'Korean',
+ '한국어',
+ 'ko|korean',
+ 'ko_KR',
+ ),
+ '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',
+ 'lt_LT',
+ ),
+ 'lv' => array(
+ 'Latvian',
+ 'Latviešu',
+ 'lv|latvian',
+ 'lv_LV',
+ ),
+ 'mk' => array(
+ 'Macedonian',
+ 'Macedonian',
+ 'mk|macedonian',
+ 'mk_MK',
+ ),
+ 'ml' => array(
+ 'Malayalam',
+ 'Malayalam',
+ 'ml|malayalam',
+ '',
+ ),
+ 'mn' => array(
+ 'Mongolian',
+ 'Монгол',
+ 'mn|mongolian',
+ 'mn_MN',
+ ),
+ 'ms' => array(
+ 'Malay',
+ 'Bahasa Melayu',
+ 'ms|malay',
+ 'ms_MY',
+ ),
+ 'ne' => array(
+ 'Nepali',
+ 'नेपाली',
+ 'ne|nepali',
+ '',
+ ),
+ 'nb' => array(
+ 'Norwegian',
+ 'Norsk',
+ 'nb|norwegian',
+ 'nb_NO',
+ ),
+ 'nl' => array(
+ 'Dutch',
+ 'Nederlands',
+ 'nl|dutch',
+ 'nl_NL',
+ ),
+ 'pa' => array(
+ 'Punjabi',
+ 'ਪੰਜਾਬੀ',
+ 'pa|punjabi',
+ '',
+ ),
+ 'pl' => array(
+ 'Polish',
+ 'Polski',
+ 'pl|polish',
+ 'pl_PL',
+ ),
+ 'pt_br' => array(
+ 'Brazilian Portuguese',
+ 'Português',
+ 'pt[-_]br|brazilian portuguese',
+ 'pt_BR',
+ ),
+ 'pt' => array(
+ 'Portuguese',
+ 'Português',
+ 'pt|portuguese',
+ 'pt_PT',
+ ),
+ 'ro' => array(
+ 'Romanian',
+ 'Română',
+ 'ro|romanian',
+ 'ro_RO',
+ ),
+ 'ru' => array(
+ 'Russian',
+ 'Русский',
+ 'ru|russian',
+ 'ru_RU',
+ ),
+ 'si' => array(
+ 'Sinhala',
+ 'සිංහල',
+ 'si|sinhala',
+ '',
+ ),
+ 'sk' => array(
+ 'Slovak',
+ 'Slovenčina',
+ 'sk|slovak',
+ 'sk_SK',
+ ),
+ 'sl' => array(
+ 'Slovenian',
+ 'Slovenščina',
+ 'sl|slovenian',
+ 'sl_SI',
+ ),
+ 'sq' => array(
+ 'Slbanian',
+ 'Shqip',
+ 'sq|albanian',
+ 'sq_AL',
+ ),
+ 'sr@latin' => array(
+ 'Serbian (latin)',
+ 'Srpski',
+ 'sr[-_]lat|sr@latin|serbian latin',
+ 'sr_YU',
+ ),
+ 'sr' => array(
+ 'Serbian',
+ 'Српски',
+ 'sr|serbian',
+ 'sr_YU',
+ ),
+ 'sv' => array(
+ 'Swedish',
+ 'Svenska',
+ 'sv|swedish',
+ 'sv_SE',
+ ),
+ 'ta' => array(
+ 'Tamil',
+ 'தமிழ்',
+ 'ta|tamil',
+ 'ta_IN',
+ ),
+ 'te' => array(
+ 'Telugu',
+ 'తెలుగు',
+ 'te|telugu',
+ 'te_IN',
+ ),
+ 'th' => array(
+ 'Thai',
+ 'ภาษาไทย',
+ 'th|thai',
+ 'th_TH',
+ ),
+ 'tk' => array(
+ 'Turkmen',
+ 'Türkmençe',
+ 'tk|turkmen',
+ '',
+ ),
+ 'tr' => array(
+ 'Turkish',
+ 'Türkçe',
+ 'tr|turkish',
+ 'tr_TR',
+ ),
+ 'tt' => array(
+ 'Tatarish',
+ 'Tatarça',
+ 'tt|tatarish',
+ '',
+ ),
+ 'ug' => array(
+ 'Uyghur',
+ 'ئۇيغۇرچە',
+ 'ug|uyghur',
+ '',
+ ),
+ 'uk' => array(
+ 'Ukrainian',
+ 'Українська',
+ 'uk|ukrainian',
+ 'uk_UA',
+ ),
+ 'ur' => array(
+ 'Urdu',
+ 'اُردوُ',
+ 'ur|urdu',
+ 'ur_PK',
+ ),
+ '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',
+ 'vi_VN',
+ ),
+ 'vls' => array(
+ 'Flemish',
+ 'West-Vlams',
+ 'vls|flemish',
+ '',
+ ),
+ 'zh_tw' => array(
+ 'Chinese traditional',
+ '中文',
+ 'zh[-_](tw|hk)|chinese traditional',
+ 'zh_TW',
+ ),
+ // only TW and HK use traditional Chinese while others (CN, SG, MY)
+ // use simplified Chinese
+ 'zh_cn' => array(
+ 'Chinese simplified',
+ '中文',
+ 'zh(?)([-_][[:alpha:]]{2,3})?|chinese simplified',
+ 'zh_CN',
+ ),
+ );
+
+ 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],
+ $data[3]
+ );
+ } 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 $a->cmp($b);
+ }
+ );
+ 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;
+ }
+
+ /**
+ * Return currently active Language object
+ *
+ * @return object Language object
+ */
+ public function getCurrentLanguage()
+ {
+ return $this->_available_languages[$GLOBALS['lang']];
+ }
+
+ /**
+ * 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/common.inc.php b/libraries/common.inc.php
index 15fb535e01..0680cf472b 100644
--- a/libraries/common.inc.php
+++ b/libraries/common.inc.php
@@ -36,12 +36,12 @@ use PMA\libraries\ErrorHandler;
use PMA\libraries\Message;
use PMA\libraries\plugins\AuthenticationPlugin;
use PMA\libraries\DbList;
-use PMA\libraries\Theme;
use PMA\libraries\ThemeManager;
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
@@ -474,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') {
@@ -1090,3 +1096,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/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/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 .= '