Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MessageUpdateJob.php
Go to the documentation of this file.
1<?php
18use MediaWiki\MediaWikiServices;
19
33 public static function newJob(
34 Title $target, string $content, $fuzzy = false
35 ): self {
36 $params = [
37 'content' => $content,
38 'fuzzy' => $fuzzy,
39 ];
40
41 $job = new self( $target, $params );
42
43 return $job;
44 }
45
56 public static function newRenameJob(
57 Title $target,
58 string $targetStr,
59 string $replacement,
60 $fuzzy,
61 string $content,
62 array $otherLangContents = []
63 ): self {
64 $params = [
65 'target' => $targetStr,
66 'replacement' => $replacement,
67 'fuzzy' => $fuzzy,
68 'rename' => 'rename',
69 'content' => $content,
70 'otherLangs' => $otherLangContents
71 ];
72
73 $job = new self( $target, $params );
74
75 return $job;
76 }
77
82 public function __construct( $title, $params = [] ) {
83 parent::__construct( __CLASS__, $title, $params );
84 }
85
86 public function run() {
87 $params = $this->params;
88 $user = FuzzyBot::getUser();
89 $flags = EDIT_FORCE_BOT;
90 $isRename = $params['rename'] ?? false;
91 $isFuzzy = $params['fuzzy'] ?? false;
92 $otherLangs = $params['otherLangs'] ?? [];
93 $originalTitle = Title::newFromLinkTarget( $this->title->getTitleValue(), Title::NEW_CLONE );
94
95 if ( $isRename ) {
96 $this->title = $this->handleRename( $params['target'], $params['replacement'], $user );
97 if ( $this->title === null ) {
98 // There was a failure, return true, but don't proceed further.
99 $this->logWarning(
100 'Rename process could not find the source title.',
101 [
102 'replacement' => $params['replacement'],
103 'target' => $params['target']
104 ]
105 );
106
107 $this->removeFromCache( $originalTitle );
108 return true;
109 }
110 }
111
112 $title = $this->title;
113 $wikiPage = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
114 $summary = wfMessage( 'translate-manage-import-summary' )
115 ->inContentLanguage()->plain();
116 $content = ContentHandler::makeContent( $params['content'], $title );
117 $editStatus = $wikiPage->doUserEditContent(
118 $content,
119 $user,
120 $summary,
121 $flags
122 );
123 if ( !$editStatus->isOK() ) {
124 $this->logError(
125 'Failed to update content for source message',
126 [
127 'content' => $content,
128 'errors' => $editStatus->getErrors()
129 ]
130 );
131 }
132
133 if ( $isRename ) {
134 // Update other language content if present.
135 $this->processTranslationChanges(
136 $otherLangs, $params['replacement'], $params['namespace'], $summary, $flags, $user
137 );
138 }
139
140 if ( $isFuzzy ) {
141 $this->handleFuzzy( $title );
142 }
143
144 $this->removeFromCache( $originalTitle );
145 return true;
146 }
147
155 private function handleRename( $target, $replacement, User $user ) {
156 $newSourceTitle = null;
157
158 $sourceMessageHandle = new MessageHandle( $this->title );
159 $movableTitles = TranslateReplaceTitle::getTitlesForMove( $sourceMessageHandle, $replacement );
160
161 if ( $movableTitles === [] ) {
162 $this->logError(
163 'No moveable titles found with target text.',
164 [
165 'title' => $this->title->getPrefixedText(),
166 'replacement' => $replacement,
167 'target' => $target
168 ]
169 );
170 return null;
171 }
172
173 $renameSummary = wfMessage( 'translate-manage-import-rename-summary' )
174 ->inContentLanguage()->plain();
175
176 foreach ( $movableTitles as [ $sourceTitle, $replacementTitle ] ) {
177 $mv = MediaWikiServices::getInstance()
178 ->getMovePageFactory()
179 ->newMovePage( $sourceTitle, $replacementTitle );
180
181 $status = $mv->move( $user, $renameSummary, false );
182 if ( !$status->isOK() ) {
183 $this->logError(
184 'Error moving message',
185 [
186 'target' => $sourceTitle->getPrefixedText(),
187 'replacement' => $replacementTitle->getPrefixedText(),
188 'errors' => $status->getErrors()
189 ]
190 );
191 }
192
193 [ , $targetCode ] = Utilities::figureMessage( $replacementTitle->getText() );
194 if ( !$newSourceTitle && $sourceMessageHandle->getCode() === $targetCode ) {
195 $newSourceTitle = $replacementTitle;
196 }
197 }
198
199 if ( $newSourceTitle ) {
200 return $newSourceTitle;
201 } else {
202 // This means that the old source Title was never moved
203 // which is not possible but handle it.
204 $this->logError(
205 'Source title was not in the list of moveable titles.',
206 [ 'title' => $this->title->getPrefixedText() ]
207 );
208 }
209 }
210
216 private function handleFuzzy( Title $title ) {
217 global $wgTranslateDocumentationLanguageCode;
218 $handle = new MessageHandle( $title );
219
220 $languages = Utilities::getLanguageNames( 'en' );
221
222 // Don't fuzzy the message documentation
223 unset( $languages[$wgTranslateDocumentationLanguageCode] );
224 $languages = array_keys( $languages );
225
226 $pages = [];
227 foreach ( $languages as $code ) {
228 $otherTitle = $handle->getTitleForLanguage( $code );
229 $pages[$otherTitle->getDBkey()] = true;
230 }
231
232 // Unset to ensure that the source language is not fuzzied
233 unset( $pages[$title->getDBkey()] );
234
235 if ( $pages === [] ) {
236 return;
237 }
238
239 $dbw = MediaWikiServices::getInstance()
240 ->getDBLoadBalancer()
241 ->getMaintenanceConnectionRef( DB_PRIMARY );
242 $fields = [ 'page_id', 'page_latest' ];
243 $conds = [ 'page_namespace' => $title->getNamespace() ];
244 $conds['page_title'] = array_keys( $pages );
245
246 $res = $dbw->select( 'page', $fields, $conds, __METHOD__ );
247 $inserts = [];
248 foreach ( $res as $row ) {
249 $inserts[] = [
250 'rt_type' => RevTagStore::FUZZY_TAG,
251 'rt_page' => $row->page_id,
252 'rt_revision' => $row->page_latest,
253 ];
254 }
255
256 if ( $inserts === [] ) {
257 return;
258 }
259
260 $dbw->replace(
261 'revtag',
262 [ [ 'rt_type', 'rt_page', 'rt_revision' ] ],
263 $inserts,
264 __METHOD__
265 );
266 }
267
277 private function processTranslationChanges(
278 array $langChanges, $baseTitle, $groupNamespace, $summary, $flags, User $user
279 ) {
280 $wikiPageFactory = MediaWikiServices::getInstance()->getWikiPageFactory();
281 foreach ( $langChanges as $code => $contentStr ) {
282 $titleStr = Utilities::title( $baseTitle, $code, $groupNamespace );
283 $title = Title::newFromText( $titleStr, $groupNamespace );
284 $wikiPage = $wikiPageFactory->newFromTitle( $title );
285 $content = ContentHandler::makeContent( $contentStr, $title );
286 $status = $wikiPage->doUserEditContent(
287 $content,
288 $user,
289 $summary,
290 $flags
291 );
292 if ( !$status->isOK() ) {
293 $this->logError(
294 'Failed to update content for non-source message',
295 [
296 'title' => $title->getPrefixedText(),
297 'errors' => $status->getErrors()
298 ]
299 );
300 }
301 }
302 }
303
304 private function removeFromCache( Title $title ): void {
305 $config = MediaWikiServices::getInstance()->getMainConfig();
306
307 if ( !$config->get( 'TranslateGroupSynchronizationCache' ) ) {
308 return;
309 }
310
311 $currentTitle = $title;
312 // Check if the current title, is equal to the title passed. This condition will be
313 // true incase of rename where the old title would have been renamed.
314 if ( $this->title && $this->title->getPrefixedDBkey() !== $title->getPrefixedDBkey() ) {
315 $currentTitle = $this->title;
316 }
317
318 $sourceMessageHandle = new MessageHandle( $currentTitle );
319 $groupIds = $sourceMessageHandle->getGroupIds();
320 if ( !$groupIds ) {
321 $this->logWarning(
322 "Could not find group Id for message title: {$currentTitle->getPrefixedDBkey()}",
323 $this->getParams()
324 );
325 return;
326 }
327
328 $groupId = $groupIds[0];
329 $group = MessageGroups::getGroup( $groupId );
330
331 if ( !$group instanceof FileBasedMessageGroup ) {
332 return;
333 }
334
335 $groupSyncCache = Services::getInstance()->getGroupSynchronizationCache();
336 $messageKey = $title->getPrefixedDBkey();
337
338 if ( $groupSyncCache->isMessageBeingProcessed( $groupId, $messageKey ) ) {
339 $groupSyncCache->removeMessages( $groupId, $messageKey );
340 $groupSyncCache->extendGroupExpiryTime( $groupId );
341 } else {
342 $this->logWarning(
343 "Did not find key: $messageKey; in group: $groupId in group sync cache",
344 $this->getParams()
345 );
346 }
347 }
348}
This class implements default behavior for file based message groups.
Factory class for accessing message groups individually by id or all of them as a list.
Class to manage revision tags for translatable bundles.
Helper class that cotains utility methods to help with identifying and replace titles.
Minimal service container.
Definition Services.php:44
FuzzyBot - the misunderstood workhorse.
Definition FuzzyBot.php:15
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Definition Utilities.php:31
Class for pointing to messages, like Title class is for titles.
Job for updating translation pages when translation or message definition changes.
__construct( $title, $params=[])
static newRenameJob(Title $target, string $targetStr, string $replacement, $fuzzy, string $content, array $otherLangContents=[])
Create a message update job containing a rename process.
static newJob(Title $target, string $content, $fuzzy=false)
Create a normal message update job without a rename process.