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