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