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