jenkins-bot has submitted this change and it was merged. Change subject: Stats: Deletion count graph ......................................................................
Stats: Deletion count graph We show it only for local wiki language. Showing cumulative deletion stats for all wikis is not possible as of now. Bug: T90538 Change-Id: I8581d07c00dac6228ba5cc8b465acf431a1163e3 --- M api/ApiQueryContentTranslationLanguageTrend.php M extension.json M i18n/en.json M i18n/qqq.json M includes/Translation.php M modules/stats/ext.cx.stats.js 6 files changed, 207 insertions(+), 119 deletions(-) Approvals: Amire80: Looks good to me, approved jenkins-bot: Verified diff --git a/api/ApiQueryContentTranslationLanguageTrend.php b/api/ApiQueryContentTranslationLanguageTrend.php index 8bbf549..a790c47 100644 --- a/api/ApiQueryContentTranslationLanguageTrend.php +++ b/api/ApiQueryContentTranslationLanguageTrend.php @@ -31,15 +31,80 @@ $target = $params['target']; } $interval = $params['interval']; - $result->addValue( - array( 'query' ), - 'contenttranslationlangtrend', - array( - 'translations' => - Translation::getPublishTrend( $source, $target, $interval ), - 'drafts' => Translation::getDraftTrend( $source, $target, $interval ) - ) + + $data = array( + 'translations' => Translation::getPublishTrend( $source, $target, $interval ), + 'drafts' => Translation::getDraftTrend( $source, $target, $interval ), ); + + if ( $target !== null ) { + // We can give deletion rates for only local wiki. We cannot give + // deletion stats for all wikis. + $data['deletions'] = Translation::getDeletionTrend( $interval ); + } + + $out = $this->addMissingDates( $data, $interval ); + $result->addValue( array( 'query' ), 'contenttranslationlangtrend', $out ); + } + + public function addMissingDates( $data, $interval ) { + $min = PHP_INT_MAX; + $max = 0; + foreach ( $data as $column ) { + foreach ( array_keys( $column ) as $date ) { + $min = min( $min, strtotime( $date ) ); + $max = max( $max, strtotime( $date ) ); + } + } + + $counts = array(); + foreach ( array_keys( $data ) as $type ) { + $counts[$type] = 0; + } + + $steps = $this->getSteps( $min, $max, $interval ); + + $out = array(); + foreach ( $steps as $step ) { + foreach ( $data as $type => $column ) { + if ( isset( $column[$step] ) ) { + $column[$step]['date'] = $step; + $out[$type][] = $column[$step]; + $counts[$type] = $column[$step]['count']; + } else { + $out[$type][] = array( + 'count' => $counts[$type], + 'delta' => 0, + 'date' => $step, + ); + } + } + } + + return $out; + } + + protected function getSteps( $min, $max, $interval ) { + $steps = array(); + while ( true ) { + // Lets not overflow + $min = min( $min, $max ); + if ( $interval === 'month' ) { + $uniq = $label = date( 'Y-m', $min ); + } else { + $uniq = date( 'Y-W', $min ); + $label = date( 'Y-m-d', $min ); + } + + $steps[$uniq] = $label; + + if ( $min === $max ) { + break; + } + $min += 3600 * 24; + } + + return $steps; } public function getAllowedParams() { diff --git a/extension.json b/extension.json index ac3afe5..5ed4bb8 100644 --- a/extension.json +++ b/extension.json @@ -853,6 +853,7 @@ "cx-stats-draft-translations-title", "cx-stats-published-translators-title", "cx-trend-all-translations", + "cx-trend-deletions", "cx-trend-translations-to", "cx-stats-try-contenttranslation", "cx-stats-published-target-source", diff --git a/i18n/en.json b/i18n/en.json index d8948db..bf13237 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -155,6 +155,7 @@ "cx-campaign-contributionsmenu-might-be-available": "$1 might be already available in other languages", "cx-campaign-contributionsmenu-myuploads": "Uploaded media", "cx-trend-all-translations": "All translations", + "cx-trend-deletions": "Deleted translations", "cx-trend-translations-to": "Translations to $1", "cx-stats-try-contenttranslation": "Content Translation is a tool to create new pages by translating from other languages. [$1 Try Content Translation]", "cx-stats-published-target-source": "Translations to", diff --git a/i18n/qqq.json b/i18n/qqq.json index a36fe83..45c4b4b 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -159,8 +159,9 @@ "cx-campaign-contributionsmenu-translate-instead": "Menu item for menu shown while hovering the contributions link in personal toolbar while a new page is being created. Points to the Content Translation dashboard\n{{Identical|Translation}}", "cx-campaign-contributionsmenu-might-be-available": "Appears under {{msg-mw|cx-campaign-contributionsmenu-translate-instead}}. $1 is the title of the article being created, in quotation marks.", "cx-campaign-contributionsmenu-myuploads": "Menu item for menu shown while hovering the contributions link in personal toolbar. Points to the Special:MyUploads in commons", - "cx-trend-all-translations": "Label shown in the legend section Content translation trends(graph visualization)", - "cx-trend-translations-to": "Label shown in the legend section Content translation trends graph visualization.\n* $1 - language name", + "cx-trend-all-translations": "Label shown in the legend section of [[Special:CXStats]] trends graph visualization", + "cx-trend-deletions": "Label shown in the legend section of [[Special:CXStats]] trends graph visualization", + "cx-trend-translations-to": "Label shown in the legend section of [[Special:CXStats]] trends graph visualization.\n* $1 - language name", "cx-stats-try-contenttranslation": "A message shown in [[Special:CXStats]] for users not enabled Content Translation . \n$1 - link to enable Content Translation beta feature and go to Content Translation dashboard", "cx-stats-published-target-source": "A message shown in [[Special:CXStats]]", "cx-stats-published-source-target": "A message shown in [[Special:CXStats]]", diff --git a/includes/Translation.php b/includes/Translation.php index 0f54508..3a7ba17 100644 --- a/includes/Translation.php +++ b/includes/Translation.php @@ -278,12 +278,8 @@ $result = array(); foreach ( $rows as $row ) { $count = (int)$row->translatons_count; - $result[] = array( - 'date' => $interval === 'week' ? - // Week end date - date( 'Y-m-d', strtotime( $row->date . ' + ' . - ( 6 - date( 'w', strtotime( $row->date ) ) ) . ' days' ) ) : - date( 'Y-m', strtotime( $row->date ) ), + $time = self::getResultTime( $row->date, $interval ); + $result[$time] = array( 'count' => $count, 'delta' => $count - $prev, ); @@ -292,6 +288,68 @@ } return $result; + } + + /** + * Get time-wise cumulative number of deletions for given + * language pairs, with given interval. + */ + public static function getDeletionTrend( $interval ) { + $dbr = wfGetDB( DB_SLAVE ); + + $conditions = array( + 'ct_tag' => 'contenttranslation', + 'ar_rev_id = ct_rev_id' + ); + $groupBy = null; + + if ( $interval === 'week' ) { + $groupBy = array( + 'GROUP BY' => array( + 'YEARWEEK(ar_timestamp)', + ), + ); + } elseif ( $interval === 'month' ) { + $groupBy = array( + 'GROUP BY' => array( + 'YEAR(ar_timestamp), MONTH(ar_timestamp)', + ), + ); + } + + $rows = $dbr->select( + array( 'change_tag', 'archive' ), + array( 'ar_timestamp', 'count(ar_page_id) as count' ), + $conditions, + __METHOD__, + $groupBy + ); + + $prev = 0; + $count = 0; + $result = array(); + foreach ( $rows as $row ) { + $count += (int)$row->count; + $time = self::getResultTime( $row->ar_timestamp, $interval ); + $result[$time] = array( + 'count' => $count, + 'delta' => $count - $prev, + ); + $prev = $count; + } + + return $result; + } + + protected static function getResultTime( $timestamp, $interval ) { + $unix = wfTimestamp( TS_UNIX, $timestamp ); + if ( $interval === 'week' ) { + $n = 7 - date( 'w', $unix ); + $unix = strtotime( "+$n days", $unix ); + return date( 'Y-m-d', $unix ); + } else { + return date( 'Y-m', $unix ); + } } /** @@ -356,12 +414,8 @@ $result = array(); foreach ( $rows as $row ) { $count = (int)$row->translatons_count; - $result[] = array( - 'date' => $interval === 'week' ? - // Week end date - date( 'Y-m-d', strtotime( $row->date . ' + ' . - ( 6 - date( 'w', strtotime( $row->date ) ) ) . ' days' ) ) : - date( 'Y-m', strtotime( $row->date ) ), + $time = self::getResultTime( $row->date, $interval ); + $result[$time] = array( 'count' => $count, 'delta' => $count - $prev, ); diff --git a/modules/stats/ext.cx.stats.js b/modules/stats/ext.cx.stats.js index b6bb788..17ce811 100644 --- a/modules/stats/ext.cx.stats.js +++ b/modules/stats/ext.cx.stats.js @@ -65,12 +65,11 @@ this.getCXTrends( mw.config.get( 'wgContentLanguage' ) ) ).done( function ( totalTrend, languageTrend ) { self.totalTranslationTrend = totalTrend.translations; - self.languageTranslationTrend = languageTrend.translations; - self.languageTranslationTrend = mergeAndFill( self.totalTranslationTrend, self.languageTranslationTrend ); + self.totalDraftTrend = totalTrend.drafts; - self.totalDraftTrend = mergeAndFill( self.totalTranslationTrend, totalTrend.drafts ); - self.languageDraftTrend = mergeAndFill( self.languageTranslationTrend, languageTrend.drafts ); - self.languageDraftTrend = mergeAndFill( self.totalDraftTrend, self.languageDraftTrend ); + self.languageTranslationTrend = languageTrend.translations; + self.languageDraftTrend = languageTrend.drafts; + self.languageDeletionTrend = languageTrend.deletions; self.renderHighlights(); self.drawCumulativeGraph( 'count' ); self.drawLanguageCumulativeGraph( 'count' ); @@ -88,49 +87,41 @@ * Render the boxes at the top with the most interesting recent data. */ CXStats.prototype.renderHighlights = function () { - var weekTrend, weekLangTrend, totalTrendLength, langTrendLength, localLanguage, total, - lastWeekTotal, prevWeekTotal, lastWeekTranslations, prevWeekTranslations, - langTotal, lastWeekLangTotal, prevWeekLangTotal, - lastWeekLangTranslations, prevWeekLangTranslations, + var getTrend, info, infoLanguage, localLanguage, $total, $weeklyStats, weekLangTrendText, weekTrendText, weekTrendClass, $parenthesizedTrend, $trendInLanguage, fmt = mw.language.convertNumber; // Shortcut - if ( this.totalTranslationTrend.length < 4 ) { - // Trend calculation works only if we have enough data + getTrend = function( data ) { + var total, trend, thisWeek; + + if ( data.length < 3 ) { + return; + } + + thisWeek = data.length - 1; + + total = data[ thisWeek ].count; + trend = + ( data[ thisWeek - 1 ].delta - data[ thisWeek - 2 ].delta ) / + data[ thisWeek - 2 ].delta * 100; + trend = parseInt( trend ); + + return { + total: total, + trend: trend, + lastWeek: data[ thisWeek - 1 ].delta + }; + }; + + localLanguage = $.uls.data.getAutonym( mw.config.get( 'wgContentLanguage' ) ); + info = getTrend( this.totalTranslationTrend ); + infoLanguage = getTrend( this.languageTranslationTrend ); + + if ( !info || !infoLanguage ) { return; } - - weekTrend = 0; - weekLangTrend = 0; - totalTrendLength = this.totalTranslationTrend.length; - langTrendLength = this.languageTranslationTrend.length; - localLanguage = $.uls.data.getAutonym( mw.config.get( 'wgContentLanguage' ) ); - total = this.totalTranslationTrend[ totalTrendLength - 1 ].count; - - lastWeekTotal = this.totalTranslationTrend[ totalTrendLength - 2 ].count; - prevWeekTotal = this.totalTranslationTrend[ totalTrendLength - 3 ].count; - lastWeekTranslations = lastWeekTotal - prevWeekTotal; - prevWeekTranslations = prevWeekTotal - - this.totalTranslationTrend[ totalTrendLength - 4 ].count; - if ( prevWeekTranslations ) { - weekTrend = ( lastWeekTranslations - prevWeekTranslations ) / - prevWeekTranslations * 100; - } - weekTrend = parseInt( weekTrend ); - - langTotal = this.languageTranslationTrend[ langTrendLength - 1 ].count; - lastWeekLangTotal = this.languageTranslationTrend[ langTrendLength - 2 ].count; - prevWeekLangTotal = this.languageTranslationTrend[ langTrendLength - 3 ].count; - lastWeekLangTranslations = lastWeekLangTotal - prevWeekLangTotal; - prevWeekLangTranslations = prevWeekLangTotal - - this.languageTranslationTrend[ langTrendLength - 4 ].count; - if ( prevWeekLangTranslations ) { - weekLangTrend = ( lastWeekLangTranslations - prevWeekLangTranslations ) / - prevWeekLangTranslations * 100; - } - weekLangTrend = parseInt( weekLangTrend ); $total = $( '<div>' ) .addClass( 'cx-stats-box' ) @@ -140,24 +131,24 @@ .text( mw.msg( 'cx-stats-total-published' ) ), $( '<div>' ) .addClass( 'cx-stats-box__total' ) - .text( fmt( total ) ), + .text( fmt( info.total ) ), $( '<div>' ) .addClass( 'cx-stats-box__localtotal' ) .text( mw.msg( 'cx-stats-local-published-number', - fmt( langTotal ), + fmt( infoLanguage.total ), fmt( localLanguage ) ) ) ); - weekLangTrendText = mw.msg( 'percent', fmt( weekLangTrend ) ); - if ( weekLangTrend >= 0 ) { + weekLangTrendText = mw.msg( 'percent', fmt( infoLanguage.trend ) ); + if ( infoLanguage.trend >= 0 ) { // Add the plus sign to make clear that it's an increase weekLangTrendText = '+' + weekLangTrendText; } - weekTrendText = mw.msg( 'percent', fmt( weekTrend ) ); - if ( weekTrend >= 0 ) { + weekTrendText = mw.msg( 'percent', fmt( info.trend ) ); + if ( info.trend >= 0 ) { // Add the plus sign to make clear that it's an increase weekTrendText = '+' + weekTrendText; weekTrendClass = 'increase'; @@ -173,7 +164,7 @@ .addClass( 'cx-stats-box__localtotal' ) .text( mw.msg( 'cx-stats-local-published', - fmt( lastWeekLangTranslations ), + fmt( infoLanguage.lastWeek ), localLanguage, '$3' ) ); @@ -191,7 +182,7 @@ $( '<div>' ).append( $( '<span>' ) .addClass( 'cx-stats-box__total' ) - .text( fmt( lastWeekTranslations ) ), + .text( fmt( info.lastWeek ) ), // nbsp is needed for separation between the numbers. // Without it the numbers appear in the wrong order in RTL environments. $( '<span>' ) @@ -509,10 +500,32 @@ ctx = this.$languageCumulativeGraph[ 0 ].getContext( '2d' ); data = { - labels: $.map( this.totalTranslationTrend, function ( data ) { + labels: $.map( this.languageTranslationTrend, function ( data ) { return data.date; } ), datasets: [ + { + label: mw.msg( 'cx-stats-draft-translations-title' ), + strokeColor: '#777', + pointColor: '#777', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: '#777', + data: $.map( this.languageDraftTrend, function ( data ) { + return data[ type ]; + } ) + }, + { + label: mw.msg( 'cx-trend-deletions' ), + strokeColor: '#FF0000', + pointColor: '#FF0000', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: '#FF0000', + data: $.map( this.languageDeletionTrend, function ( data ) { + return data[ type ]; + } ) + }, { label: mw.message( 'cx-trend-translations-to', @@ -524,17 +537,6 @@ pointHighlightFill: '#fff', pointHighlightStroke: '#347BFF', data: $.map( this.languageTranslationTrend, function ( data ) { - return data[ type ]; - } ) - }, - { - label: mw.msg( 'cx-stats-draft-translations-title' ), - strokeColor: '#777', - pointColor: '#777', - pointStrokeColor: '#fff', - pointHighlightFill: '#fff', - pointHighlightStroke: '#777', - data: $.map( this.languageDraftTrend, function ( data ) { return data[ type ]; } ) } @@ -634,42 +636,6 @@ } // a must be equal to b return 0; - } - - /** - * Fill the data in languageData to match with totalData length. - * @param {[Object]} totalData Array of total translation trend data - * @param {[Object]} totalData Array of translations to a particular language - * @return {[Object]} Array of translations to a particular language, after padding - */ - function mergeAndFill( totalData, languageData ) { - var i; - - if ( totalData.length === languageData.length ) { - return languageData; - } - - // Fill at the beginning if languageData is not starting - // when totalData starts - for ( i = 0; i < totalData.length; i++ ) { - if ( !languageData || languageData.length === 0 ) { - break; - } - if ( languageData[ i ] && new Date( totalData[ i ].date ) > new Date( languageData[ i ].date ) ) { - totalData.splice( i, 0, { - date: languageData[ i ].date, - count: totalData[ i - 1 ] ? totalData[ i - 1 ].count : 0 - } ); - } - if ( !languageData[ i ] || new Date( totalData[ i ].date ) < new Date( languageData[ i ].date ) ) { - languageData.splice( i, 0, { - date: totalData[ i ].date, - count: languageData[ i - 1 ] ? languageData[ i - 1 ].count : 0 - } ); - } - } - - return languageData; } $( function () { -- To view, visit https://gerrit.wikimedia.org/r/236538 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8581d07c00dac6228ba5cc8b465acf431a1163e3 Gerrit-PatchSet: 7 Gerrit-Project: mediawiki/extensions/ContentTranslation Gerrit-Branch: master Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com> Gerrit-Reviewer: Amire80 <amir.ahar...@mail.huji.ac.il> Gerrit-Reviewer: KartikMistry <kartik.mis...@gmail.com> Gerrit-Reviewer: Nikerabbit <niklas.laxst...@gmail.com> Gerrit-Reviewer: Santhosh <santhosh.thottin...@gmail.com> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits