Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
characterEditStats.php
Go to the documentation of this file.
1<?php
12// Standard boilerplate to define $IP
15use MediaWiki\MediaWikiServices;
16use MediaWiki\Title\Title;
17
18if ( getenv( 'MW_INSTALL_PATH' ) !== false ) {
19 $IP = getenv( 'MW_INSTALL_PATH' );
20} else {
21 $dir = __DIR__;
22 $IP = "$dir/../../..";
23}
24require_once "$IP/maintenance/Maintenance.php";
25
26class CharacterEditStats extends Maintenance {
27 public function __construct() {
28 parent::__construct();
29 $this->addDescription( 'Script to show number of characters translated .' );
30 $this->addOption(
31 'top',
32 '(optional) Show given number of language codes (default: show all)',
33 false, /*required*/
34 true /*has arg*/
35 );
36 $this->addOption(
37 'days',
38 '(optional) Calculate for given number of days (default: 30)',
39 false, /*required*/
40 true /*has arg*/
41 );
42 $this->addOption(
43 'ns',
44 '(optional) Comma separated list of namespace IDs',
45 false, /*required*/
46 true /*has arg*/
47 );
48 $this->requireExtension( 'Translate' );
49 }
50
51 public function execute() {
52 global $wgSitename, $wgTranslateMessageNamespaces;
53
54 $days = (int)$this->getOption( 'days', 30 );
55 $top = (int)$this->getOption( 'top', -1 );
56
57 $namespaces = [];
58 if ( $this->hasOption( 'ns' ) ) {
59 $input = explode( ',', $this->getOption( 'ns' ) );
60
61 foreach ( $input as $namespace ) {
62 if ( is_numeric( $namespace ) ) {
63 $namespaces[] = $namespace;
64 }
65 }
66 } else {
67 $namespaces = $wgTranslateMessageNamespaces;
68 }
69
70 // Select set of edits to report on
71 $rows = $this->getRevisionsFromHistory( $days, $namespaces );
72
73 // Get counts for edits per language code after filtering out edits by FuzzyBot
74 $codes = [];
75
76 foreach ( $rows as $_ ) {
77 // Filter out edits by FuzzyBot
78 if ( $_->user_text === FuzzyBot::getName() ) {
79 continue;
80 }
81
82 $handle = new MessageHandle( Title::newFromText( $_->title ) );
83 $code = $handle->getCode();
84
85 if ( !isset( $codes[$code] ) ) {
86 $codes[$code] = 0;
87 }
88
89 $codes[$code] += $_->length;
90 }
91
92 // Sort counts and report descending up to $top rows.
93 arsort( $codes );
94 $i = 0;
95 $total = 0;
96 $this->output( "Character edit stats for last $days days in $wgSitename\n" );
97 $this->output( "code\tname\tedit\n" );
98 $this->output( "-----------------------\n" );
99 $languageNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
100 foreach ( $codes as $code => $num ) {
101 if ( $i++ === $top ) {
102 break;
103 }
104 $language = $languageNameUtils->getLanguageName( $code );
105 if ( !$language ) {
106 // this will be very rare, but avoid division by zero in next line
107 continue;
108 }
109 $charRatio = mb_strlen( $language, 'UTF-8' ) / strlen( $language );
110 $num = (int)( $num * $charRatio );
111 $total += $num;
112 $this->output( "$code\t$language\t$num\n" );
113 }
114 $this->output( "-----------------------\n" );
115 $this->output( "Total\t\t$total\n" );
116 }
117
118 private function getRevisionsFromHistory( $days, array $namespaces ) {
119 $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_REPLICA );
120 $cutoff = $dbr->addQuotes( $dbr->timestamp( time() - $days * 24 * 3600 ) );
121
122 $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
123 $result = $revisionStore->newSelectQueryBuilder( $dbr )
124 ->select(
125 [
126 'title' => 'page_title',
127 'user_text' => 'actor_rev_user.actor_name',
128 'length' => 'rev_len',
129 ]
130 )
131 ->joinPage()
132 ->where( [
133 "rev_timestamp > $cutoff",
134 'page_namespace' => $namespaces,
135 ] )
136 ->caller( __METHOD__ )
137 ->fetchResultSet();
138 return iterator_to_array( $result );
139 }
140}
141
142$maintClass = CharacterEditStats::class;
143require_once RUN_MAINTENANCE_IF_MAIN;
Class for pointing to messages, like Title class is for titles.
FuzzyBot - the misunderstood workhorse.
Definition FuzzyBot.php:15