Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 79 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
DeleteEqualTranslationsMaintenanceScript | |
0.00% |
0 / 79 |
|
0.00% |
0 / 7 |
306 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
getEqualMessages | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
getUserStats | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
printUserStats | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
printMessages | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
deleteMessages | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace MediaWiki\Extension\Translate\Diagnostics; |
5 | |
6 | use MediaWiki\Extension\Translate\MessageGroupProcessing\MessageGroups; |
7 | use MediaWiki\Extension\Translate\MessageLoading\Message; |
8 | use MediaWiki\Extension\Translate\MessageLoading\MessageCollection; |
9 | use MediaWiki\Extension\Translate\SystemUsers\FuzzyBot; |
10 | use MediaWiki\Extension\Translate\Utilities\BaseMaintenanceScript; |
11 | use MediaWiki\MediaWikiServices; |
12 | use MediaWiki\Title\Title; |
13 | use MediaWiki\Title\TitleValue; |
14 | use SplObjectStorage; |
15 | use const SORT_NUMERIC; |
16 | |
17 | /** |
18 | * @since 2021.01 |
19 | * @license GPL-2.0-or-later |
20 | * @author Niklas Laxström |
21 | */ |
22 | class DeleteEqualTranslationsMaintenanceScript extends BaseMaintenanceScript { |
23 | public function __construct() { |
24 | parent::__construct(); |
25 | $this->addDescription( 'Delete translations that are equal to the definition' ); |
26 | |
27 | $this->addOption( |
28 | 'group', |
29 | 'Which group to scan', |
30 | self::REQUIRED, |
31 | self::HAS_ARG |
32 | ); |
33 | $this->addOption( |
34 | 'language', |
35 | 'Which language to scan', |
36 | self::REQUIRED, |
37 | self::HAS_ARG |
38 | ); |
39 | $this->addOption( |
40 | 'really', |
41 | 'Delete the listed pages instead of just listing them' |
42 | ); |
43 | $this->addOption( |
44 | 'comment', |
45 | 'Comment for the deletions' |
46 | ); |
47 | |
48 | $this->requireExtension( 'Translate' ); |
49 | } |
50 | |
51 | /** @inheritDoc */ |
52 | public function execute() { |
53 | $groupId = $this->getOption( 'group' ); |
54 | $language = $this->getOption( 'language' ); |
55 | $group = MessageGroups::getGroup( $groupId ); |
56 | if ( !$group ) { |
57 | $this->fatalError( "Message group '$groupId' does not exist" ); |
58 | } |
59 | |
60 | $collection = $group->initCollection( $language ); |
61 | $equalMessages = $this->getEqualMessages( $collection ); |
62 | $equalMessageCount = count( $equalMessages ); |
63 | if ( $equalMessageCount === 0 ) { |
64 | $this->output( "No translations equal to definition found\n" ); |
65 | return; |
66 | } |
67 | |
68 | $stats = $this->getUserStats( $equalMessages ); |
69 | $this->printUserStats( $stats, $equalMessageCount ); |
70 | $this->output( "\n" ); |
71 | $this->printMessages( $equalMessages ); |
72 | |
73 | if ( $this->hasOption( 'really' ) ) { |
74 | $comment = $this->getOption( 'comment' ) ?? ''; |
75 | $this->deleteMessages( $equalMessages, $comment ); |
76 | } else { |
77 | $this->output( "This is a dry-run. Run again with --really to delete these messages\n" ); |
78 | } |
79 | } |
80 | |
81 | private function getEqualMessages( MessageCollection $collection ): SplObjectStorage { |
82 | $collection->filter( MessageCollection::FILTER_TRANSLATED, MessageCollection::INCLUDE_MATCHING ); |
83 | $collection->loadTranslations(); |
84 | |
85 | $messages = new SplObjectStorage(); |
86 | foreach ( $collection->keys() as $key => $titleValue ) { |
87 | /** @var Message $message */ |
88 | $message = $collection[$key]; |
89 | |
90 | if ( $message->definition() === $message->translation() ) { |
91 | $messages->attach( $titleValue, $message ); |
92 | } |
93 | } |
94 | |
95 | return $messages; |
96 | } |
97 | |
98 | private function getUserStats( SplObjectStorage $messages ): array { |
99 | $stats = []; |
100 | foreach ( $messages as $key ) { |
101 | /** @var Message $message */ |
102 | $message = $messages[$key]; |
103 | $index = $message->getProperty( 'last-translator-text' ); |
104 | $stats[$index] = ( $stats[$index] ?? 0 ) + 1; |
105 | } |
106 | |
107 | return $stats; |
108 | } |
109 | |
110 | private function printUserStats( array $stats, int $equalMessageCount ): void { |
111 | $this->output( "Found $equalMessageCount message(s) created by these user(s):\n" ); |
112 | arsort( $stats, SORT_NUMERIC ); |
113 | foreach ( $stats as $userName => $count ) { |
114 | $this->output( sprintf( "%6d | %s\n", $count, $userName ) ); |
115 | } |
116 | } |
117 | |
118 | private function printMessages( SplObjectStorage $messages ): void { |
119 | /** @var TitleValue $key */ |
120 | foreach ( $messages as $key ) { |
121 | /** @var Message $message */ |
122 | $message = $messages[$key]; |
123 | $title = Title::newFromLinkTarget( $key ); |
124 | $this->output( |
125 | sprintf( "== %s ==\n%s\n\n", $title->getPrefixedText(), $message->translation() ) |
126 | ); |
127 | } |
128 | } |
129 | |
130 | private function deleteMessages( SplObjectStorage $messages, string $reason ): void { |
131 | $services = MediaWikiServices::getInstance(); |
132 | $wikiPageFactory = $services->getWikiPageFactory(); |
133 | $deletePageFactory = $services->getDeletePageFactory(); |
134 | |
135 | $user = FuzzyBot::getUser(); |
136 | |
137 | /** @var TitleValue $key */ |
138 | foreach ( $messages as $key ) { |
139 | $title = Title::newFromLinkTarget( $key ); |
140 | $page = $wikiPageFactory->newFromTitle( $title ); |
141 | $status = $deletePageFactory->newDeletePage( $page, $user ) |
142 | ->deleteUnsafe( $reason ); |
143 | |
144 | if ( $status->isOK() ) { |
145 | $this->output( '.', 'deletions' ); |
146 | } else { |
147 | $pageName = $title->getPrefixedText(); |
148 | $this->output( "FAILED to delete page $pageName\n" ); |
149 | } |
150 | } |
151 | } |
152 | } |