From c32e2ed3a5093692184f0b2b02ed0f8079bfd155 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Tue, 12 Jan 2016 12:36:59 +0100 Subject: [PATCH 01/20] Translated using Weblate (French) Currently translated at 100.0% (3217 of 3217 strings) [CI skip] --- po/fr.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/po/fr.po b/po/fr.po index 806ee3218b..0bf1c68863 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin-docs 4.0.0-dev\n" "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n" "POT-Creation-Date: 2016-01-08 16:50+0100\n" -"PO-Revision-Date: 2016-01-09 15:57+0000\n" +"PO-Revision-Date: 2016-01-12 12:36+0000\n" "Last-Translator: Marc Delisle \n" "Language-Team: French " "\n" @@ -40,7 +40,7 @@ msgstr "Affichage des lignes %1$s - %2$s." #: db_datadict.php:57 libraries/operations.lib.php:34 msgid "Database comment" -msgstr "Commentaire sur la base de données :" +msgstr "Commentaire sur la base de données" #: db_datadict.php:104 libraries/plugins/schema/pdf/PdfRelationSchema.php:595 #: templates/columns_definitions/column_definitions_form.phtml:84 @@ -137,7 +137,7 @@ msgstr "Null" #: templates/database/structure/body_for_table_summary.phtml:55 #: templates/table/structure/table_structure_header.phtml:12 msgid "Default" -msgstr "Défaut" +msgstr "Valeur par défaut" #: db_datadict.php:118 libraries/plugins/export/ExportHtmlword.php:399 #: libraries/plugins/export/ExportLatex.php:528 From 0f23dd51d834e55d9629e39850af3a7673b48b11 Mon Sep 17 00:00:00 2001 From: Atul Pratap Singh Date: Tue, 12 Jan 2016 18:30:04 +0530 Subject: [PATCH 02/20] Add localStorage availability checks, update the error message Signed-off-by: Atul Pratap Singh --- ChangeLog | 1 + js/config.js | 4 ++-- js/messages.php | 2 +- js/server_status_monitor.js | 27 +++++++++++++++++---------- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3a8eb01e85..dff328e7a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,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/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 465df2ef97..d3a5cf71e1 100644 --- a/js/messages.php +++ b/js/messages.php @@ -604,7 +604,7 @@ $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".'); echo "var PMA_messages = new Array();\n"; foreach ($js_messages as $name => $js_message) { diff --git a/js/server_status_monitor.js b/js/server_status_monitor.js index 84b8a31477..14328a5975 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; From 5613c32029135370d7bbc01f9ebc87d7204014c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristjan=20R=C3=A4ts?= Date: Mon, 11 Jan 2016 14:10:49 +0100 Subject: [PATCH 03/20] Translated using Weblate (Estonian) Currently translated at 100.0% (3210 of 3210 strings) [CI skip] --- po/et.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/po/et.po b/po/et.po index 0e5031584f..e076b13b94 100644 --- a/po/et.po +++ b/po/et.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 4.5.3-dev\n" "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n" "POT-Creation-Date: 2015-12-16 07:59+0100\n" -"PO-Revision-Date: 2015-12-17 12:07+0000\n" +"PO-Revision-Date: 2016-01-11 14:10+0000\n" "Last-Translator: Kristjan Räts \n" "Language-Team: Estonian " "\n" @@ -23,8 +23,8 @@ msgid "" "The %s file is not available on this system, please visit www.phpmyadmin.net " "for more information." msgstr "" -"%s fail pole selles süsteemis saadaval. Lisateavet leiad aadressilt www." -"phpmyadmin.net ." +"Fail %s ei ole selles süsteemis saadaval; aadressilt www.phpmyadmin.net " +"leiad täiendavat informatsiooni." #: db_central_columns.php:105 msgid "The central list of columns for the current database is empty." From 814ea29854fb395468c5caa08d07a36000f750d0 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Tue, 12 Jan 2016 12:37:03 +0100 Subject: [PATCH 04/20] Translated using Weblate (French) Currently translated at 100.0% (3210 of 3210 strings) [CI skip] --- po/fr.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/po/fr.po b/po/fr.po index 1c26bae0a1..613e43e12d 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin-docs 4.0.0-dev\n" "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n" "POT-Creation-Date: 2015-12-16 07:59+0100\n" -"PO-Revision-Date: 2015-12-17 14:28+0000\n" +"PO-Revision-Date: 2016-01-12 12:36+0000\n" "Last-Translator: Marc Delisle \n" "Language-Team: French " "\n" @@ -45,7 +45,7 @@ msgstr "La base de données %1$s a été créée." #: db_datadict.php:58 libraries/operations.lib.php:33 msgid "Database comment" -msgstr "Commentaire sur la base de données :" +msgstr "Commentaire sur la base de données" #: db_datadict.php:105 #: libraries/plugins/schema/pdf/Pdf_Relation_Schema.class.php:966 @@ -142,7 +142,7 @@ msgstr "Null" #: templates/database/structure/body_for_table_summary.phtml:55 #: templates/table/structure/table_structure_header.phtml:10 msgid "Default" -msgstr "Défaut" +msgstr "Valeur par défaut" #: db_datadict.php:119 libraries/plugins/export/ExportHtmlword.class.php:389 #: libraries/plugins/export/ExportLatex.class.php:513 From 5b577198bb6be4956e56cf0eceac226d9173e672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xos=C3=A9=20Calvo?= Date: Mon, 11 Jan 2016 22:37:33 +0100 Subject: [PATCH 05/20] Translated using Weblate (Galician) Currently translated at 85.0% (2730 of 3210 strings) [CI skip] --- po/gl.po | 171 +++++++++++++++++++------------------------------------ 1 file changed, 59 insertions(+), 112 deletions(-) diff --git a/po/gl.po b/po/gl.po index b69ccdb923..4855879753 100644 --- a/po/gl.po +++ b/po/gl.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 4.5.3-dev\n" "Report-Msgid-Bugs-To: translators@phpmyadmin.net\n" "POT-Creation-Date: 2015-12-16 07:59+0100\n" -"PO-Revision-Date: 2015-12-17 22:28+0000\n" +"PO-Revision-Date: 2016-01-11 22:37+0000\n" "Last-Translator: Xosé Calvo \n" "Language-Team: Galician " "\n" @@ -5127,10 +5127,9 @@ msgid "key" msgstr "clave" #: libraries/config.values.php:99 -#, fuzzy #| msgid "Display columns table" msgid "display column" -msgstr "Mostrar a táboa de columnas" +msgstr "mostrar a columna" #: libraries/config.values.php:102 msgid "Welcome" @@ -6853,10 +6852,9 @@ msgid "Recently used tables" msgstr "Táboas usadas recentemente" #: libraries/config/messages.inc.php:545 -#, fuzzy #| msgid "These are Edit, Copy and Delete links" msgid "These are Edit, Copy and Delete links." -msgstr "Estas son as ligazóns Editar, Copiar e Eliminar" +msgstr "Estas son as ligazóns Editar, Copiar e Eliminar." #: libraries/config/messages.inc.php:546 msgid "Where to show the table row links" @@ -6871,12 +6869,11 @@ msgid "Show row links anyway" msgstr "" #: libraries/config/messages.inc.php:552 -#, fuzzy #| msgid "Use natural order for sorting table and database names" msgid "Use natural order for sorting table and database names." msgstr "" "Empregar a ordenación natural para ordenar os nomes das táboas e as bases de " -"datos" +"datos." #: libraries/config/messages.inc.php:553 msgid "Natural order" @@ -6884,29 +6881,26 @@ msgstr "Ordenación natural" #: libraries/config/messages.inc.php:554 libraries/config/messages.inc.php:585 #: libraries/config/messages.inc.php:587 -#, fuzzy #| msgid "Use only icons, only text or both" msgid "Use only icons, only text or both." -msgstr "Empregar só iconas, só texto ou ambos os dous" +msgstr "Empregar só iconas, só texto ou ambos os dous." #: libraries/config/messages.inc.php:555 msgid "Table navigation bar" msgstr "Barra de navegación das táboas" #: libraries/config/messages.inc.php:557 -#, fuzzy #| msgid "use GZip output buffering for increased speed in HTTP transfers" msgid "Use GZip output buffering for increased speed in HTTP transfers." msgstr "" "Empregar un buffer para a saída de GZip para atinxir unha maior velocidade " -"nas transferencias mediante HTTP" +"nas transferencias mediante HTTP." #: libraries/config/messages.inc.php:558 msgid "GZip output buffering" msgstr "Buffer para a saída de GZip" #: libraries/config/messages.inc.php:560 -#, fuzzy #| msgid "" #| "[kbd]SMART[/kbd] - i.e. descending order for columns of type TIME, DATE, " #| "DATETIME and TIMESTAMP, ascending order otherwise" @@ -6915,24 +6909,22 @@ msgid "" "DATETIME and TIMESTAMP, ascending order otherwise." msgstr "" "[kbd]INTELIXENTE[/kbd] - isto é, orde descendente para os campos do tipo " -"TIME, DATE, DATETIME e TIMESTAMP e ascendente para os demais" +"TIME, DATE, DATETIME e TIMESTAMP e ascendente para os demais." #: libraries/config/messages.inc.php:563 msgid "Default sorting order" msgstr "Ordenación por omisión" #: libraries/config/messages.inc.php:565 -#, fuzzy #| msgid "Use persistent connections to MySQL databases" msgid "Use persistent connections to MySQL databases." -msgstr "Empregar conexións persistentes coas bases de datos MySQL" +msgstr "Empregar conexións persistentes coas bases de datos MySQL." #: libraries/config/messages.inc.php:566 msgid "Persistent connections" msgstr "Conexións persistentes" #: libraries/config/messages.inc.php:568 -#, fuzzy #| msgid "" #| "Disable the default warning that is displayed on the database details " #| "Structure page if any of the required tables for the phpMyAdmin " @@ -6944,14 +6936,13 @@ msgid "" msgstr "" "Desactivar o aviso que por omisión se mostra na páxina de detalles da " "estrutura da base de datos se non foi posíbel atopar algunha das táboas " -"requiridas para o almacenamento da configuración do phpMyAdmin" +"requiridas para o almacenamento da configuración do phpMyAdmin." #: libraries/config/messages.inc.php:573 msgid "Missing phpMyAdmin configuration storage tables" msgstr "Faltan as táboas de almacenamento da configuración do phpMyAdmin" #: libraries/config/messages.inc.php:575 -#, fuzzy #| msgid "" #| "Disable the default warning that is displayed if a difference between the " #| "MySQL library and server is detected" @@ -6960,14 +6951,13 @@ msgid "" "MySQL library and server is detected." msgstr "" "Desactivar o aviso por omisión que aparece se se detecta unha diferenza " -"entre a biblioteca de MySQL e o servidor" +"entre a biblioteca de MySQL e o servidor." #: libraries/config/messages.inc.php:579 msgid "Server/library difference warning" msgstr "Advertencia de diferenza entre servidor e biblioteca" #: libraries/config/messages.inc.php:581 -#, fuzzy #| msgid "" #| "Disable the default warning that is displayed on the Structure page if " #| "column names in a table are reserved MySQL words" @@ -6976,7 +6966,7 @@ msgid "" "column names in a table are reserved MySQL words." msgstr "" "Desactivar o aviso que por omisión se mostra na páxina da estrutura da base " -"de datos se os nomes de columna dunha táboa son palabras reservadas do MySQL" +"de datos se os nomes de columna dunha táboa son palabras reservadas do MySQL." #: libraries/config/messages.inc.php:584 msgid "MySQL reserved word warning" @@ -6991,10 +6981,9 @@ msgid "How to display various action links" msgstr "Como mostrar diversas ligazóns de acción" #: libraries/config/messages.inc.php:589 -#, fuzzy #| msgid "Disallow BLOB and BINARY columns from editing" msgid "Disallow BLOB and BINARY columns from editing." -msgstr "Impedir a edición das columnas BLOB e BINARY" +msgstr "Impedir a edición das columnas BLOB e BINARY." #: libraries/config/messages.inc.php:590 msgid "Protect binary columns" @@ -7016,32 +7005,29 @@ msgid "Permanent query history" msgstr "Historial de consultas permanente" #: libraries/config/messages.inc.php:598 -#, fuzzy #| msgid "How many queries are kept in history" msgid "How many queries are kept in history." -msgstr "Cantas consultas se gardan no historial" +msgstr "Cantas consultas se gardan no historial." #: libraries/config/messages.inc.php:599 msgid "Query history length" msgstr "Lonxitude do historial de consultas" #: libraries/config/messages.inc.php:601 -#, fuzzy #| msgid "Select which functions will be used for character set conversion" msgid "Select which functions will be used for character set conversion." msgstr "" "Escolla as funcións que desexe empregar para a conversión dos conxuntos de " -"caracteres" +"caracteres." #: libraries/config/messages.inc.php:602 msgid "Recoding engine" msgstr "Motor de recodificación" #: libraries/config/messages.inc.php:604 -#, fuzzy #| msgid "When browsing tables, the sorting of each table is remembered" msgid "When browsing tables, the sorting of each table is remembered." -msgstr "Ao navegar polas táboas lémbrase a ordenación de cada unha delas" +msgstr "Ao navegar polas táboas lémbrase a ordenación de cada unha delas." #: libraries/config/messages.inc.php:605 msgid "Remember table's sorting" @@ -7058,14 +7044,13 @@ msgid "Primary key default sort order" msgstr "Ordenación por omisión" #: libraries/config/messages.inc.php:611 -#, fuzzy #| msgid "" #| "Repeat the headers every X cells, [kbd]0[/kbd] deactivates this feature" msgid "" "Repeat the headers every X cells, [kbd]0[/kbd] deactivates this feature." msgstr "" "Repetir os cabezallos cada X celas; [kbd]0[/kbd] desactiva esta " -"funcionalidade" +"funcionalidade." #: libraries/config/messages.inc.php:612 msgid "Repeat headers" @@ -7134,12 +7119,11 @@ msgid "" msgstr "" #: libraries/config/messages.inc.php:632 -#, fuzzy #| msgid "HTTP Basic Auth Realm name to display when doing HTTP Auth" msgid "HTTP Basic Auth Realm name to display when doing HTTP Auth." msgstr "" "Nome de HTTP Basic Auth Realm que mostrar cando se faga a autenticación " -"mediante HTTP" +"mediante HTTP Auth." #: libraries/config/messages.inc.php:633 msgid "HTTP Realm" @@ -7586,7 +7570,6 @@ msgid "Statements to track" msgstr "Instrucións que seguir" #: libraries/config/messages.inc.php:796 -#, fuzzy #| msgid "" #| "Leave blank for no SQL query tracking support, suggested: " #| "[kbd]pma__tracking[/kbd]" @@ -7595,7 +7578,7 @@ msgid "" "[kbd]pma__tracking[/kbd]." msgstr "" "Déixeo en branco se non quere a funcionalidade de seguimento das consultas " -"de SQL; valor suxerido: [kbd]pma_tracking[/kbd]" +"de SQL; valor suxerido: [kbd]pma_tracking[/kbd]." #: libraries/config/messages.inc.php:799 msgid "SQL query tracking table" @@ -7614,7 +7597,6 @@ msgid "Automatically create versions" msgstr "Crear versions automaticamente" #: libraries/config/messages.inc.php:807 -#, fuzzy #| msgid "" #| "Leave blank for no user preferences storage in database, suggested: " #| "[kbd]pma__userconfig[/kbd]" @@ -7623,7 +7605,7 @@ msgid "" "[kbd]pma__userconfig[/kbd]." msgstr "" "Déixeo en branco se non quere almacenar as preferencias na base de datos; " -"suxerido: [kbd]pma__userconfig[/kbd]" +"suxerido: [kbd]pma__userconfig[/kbd]." #: libraries/config/messages.inc.php:810 msgid "User preferences storage table" @@ -7637,10 +7619,9 @@ msgid "" msgstr "" #: libraries/config/messages.inc.php:816 -#, fuzzy #| msgid "Use Tables" msgid "Users table" -msgstr "Usar as táboas" +msgstr "Táboa de usuarios" #: libraries/config/messages.inc.php:818 msgid "" @@ -7650,13 +7631,11 @@ msgid "" msgstr "" #: libraries/config/messages.inc.php:822 -#, fuzzy #| msgid "Use Host Table" msgid "User groups table" -msgstr "Empregar a táboa Host" +msgstr "Táboa de grupos de usuarios" #: libraries/config/messages.inc.php:824 -#, fuzzy #| msgid "" #| "Leave blank for no user preferences storage in database, suggested: " #| "[kbd]pma__userconfig[/kbd]" @@ -7665,7 +7644,7 @@ msgid "" "suggested: [kbd]pma__navigationhiding[/kbd]." msgstr "" "Déixeo en branco se non quere almacenar as preferencias na base de datos; " -"suxerido: [kbd]pma__userconfig[/kbd]" +"suxerido: [kbd]pma__userconfig[/kbd]." #: libraries/config/messages.inc.php:827 msgid "Hidden navigation items table" @@ -7688,19 +7667,16 @@ msgid "Verbose name of this server" msgstr "Nome longo deste servidor" #: libraries/config/messages.inc.php:836 -#, fuzzy #| msgid "Whether a user should be displayed a \"show all (rows)\" button" msgid "Whether a user should be displayed a \"show all (rows)\" button." msgstr "" -"Se se lle desexa mostrar un botón \"mostrar todos (os rexistros)\" ao " -"usuario" +"Se se lle desexa mostrar un botón «mostrar todas (as filas)» ao usuario." #: libraries/config/messages.inc.php:838 msgid "Allow to display all the rows" msgstr "Permitir que se mostren todas as fileiras" #: libraries/config/messages.inc.php:840 -#, fuzzy #| msgid "" #| "Please note that enabling this has no effect with [kbd]config[/kbd] " #| "authentication mode because the password is hard coded in the " @@ -7714,7 +7690,7 @@ msgstr "" "Lembre que activar isto non ten efecto ningún co modo de autenticación " "mediante [kbd]config[/kbd] porque o contrasinal está escrito no ficheiro de " "configuración; isto non limita a capacidade de executar a mesma orde " -"directamente" +"directamente." #: libraries/config/messages.inc.php:844 msgid "Show password change form" @@ -7725,60 +7701,53 @@ msgid "Show create database form" msgstr "Mostrar o formulario para crear bases de datos" #: libraries/config/messages.inc.php:847 -#, fuzzy #| msgid "" #| "Show or hide a column displaying the Creation timestamp for all tables" msgid "Show or hide a column displaying the comments for all tables." msgstr "" "Mostrar ou agochar unha columna que mostre a marca temporal da creación de " -"todas as táboas" +"todas as táboas." #: libraries/config/messages.inc.php:849 -#, fuzzy #| msgid "Table comments" msgid "Show table comments" -msgstr "Comentarios da táboa" +msgstr "Mostrar os comentarios de táboa" #: libraries/config/messages.inc.php:851 -#, fuzzy #| msgid "" #| "Show or hide a column displaying the Creation timestamp for all tables" msgid "Show or hide a column displaying the Creation timestamp for all tables." msgstr "" "Mostrar ou agochar unha columna que mostre a marca temporal da creación de " -"todas as táboas" +"todas as táboas." #: libraries/config/messages.inc.php:853 -#, fuzzy #| msgid "Show Creation timestamp" msgid "Show creation timestamp" msgstr "Mostrar marca temporal de creación" #: libraries/config/messages.inc.php:855 -#, fuzzy #| msgid "" #| "Show or hide a column displaying the Last update timestamp for all tables" msgid "" "Show or hide a column displaying the Last update timestamp for all tables." msgstr "" "Mostrar ou agochar unha columna que mostre a marca temporal da última " -"actualización de todas as táboas" +"actualización de todas as táboas." #: libraries/config/messages.inc.php:857 -#, fuzzy #| msgid "Show Last update timestamp" msgid "Show last update timestamp" msgstr "Mostrar a última actualización da marca temporal" #: libraries/config/messages.inc.php:859 -#, fuzzy #| msgid "" #| "Show or hide a column displaying the Last check timestamp for all tables" msgid "" "Show or hide a column displaying the Last check timestamp for all tables." msgstr "" "Mostrar ou agochar unha columna que mostre a marca temporal da última " -"comprobación de todas as táboas" +"comprobación de todas as táboas." #: libraries/config/messages.inc.php:861 #, fuzzy @@ -7787,7 +7756,6 @@ msgid "Show last check timestamp" msgstr "Mostrar a última revisión da marca temporal" #: libraries/config/messages.inc.php:863 -#, fuzzy #| msgid "" #| "Defines whether or not type fields should be initially displayed in edit/" #| "insert mode" @@ -7795,35 +7763,32 @@ msgid "" "Defines whether or not type fields should be initially displayed in edit/" "insert mode." msgstr "" -"Define se os campos tipo deben ser mostrados inicialmente no modo editar/" -"inserir" +"Define se os campos tipo deben ser mostrados inicialmente no modo " +"editar/inserir." #: libraries/config/messages.inc.php:866 msgid "Show field types" msgstr "Mostrar os tipos de campo" #: libraries/config/messages.inc.php:868 -#, fuzzy #| msgid "Display the function fields in edit/insert mode" msgid "Display the function fields in edit/insert mode." -msgstr "Mostrar os campos de función no modo editar/inserir" +msgstr "Mostrar os campos de función no modo editar/inserir." #: libraries/config/messages.inc.php:870 msgid "Show function fields" msgstr "Mostrar os campos de función" #: libraries/config/messages.inc.php:871 -#, fuzzy #| msgid "Whether to show hint or not" msgid "Whether to show hint or not." -msgstr "Mostrar axudas ou non" +msgstr "Mostrar axudas ou non." #: libraries/config/messages.inc.php:872 msgid "Show hint" msgstr "Mostrar consellos" #: libraries/config/messages.inc.php:874 -#, fuzzy #| msgid "" #| "Shows link to [a@http://php.net/manual/function.phpinfo.php]phpinfo()[/a] " #| "output" @@ -7831,8 +7796,8 @@ msgid "" "Shows link to [a@http://php.net/manual/function.phpinfo.php]phpinfo()[/a] " "output." msgstr "" -"Mostra unha ligazón á saída de [a@http://php.net/manual/function.phpinfo." -"php]phpinfo()[/a]" +"Mostra unha ligazón á saída de " +"[a@http://php.net/manual/function.phpinfo.php]phpinfo()[/a]." #: libraries/config/messages.inc.php:877 msgid "Show phpinfo() link" @@ -7843,52 +7808,48 @@ msgid "Show detailed MySQL server information" msgstr "Mostrar información detallada do servidor de MySQL" #: libraries/config/messages.inc.php:880 -#, fuzzy #| msgid "" #| "Defines whether SQL queries generated by phpMyAdmin should be displayed" msgid "" "Defines whether SQL queries generated by phpMyAdmin should be displayed." -msgstr "Define se se deben mostrar as consultas de SQL xeradas polo phpMyAdmin" +msgstr "Indica se se deben mostrar as consultas de SQL xeradas polo phpMyAdmin." #: libraries/config/messages.inc.php:882 msgid "Show SQL queries" msgstr "Mostrar as consultas de SQL" #: libraries/config/messages.inc.php:884 -#, fuzzy #| msgid "" #| "Defines whether the query box should stay on-screen after its submission" msgid "" "Defines whether the query box should stay on-screen after its submission." msgstr "" -"Define se a caixa de consultas debe permanecer en pantalla despois da súa " -"execución" +"Indica se a caixa de consultas debe permanecer en pantalla despois da súa " +"execución." #: libraries/config/messages.inc.php:886 libraries/sql_query_form.lib.php:351 msgid "Retain query box" msgstr "Reter a caixa de consultas" #: libraries/config/messages.inc.php:888 -#, fuzzy #| msgid "Allow to display database and table statistics (eg. space usage)" msgid "Allow to display database and table statistics (eg. space usage)." msgstr "" -"Permitir que se mostren as estatísticas das bases de datos e das táboas (p." -"ex. o uso do espazo)" +"Permitir que se mostren as estatísticas das bases de datos e das táboas (" +"p.ex. o uso do espazo)." #: libraries/config/messages.inc.php:890 msgid "Show statistics" msgstr "Mostrar as estatísticas" #: libraries/config/messages.inc.php:892 -#, fuzzy #| msgid "" #| "Mark used tables and make it possible to show databases with locked tables" msgid "" "Mark used tables and make it possible to show databases with locked tables." msgstr "" "Marcar as táboas empregadas e permitir que se mostren as bases de datos con " -"táboas bloqueadas" +"táboas bloqueadas." #: libraries/config/messages.inc.php:894 msgid "Skip locked tables" @@ -7961,32 +7922,28 @@ msgid "Textarea rows" msgstr "Fileiras da área de texto" #: libraries/config/messages.inc.php:923 -#, fuzzy #| msgid "Title of browser window when a database is selected" msgid "Title of browser window when a database is selected." -msgstr "Título da xanela do navegador cando a base de datos estea seleccionada" +msgstr "Título da xanela do navegador cando a base de datos estea seleccionada." #: libraries/config/messages.inc.php:927 -#, fuzzy #| msgid "Title of browser window when nothing is selected" msgid "Title of browser window when nothing is selected." -msgstr "Título da xanela do navegador cando non haxa nada escollido" +msgstr "Título da xanela do navegador cando non haxa nada seleccionado." #: libraries/config/messages.inc.php:929 msgid "Default title" msgstr "Título por omisión" #: libraries/config/messages.inc.php:931 -#, fuzzy #| msgid "Title of browser window when a server is selected" msgid "Title of browser window when a server is selected." -msgstr "Título da xanela do navegador cando un servidor estea seleccionado" +msgstr "Título da xanela do navegador cando un servidor estea seleccionado." #: libraries/config/messages.inc.php:934 -#, fuzzy #| msgid "Title of browser window when a table is selected" msgid "Title of browser window when a table is selected." -msgstr "Título da xanela do navegador cando unha táboa estea seleccionada" +msgstr "Título da xanela do navegador cando unha táboa estea seleccionada." #: libraries/config/messages.inc.php:937 #, fuzzy @@ -8011,28 +7968,25 @@ msgid "List of trusted proxies for IP allow/deny" msgstr "Lista de proxies de confianza para permiso/denegación de IP" #: libraries/config/messages.inc.php:944 -#, fuzzy #| msgid "Directory on server where you can upload files for import" msgid "Directory on server where you can upload files for import." msgstr "" -"Directorio do servidor ao que se poden enviar os ficheiros que importar" +"Directorio do servidor ao que se poden enviar os ficheiros que importar." #: libraries/config/messages.inc.php:946 msgid "Upload directory" msgstr "Directorio de envíos" #: libraries/config/messages.inc.php:947 -#, fuzzy #| msgid "Allow for searching inside the entire database" msgid "Allow for searching inside the entire database." -msgstr "Permitir buscar na base de datos completa" +msgstr "Permitir buscar na base de datos completa." #: libraries/config/messages.inc.php:948 msgid "Use database search" msgstr "Empregar buscas na base de datos" #: libraries/config/messages.inc.php:950 -#, fuzzy #| msgid "" #| "When disabled, users cannot set any of the options below, regardless of " #| "the checkbox on the right" @@ -8041,7 +7995,7 @@ msgid "" "checkbox on the right." msgstr "" "Se está desactivado os usuarios non poden establecer ningunha das opcións " -"que hai debaixo, independentemente da caixa da dereita" +"que hai debaixo, independentemente da caixa da dereita." #: libraries/config/messages.inc.php:953 msgid "Enable the Developer tab in settings" @@ -8052,11 +8006,10 @@ msgid "Check for latest version" msgstr "Comprobar cal é a última versión" #: libraries/config/messages.inc.php:956 -#, fuzzy #| msgid "Enables check for latest version on main phpMyAdmin page" msgid "Enables check for latest version on main phpMyAdmin page." msgstr "" -"Activar a comprobación da última versión na páxina principal do phpMyAdmin" +"Activar a comprobación da última versión na páxina principal do phpMyAdmin." #: libraries/config/messages.inc.php:958 setup/lib/index.lib.php:118 #: setup/lib/index.lib.php:141 setup/lib/index.lib.php:154 @@ -8066,7 +8019,6 @@ msgid "Version check" msgstr "Comprobación da versión" #: libraries/config/messages.inc.php:960 -#, fuzzy #| msgid "" #| "The url of the proxy to be used when retrieving the information about the " #| "latest version of phpMyAdmin. You need this if the server where " @@ -8081,7 +8033,7 @@ msgstr "" "O URL do proxy que se desexa empregar para obter a información sobre a " "versión máis recente do phpMyAdmin. É necesario se o servidor no que está " "instalado o phpMyAdmin non ten acceso á Internet. O formato é: " -"«nome_do_servidor:número_do_porto»" +"«nome_do_servidor:número_do_porto»." #: libraries/config/messages.inc.php:965 msgid "Proxy url" @@ -8099,23 +8051,20 @@ msgstr "" "autenticación." #: libraries/config/messages.inc.php:972 -#, fuzzy #| msgid "Username" msgid "Proxy username" -msgstr "Nome de usuario" +msgstr "Nome de usuario do proxy" #: libraries/config/messages.inc.php:973 msgid "The password for authenticating with the proxy." msgstr "O contrasinal para identificarse diante do proxy." #: libraries/config/messages.inc.php:974 -#, fuzzy #| msgid "Password" msgid "Proxy password" -msgstr "Contrasinal" +msgstr "Contrasinal do proxy" #: libraries/config/messages.inc.php:977 -#, fuzzy #| msgid "" #| "Enable [a@http://en.wikipedia.org/wiki/ZIP_(file_format)]ZIP[/a] " #| "compression for import and export operations" @@ -8124,29 +8073,27 @@ msgid "" "for import and export operations." msgstr "" "Activar a compresión [a@http://gl.wikipedia.org/wiki/ZIP_(formato de " -"ficheiro)]ZIP[/a] nas operacións de importación e exportación" +"ficheiro)]ZIP[/a] nas operacións de importación e exportación." #: libraries/config/messages.inc.php:980 msgid "ZIP" msgstr "ZIP" #: libraries/config/messages.inc.php:982 -#, fuzzy #| msgid "Enter your public key for your domain reCaptcha service" msgid "Enter your public key for your domain reCaptcha service." msgstr "" -"Introduza a súa chave pública para o servizo de reCaptcha do seu dominio" +"Introduza a súa chave pública para o servizo de reCaptcha do seu dominio." #: libraries/config/messages.inc.php:984 msgid "Public key for reCaptcha" msgstr "Chave pública do reCaptcha" #: libraries/config/messages.inc.php:986 -#, fuzzy #| msgid "Enter your private key for your domain reCaptcha service" msgid "Enter your private key for your domain reCaptcha service." msgstr "" -"Introduza a súa chave privada para o servizo de reCaptcha do seu dominio" +"Introduza a súa chave privada para o servizo de reCaptcha do seu dominio." #: libraries/config/messages.inc.php:988 msgid "Private key for reCaptcha" @@ -8157,10 +8104,9 @@ msgid "Choose the default action when sending error reports." msgstr "" #: libraries/config/messages.inc.php:993 -#, fuzzy #| msgid "Server port" msgid "Send error reports" -msgstr "Porto do servidor" +msgstr "Enviar informes de erro" #: libraries/config/messages.inc.php:996 msgid "" @@ -8187,10 +8133,11 @@ msgid "Enable Zero Configuration mode" msgstr "Configuración do servidor" #: libraries/config/page_settings.class.php:140 -#, fuzzy #| msgid "Cannot save settings, submitted form contains errors" msgid "Cannot save settings, submitted configuration form contains errors!" -msgstr "Configuración non gardada; o formulario enviado contén erros" +msgstr "" +"Non é posíbel gardar a configuración; o formulario de configuración enviado " +"contén erros!" #: libraries/config/setup.forms.php:40 msgid "Config authentication" From ff21ad8e0e0fdeca57c27aead243c4a9571db6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jan 2016 14:49:40 +0100 Subject: [PATCH 06/20] Remove unused use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/common.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/common.inc.php b/libraries/common.inc.php index 15fb535e01..fa4785387a 100644 --- a/libraries/common.inc.php +++ b/libraries/common.inc.php @@ -36,7 +36,6 @@ 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; 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 07/20] 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 08/20] 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 09/20] 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 10/20] 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 11/20] 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 12/20] 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 .= '