jenkins-bot has submitted this change and it was merged.

Change subject: New Special:ContentTranslationStats using central database
......................................................................


New Special:ContentTranslationStats using central database

Bug: T87709
Change-Id: I6f6d026fcbc0286731201c93672de80a343ff09f
---
M Resources.php
M i18n/en.json
M i18n/qqq.json
M includes/Translation.php
A modules/stats/ext.cx.stats.js
A modules/stats/styles/ext.cx.stats.less
M specials/SpecialContentTranslationStats.php
7 files changed, 194 insertions(+), 57 deletions(-)

Approvals:
  Amire80: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/Resources.php b/Resources.php
index 2b4f47b..9f88842 100644
--- a/Resources.php
+++ b/Resources.php
@@ -610,6 +610,22 @@
        ),
 ) + $resourcePaths;
 
+$wgResourceModules['ext.cx.stats'] = array(
+       'scripts' => array(
+               'stats/ext.cx.stats.js',
+       ),
+       'styles' => array(
+               'stats/styles/ext.cx.stats.less',
+       ),
+       'messages' => array(
+               'cx-stats-table-source-target',
+               'cx-stats-table-source-total',
+               'cx-stats-table-target-total',
+               'cx-stats-published-translations-title',
+               'cx-stats-draft-translations-title',
+       )
+) + $resourcePaths;
+
 $wgHooks['ResourceLoaderTestModules'][] = function ( array &$modules ) {
        $resourcePaths = array(
                'localBasePath' => __DIR__,
diff --git a/i18n/en.json b/i18n/en.json
index 5754f24..0d2adbf 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -68,12 +68,8 @@
        "cx-tools-mt-dont-use": "Don't use machine translation",
        "cx-tools-categories-count-message": "{{PLURAL:$1|$1 category|$1 
categories|0=No categories}}",
        "cx-stats-title": "Content translation statistics",
-       "cx-stats-page-title": "Page",
-       "cx-stats-from": "Source language",
-       "cx-stats-to": "Target language",
-       "cx-stats-pages-title": "Translated pages",
        "cx-stats-unknown": "unknown",
-       "cx-stats-summary": "$1/$2 {{PLURAL:$1|page|pages}} ($3%) in the main 
namespace.",
+       "cx-stats-summary": "$1/$2 {{PLURAL:$1|page|pages}} ($3%) in the main 
namespace in this wiki.",
        "cx-tools-reference-title": "Reference",
        "cx-tools-reference-remove": "Remove reference",
        "cx-tools-link-instruction-shortcut": "Shift + click any link to open",
@@ -139,5 +135,10 @@
        "cx-translation-already-in-progress": "This is an ongoing translation 
by $1.",
        "cx-translation-already-in-progress-collaborate": "Please make sure you 
coordinate with the user who translated the current translation.",
        "cx-publishing-dialog-publish-draft-button": "Publish as draft",
-       "cx-feedback-link": "Provide feedback"
+       "cx-feedback-link": "Provide feedback",
+       "cx-stats-table-source-target": "Source↓ / Target→",
+       "cx-stats-table-source-total": "Total (Source)",
+       "cx-stats-table-target-total": "Total (Target)",
+       "cx-stats-published-translations-title": "Published tranlslations",
+       "cx-stats-draft-translations-title": "In progress tranlslations"
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 60d7214..097c973 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -144,5 +144,10 @@
        "cx-translation-already-in-progress": "Message shown when a second 
translator tries to translate the same page between same languages. 
\n\nParameters:\n* $1 - User name of first translator",
        "cx-translation-already-in-progress-collaborate": "A message to 
collaborate with other translator. Shown when there is translation conflict.",
        "cx-publishing-dialog-publish-draft-button": "Button label for 
publishing options dialog. Used if extension is not configured to publish to 
User namespace.",
-       "cx-feedback-link": "Link text for the link to give feedback"
+       "cx-feedback-link": "Link text for the link to give feedback",
+       "cx-stats-table-source-target": "Text in the first cell of stats table. 
Indicates what is the table header and table first column.",
+       "cx-stats-table-source-total": "Header text to indicate total 
translations from source language",
+       "cx-stats-table-target-total": "Header text to indicate total 
translations to target language",
+       "cx-stats-published-translations-title": "Section title for published 
translation stats",
+       "cx-stats-draft-translations-title": "Section title for translations in 
draft(in progress) state stats"
 }
diff --git a/includes/Translation.php b/includes/Translation.php
index 2962f36..b7f5e14 100644
--- a/includes/Translation.php
+++ b/includes/Translation.php
@@ -91,6 +91,7 @@
                        ),
                        __METHOD__
                );
+
                $result = array();
                foreach ( $rows as $row ) {
                        $result[] = array(
diff --git a/modules/stats/ext.cx.stats.js b/modules/stats/ext.cx.stats.js
new file mode 100644
index 0000000..6929d32
--- /dev/null
+++ b/modules/stats/ext.cx.stats.js
@@ -0,0 +1,129 @@
+/**
+ * ContentTranslation Stats
+ *
+ * @file
+ * @ingroup Extensions
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+( function ( $, mw ) {
+       'use strict';
+
+       var max = 0;
+
+       function getCXStats() {
+               var api = new mw.Api();
+               return api.get( {
+                       action: 'query',
+                       list: 'contenttranslationstats'
+               } );
+       }
+
+       function findLanguagePair( records, source, target, status ) {
+               return $.grep( records, function ( record ) {
+                       return record.sourceLanguage === source &&
+                               record.targetLanguage === target &&
+                               record.status === status;
+               } );
+       }
+
+       function jsonToTable( records, status ) {
+               var i, j, record,
+                       table = [],
+                       languages = [];
+
+               for ( i = 0; i < records.length; i++ ) {
+                       languages.push( records[ i ].sourceLanguage );
+                       languages.push( records[ i ].targetLanguage );
+               }
+               // remove duplicates
+               languages = $.grep( languages, function ( v, k ) {
+                       return $.inArray( v, languages ) === k;
+               } );
+               languages.sort();
+               for ( i = 0; i <= languages.length; i++ ) {
+                       for ( j = 0; j <= languages.length; j++ ) {
+                               table[ i ] = table[ i ] || [];
+                               if ( i === 0 && j === 0 ) {
+                                       table[ 0 ][ 0 ] = mw.msg( 
'cx-stats-table-source-target' );
+                                       continue;
+                               }
+                               if ( i === 0 ) {
+                                       table[ 0 ][ j ] = languages[ j - 1 ];
+                                       continue;
+                               }
+                               if ( j === 0 ) {
+                                       table[ i ][ 0 ] = languages[ i - 1 ];
+                                       continue;
+                               }
+                               record = findLanguagePair( records, languages[ 
i - 1 ], languages[ j - 1 ], status );
+                               table[ i ][ j ] = record[ 0 ] && record[ 0 
].count || '';
+                               // Keep track of max value of translation in 
any language pair.
+                               // Required for coloring
+                               max = table[ i ][ j ] > max ? table[ i ][ j ] : 
max;
+                               // Total(to)
+                               table[ i ][ languages.length + 1 ] = table[ i 
][ languages.length + 1 ] || 0;
+                               table[ i ][ languages.length + 1 ] += parseInt( 
table[ i ][ j ] ) || 0;
+                               // Total(from)
+                               table[ languages.length + 1 ] = table[ 
languages.length + 1 ] || [];
+                               table[ languages.length + 1 ][ j ] = table[ 
languages.length + 1 ][ j ] || 0;
+                               table[ languages.length + 1 ][ j ] += parseInt( 
table[ i ][ j ] ) || 0;
+                       }
+                       // Total translations
+                       table[ languages.length + 1 ] = table[ languages.length 
+ 1 ] || [];
+                       table[ languages.length + 1 ][ languages.length + 1 ] =
+                               table[ languages.length + 1 ][ languages.length 
+ 1 ] || 0;
+                       table[ languages.length + 1 ][ languages.length + 1 ] 
+= table[ i ][ languages.length + 1 ];
+               }
+               table[ 0 ][ languages.length + 1 ] = mw.msg( 
'cx-stats-table-source-total' );
+               table[ languages.length + 1 ][ 0 ] = mw.msg( 
'cx-stats-table-target-total' );
+
+               return table;
+       }
+
+       function prepareStatsTable( records, status ) {
+               var i, j, $table, $thead, $tbody, $headerRow,
+                       table, $row, division, value, $td;
+
+               table = jsonToTable( records, status );
+
+               // Categorize the translations to 5 sets for coloring
+               division = Math.ceil( max / 5 );
+               $table = $( '<table>' )
+                       .addClass( 'cx-stats' );
+
+               $thead = $( '<thead>' );
+               $tbody = $( '<tbody>' );
+               $thead.append( $headerRow );
+
+               for ( i = 0; i < table.length; i++ ) {
+                       $row = $( '<tr>' );
+                       for ( j = 0; j < table.length; j++ ) {
+                               value = table[ i ][ j ];
+                               $td = $( '<td>' ).text( value ? 
mw.language.convertNumber( value ) : '' );
+                               if ( i > 0 && j > 0 && i < table.length - 1 && 
j < table.length - 1 && value > 0 ) {
+                                       $td.addClass( 'cx-stat-color-' + 
parseInt( value / division ) );
+                               }
+                               $row.append( $td );
+                       }
+                       if ( i === 0 ) {
+                               $thead.append( $row );
+                       } else {
+                               $tbody.append( $row );
+                       }
+               }
+               $table.append( $thead, $tbody );
+               return $table;
+       }
+
+       $( function () {
+               getCXStats().then( function ( data ) {
+                       var $container = $( '#bodyContent' );
+                       $container.append(
+                               $( '<h2>' ).text( mw.msg( 
'cx-stats-published-translations-title' ) ),
+                               prepareStatsTable( 
data.query.contenttranslationstats, 'published' ),
+                               $( '<h2>' ).text( mw.msg( 
'cx-stats-draft-translations-title' ) ),
+                               prepareStatsTable( 
data.query.contenttranslationstats, 'draft' ) );
+               } );
+       } );
+}( jQuery, mediaWiki ) );
diff --git a/modules/stats/styles/ext.cx.stats.less 
b/modules/stats/styles/ext.cx.stats.less
new file mode 100644
index 0000000..17f8f71
--- /dev/null
+++ b/modules/stats/styles/ext.cx.stats.less
@@ -0,0 +1,31 @@
+@import "../../base/styles/grid/agora-grid";
+
+.cx-stats {
+       border-collapse: collapse;
+       border: 1px solid black;
+       tr, td {
+               padding: 5px;
+               border: 1px solid #ddd;
+               text-align: center;
+       }
+       tr td:first-child,
+       thead {
+               font-weight: 700;
+               background-color: #eee;
+       }
+       .cx-stat-color-0 {
+               background-color: #E8F5E9;
+       }
+       .cx-stat-color-1 {
+               background-color: #C8E6C9;
+       }
+       .cx-stat-color-2 {
+               background-color: #A5D6A7;
+       }
+       .cx-stat-color-3 {
+               background-color: #81C784;
+       }
+       .cx-stat-color-4 {
+               background-color: #66BB6A;
+       }
+}
\ No newline at end of file
diff --git a/specials/SpecialContentTranslationStats.php 
b/specials/SpecialContentTranslationStats.php
index b79eeed..fad3d8b 100644
--- a/specials/SpecialContentTranslationStats.php
+++ b/specials/SpecialContentTranslationStats.php
@@ -36,34 +36,13 @@
                $this->setHeaders();
                $this->outputHeader();
 
-               $out->wrapWikiMsg( '== $1 ==',  array( 'cx-stats-pages-title' ) 
);
-
                // @TODO better to return title => stats iterator
                $stats = ContentTranslation\Stats::getStats();
-               $out->addHtml( $this->getPagesTable( $stats ) );
+               $out->addHtml( $this->getPagesSummary( $stats ) );
+               $out->addModules( 'ext.cx.stats' );
        }
 
-       private function getPagesTable( $pages ) {
-               $headingMsgs = array(
-                       'cx-stats-page-title',
-                       'cx-stats-from',
-                       'cx-stats-to',
-               );
-
-               // @TODO want to use html template here
-               $headingRow = '';
-               foreach ( $headingMsgs as $headingMsg ) {
-                       $headingRow .= Html::element( 'th',
-                               array(),
-                               $this->msg( $headingMsg )->text()
-                       );
-               }
-
-               $rows = array( Html::rawElement( 'tr',
-                       array(),
-                       $headingRow
-               ) );
-
+       private function getPagesSummary( $pages ) {
                $total = $main = 0;
 
                foreach ( $pages as $row ) {
@@ -73,32 +52,7 @@
                        if ( $title->inNamespace( NS_MAIN ) ) {
                                $main++;
                        }
-
-                       $titleCell = Html::rawElement( 'td', array(), 
Linker::link( $title ) );
-
-                       $languages = FormatJson::decode( $row->ct_params );
-                       if ( $languages === null ) {
-                               $from = $to = $this->msg( 'cx-stats-unknown' 
)->text();
-                       } else {
-                               $from = $languages->from;
-                               $to = $languages->to;
-                       }
-
-                       $fromCell = Html::element( 'td', array(), $from );
-                       $toCell = Html::element( 'td', array(), $to );
-
-                       $rows[] = Html::rawElement( 'tr',
-                               array(),
-                               $titleCell . $fromCell . $toCell
-                       );
                }
-
-               $table = Html::rawElement( 'table',
-                       array(
-                               'class' => 'wikitable sortable',
-                       ),
-                       implode( "\n", $rows )
-               );
 
                if ( $total > 0 ) {
                        $percentage = round( $main / $total * 100 );
@@ -110,6 +64,6 @@
                        ->numParams( $main, $total, $percentage )
                        ->parse();
 
-               return $table . $summary;
+               return $summary;
        }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/188042
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I6f6d026fcbc0286731201c93672de80a343ff09f
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <[email protected]>
Gerrit-Reviewer: Amire80 <[email protected]>
Gerrit-Reviewer: Nikerabbit <[email protected]>
Gerrit-Reviewer: Santhosh <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: Tuxilina <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to