Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MessageWebImporter.php
1<?php
2declare( strict_types = 1 );
3
5
6use DifferenceEngine;
7use InvalidArgumentException;
8use MediaWiki\CommentStore\CommentStoreComment;
9use MediaWiki\Content\ContentHandler;
10use MediaWiki\Context\RequestContext;
16use MediaWiki\Html\Html;
17use MediaWiki\Language\Language;
18use MediaWiki\MediaWikiServices;
19use MediaWiki\Revision\MutableRevisionRecord;
20use MediaWiki\Revision\SlotRecord;
21use MediaWiki\Title\Title;
22use MediaWiki\User\User;
23use MediaWiki\Xml\Xml;
24use MessageGroup;
25use MessageLocalizer;
26use RecentChange;
27use RuntimeException;
28
39 private Title $title;
40 private User $user;
41 private MessageGroup $group;
42 private string $code;
44 private $time;
45 private MessageLocalizer $messageLocalizer;
47 private const MAX_PROCESSING_TIME = 43;
48
56 public function __construct(
57 Title $title,
58 User $user,
59 MessageLocalizer $messageLocalizer,
60 $group = null,
61 string $code = 'en'
62 ) {
63 $this->setTitle( $title );
64 $this->setUser( $user );
65 $this->setGroup( $group );
66 $this->setCode( $code );
67 $this->messageLocalizer = $messageLocalizer;
68 }
69
71 public function getTitle(): Title {
72 return $this->title;
73 }
74
75 public function setTitle( Title $title ): void {
76 $this->title = $title;
77 }
78
79 public function getUser(): User {
80 return $this->user;
81 }
82
83 public function setUser( User $user ): void {
84 $this->user = $user;
85 }
86
87 public function getGroup(): MessageGroup {
88 return $this->group;
89 }
90
92 public function setGroup( $group ): void {
93 if ( $group instanceof MessageGroup ) {
94 $this->group = $group;
95 } else {
96 $this->group = MessageGroups::getGroup( $group );
97 }
98 }
99
100 public function getCode(): string {
101 return $this->code;
102 }
103
104 public function setCode( string $code = 'en' ): void {
105 $this->code = $code;
106 }
107
108 protected function getAction(): string {
109 return $this->getTitle()->getLocalURL();
110 }
111
112 protected function doHeader(): string {
113 $formParams = [
114 'method' => 'post',
115 'action' => $this->getAction(),
116 'class' => 'mw-translate-manage'
117 ];
118
119 $csrfTokenSet = RequestContext::getMain()->getCsrfTokenSet();
120 return Xml::openElement( 'form', $formParams ) .
121 Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
122 Html::hidden( 'token', $csrfTokenSet->getToken() ) .
123 Html::hidden( 'process', 1 );
124 }
125
126 protected function doFooter(): string {
127 return '</form>';
128 }
129
130 protected function allowProcess(): bool {
131 $context = RequestContext::getMain();
132 $request = $context->getRequest();
133 $csrfTokenSet = $context->getCsrfTokenSet();
134
135 return $request->wasPosted()
136 && $request->getBool( 'process' )
137 && $csrfTokenSet->matchTokenField( 'token' );
138 }
139
140 protected function getActions(): array {
141 return [
142 'import',
143 $this->code === 'en' ? 'fuzzy' : 'conflict',
144 'ignore',
145 ];
146 }
147
148 public function execute( array $messages ): bool {
149 $context = RequestContext::getMain();
150 $output = $context->getOutput();
151
152 // Set up diff engine
153 $diff = new DifferenceEngine();
154 $diff->showDiffStyle();
155 $diff->setReducedLineNumbers();
156
157 // Check whether we do processing
158 $process = $this->allowProcess();
159
160 // Initialise collection
161 $group = $this->getGroup();
162 $code = $this->getCode();
163 $collection = $group->initCollection( $code );
164 $collection->loadTranslations();
165
166 $output->addHTML( $this->doHeader() );
167
168 // Initialise variable to keep track whether all changes were imported
169 // or not. If we're allowed to process, initially assume they were.
170 $allDone = $process;
171
172 // Determine changes for each message.
173 $changed = [];
174
175 foreach ( $messages as $key => $value ) {
176 $old = null;
177 $isExistingMessageFuzzy = false;
178
179 if ( isset( $collection[$key] ) ) {
180 // This returns null if no existing translation is found
181 $old = $collection[$key]->translation();
182 $isExistingMessageFuzzy = $collection[$key]->hasTag( 'fuzzy' );
183 }
184
185 if ( $old === null ) {
186 // We found a new translation for this message of the
187 // current group: import it.
188 if ( $process ) {
189 $action = 'import';
190 $this->doAction(
191 $action,
192 $group,
193 $key,
194 $value
195 );
196 }
197 // Show the user that we imported the new translation
198 $para = '<code class="mw-tmi-new">' . htmlspecialchars( $key ) . '</code>';
199 $name = $context->msg( 'translate-manage-import-new' )->rawParams( $para )
200 ->escaped();
201 $text = Utilities::convertWhiteSpaceToHTML( $value );
202 $changed[] = self::makeSectionElement( $name, 'new', $text );
203 } else {
204 // No changes at all, ignore
205 if ( $old === (string)$value ) {
206 continue;
207 }
208
209 // Check if the message is already fuzzy in the system, and then determine if there are changes
210 $oldTextForDiff = $old;
211 if ( $isExistingMessageFuzzy ) {
212 if ( MessageHandle::makeFuzzyString( $old ) === (string)$value ) {
213 continue;
214 }
215
216 // Normalize the display of FUZZY message diffs so that if an old message has
217 // a fuzzy tag, then that is added to the text used in the diff.
218 $oldTextForDiff = MessageHandle::makeFuzzyString( $old );
219 }
220
221 // MutableRevisionRecord expects a page that can exist, so use a dummy non-special page.
222 $dummyMainPage = Title::makeTitle( NS_MAIN, 'Some title just for diff' );
223 $oldContent = ContentHandler::makeContent( $oldTextForDiff, $dummyMainPage );
224 $oldRevision = new MutableRevisionRecord( $dummyMainPage );
225 $oldRevision->setContent( SlotRecord::MAIN, $oldContent );
226
227 $newContent = ContentHandler::makeContent( $value, $dummyMainPage );
228 $newRevision = new MutableRevisionRecord( $dummyMainPage );
229 $newRevision->setContent( SlotRecord::MAIN, $newContent );
230
231 $diff->setRevisions( $oldRevision, $newRevision );
232 $text = $diff->getDiff( '', '' );
233
234 // This is a changed translation. Note it for the next steps.
235 $type = 'changed';
236
237 // Get the user instructions for the current message,
238 // submitted together with the form
239 $action = $context->getRequest()
240 ->getVal( self::escapeNameForPHP( "action-$type-$key" ) );
241
242 if ( $process ) {
243 if ( $changed === [] ) {
244 // Initialise the HTML list showing the changes performed
245 $changed[] = '<ul>';
246 }
247
248 if ( $action === null ) {
249 // We have been told to process the messages, but not
250 // what to do with this one. Tell the user.
251 $message = $context->msg(
252 'translate-manage-inconsistent',
253 wfEscapeWikiText( "action-$type-$key" )
254 )->parse();
255 $changed[] = "<li>$message</li></ul>";
256
257 // Also stop any further processing for the other messages.
258 $process = false;
259 } else {
260 // Check processing time
261 if ( $this->time === null ) {
262 $this->time = (int)wfTimestamp();
263 }
264
265 // We have all the necessary information on this changed
266 // translation: actually process the message
267 $messageKeyAndParams = $this->doAction(
268 $action,
269 $group,
270 $key,
271 $value
272 );
273
274 // Show what we just did, adding to the list of changes
275 $msgKey = array_shift( $messageKeyAndParams );
276 $params = $messageKeyAndParams;
277 $message = $context->msg( $msgKey, $params )->parse();
278 $changed[] = "<li>$message</li>";
279
280 // Stop processing further messages if too much time
281 // has been spent.
282 if ( $this->checkProcessTime() ) {
283 $process = false;
284 $message = $context->msg( 'translate-manage-toolong' )
285 ->numParams( self::MAX_PROCESSING_TIME )->parse();
286 $changed[] = "<li>$message</li></ul>";
287 }
288
289 continue;
290 }
291 }
292
293 // We are not processing messages, or no longer, or this was an
294 // un-actionable translation. We will eventually return false
295 $allDone = false;
296
297 // Prepare to ask the user what to do with this message
298 $actions = $this->getActions();
299 $defaultAction = $action ?: 'import';
300
301 $act = [];
302
303 // Give grep a chance to find the usages:
304 // translate-manage-action-import, translate-manage-action-conflict,
305 // translate-manage-action-ignore, translate-manage-action-fuzzy
306 foreach ( $actions as $action ) {
307 $label = $context->msg( "translate-manage-action-$action" )->escaped();
308 $act[] = Html::rawElement(
309 'label',
310 [],
311 Html::radio(
312 self::escapeNameForPHP( "action-$type-$key" ),
313 $action === $defaultAction,
314 [ 'value' => $action ]
315 ) .
316 "\u{00A0}" .
317 $label
318 );
319 }
320
321 $param = '<code class="mw-tmi-diff">' . htmlspecialchars( $key ) . '</code>';
322 $name = $context->msg( 'translate-manage-import-diff' )
323 ->rawParams( $param, implode( ' ', $act ) )
324 ->escaped();
325
326 $changed[] = self::makeSectionElement( $name, $type, $text );
327 }
328 }
329
330 if ( !$process ) {
331 $collection->filter( MessageCollection::FILTER_HAS_TRANSLATION, MessageCollection::INCLUDE_MATCHING );
332 $keys = $collection->getMessageKeys();
333
334 $diff = array_diff( $keys, array_keys( $messages ) );
335
336 foreach ( $diff as $s ) {
337 $para = '<code class="mw-tmi-deleted">' . htmlspecialchars( $s ) . '</code>';
338 $name = $context->msg( 'translate-manage-import-deleted' )->rawParams( $para )->escaped();
339 $text = Utilities::convertWhiteSpaceToHTML( $collection[$s]->translation() );
340 $changed[] = self::makeSectionElement( $name, 'deleted', $text );
341 }
342 }
343
344 if ( $process || ( $changed === [] && $code !== 'en' ) ) {
345 if ( $changed === [] ) {
346 $output->addWikiMsg( 'translate-manage-nochanges-other' );
347 }
348
349 if ( $changed === [] || !str_starts_with( end( $changed ), '<li>' ) ) {
350 $changed[] = '<ul>';
351 }
352
353 $changed[] = '</ul>';
354
355 $languageName = Utilities::getLanguageName( $code, $context->getLanguage()->getCode() );
356 $message = $context
357 ->msg( 'translate-manage-import-done', $group->getId(), $group->getLabel(), $languageName )
358 ->parse();
359 $changed[] = Html::successBox( $message );
360 $output->addHTML( implode( "\n", $changed ) );
361 } else {
362 // END
363 if ( $changed !== [] ) {
364 if ( $code === 'en' ) {
365 $output->addWikiMsg( 'translate-manage-intro-en' );
366 } else {
367 $lang = Utilities::getLanguageName(
368 $code,
369 $context->getLanguage()->getCode()
370 );
371 $output->addWikiMsg( 'translate-manage-intro-other', $lang );
372 }
373 $output->addHTML( Html::hidden( 'language', $code ) );
374 $output->addHTML( implode( "\n", $changed ) );
375 $output->addHTML( Html::submitButton( $context->msg( 'translate-manage-submit' )->text() ) );
376 } else {
377 $output->addWikiMsg( 'translate-manage-nochanges' );
378 }
379 }
380
381 $output->addHTML( $this->doFooter() );
382
383 return $allDone;
384 }
385
395 private function doAction(
396 string $action,
397 MessageGroup $group,
398 string $key,
399 string $message
400 ): array {
401 global $wgTranslateDocumentationLanguageCode;
402
403 $comment = '';
404 $code = $this->getCode();
405 $title = $this->makeTranslationTitle( $group, $key, $code );
406
407 if ( $action === 'import' || $action === 'conflict' ) {
408 if ( $action === 'import' ) {
409 $comment = wfMessage( 'translate-manage-import-summary' )->inContentLanguage()->plain();
410 } else {
411 $comment = wfMessage( 'translate-manage-conflict-summary' )->inContentLanguage()->plain();
412 $message = MessageHandle::makeFuzzyString( $message );
413 }
414
415 return self::doImport( $title, $message, $comment, $this->getUser(), $this->messageLocalizer );
416 } elseif ( $action === 'ignore' ) {
417 return [ 'translate-manage-import-ignore', $key ];
418 } elseif ( $action === 'fuzzy' && $code !== 'en' &&
419 $code !== $wgTranslateDocumentationLanguageCode
420 ) {
421 $message = MessageHandle::makeFuzzyString( $message );
422
423 return self::doImport( $title, $message, $comment, $this->getUser(), $this->messageLocalizer );
424 } elseif ( $action === 'fuzzy' && $code === 'en' ) {
425 return self::doFuzzy( $title, $message, $comment, $this->getUser(), $this->messageLocalizer );
426 } else {
427 throw new InvalidArgumentException( "Unhandled action $action" );
428 }
429 }
430
431 protected function checkProcessTime() {
432 return (int)wfTimestamp() - $this->time >= self::MAX_PROCESSING_TIME;
433 }
434
436 private static function doImport(
437 Title $title,
438 string $message,
439 string $summary,
440 User $user,
441 MessageLocalizer $messageLocalizer
442 ): array {
443 $mwServices = MediaWikiServices::getInstance();
444 $wikiPage = $mwServices->getWikiPageFactory()->newFromTitle( $title );
445 $content = ContentHandler::makeContent( $message, $title );
446
447 $updater = $wikiPage->newPageUpdater( $user )->setContent( SlotRecord::MAIN, $content );
448 if ( $user->authorizeWrite( 'autopatrol', $title ) ) {
449 $updater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
450 }
451 $updater->saveRevision( CommentStoreComment::newUnsavedComment( $summary ) );
452 $status = $updater->getStatus();
453 $success = $status->isOK();
454
455 if ( $success ) {
456 return [ 'translate-manage-import-ok',
457 wfEscapeWikiText( $title->getPrefixedText() )
458 ];
459 }
460
461 $statusFormatter = $mwServices
462 ->getFormatterFactory()
463 ->getStatusFormatter( $messageLocalizer );
464 $text = "Failed to import new version of page {$title->getPrefixedText()}\n";
465 $text .= $statusFormatter->getWikiText( $status );
466 throw new RuntimeException( $text );
467 }
468
470 public static function doFuzzy(
471 Title $title,
472 string $message,
473 string $comment,
474 ?User $user,
475 MessageLocalizer $messageLocalizer
476 ): array {
477 $context = RequestContext::getMain();
478 $services = MediaWikiServices::getInstance();
479
480 if ( !$context->getUser()->isAllowed( 'translate-manage' ) ) {
481 return [ 'badaccess-group0' ];
482 }
483
484 // Edit with fuzzybot if there is no user.
485 if ( !$user ) {
486 $user = FuzzyBot::getUser();
487 }
488
489 // Work on all subpages of base title.
490 $handle = new MessageHandle( $title );
491 $titleText = $handle->getKey();
492
493 $revStore = $services->getRevisionStore();
494 $dbw = $services->getDBLoadBalancer()->getConnection( DB_PRIMARY );
495 $rows = $revStore->newSelectQueryBuilder( $dbw )
496 ->joinPage()
497 ->where( [
498 'page_namespace' => $title->getNamespace(),
499 'page_latest=rev_id',
500 'page_title' . $dbw->buildLike( "$titleText/", $dbw->anyString() ),
501 ] )
502 ->caller( __METHOD__ )
503 ->fetchResultSet();
504
505 $changed = [];
506 $slots = $revStore->getContentBlobsForBatch( $rows, [ SlotRecord::MAIN ] )->getValue();
507
508 foreach ( $rows as $row ) {
509 global $wgTranslateDocumentationLanguageCode;
510
511 $translationTitle = Title::makeTitle( (int)$row->page_namespace, $row->page_title );
512
513 // No fuzzy for English original or documentation language code.
514 if ( $translationTitle->getSubpageText() === 'en' ||
515 $translationTitle->getSubpageText() === $wgTranslateDocumentationLanguageCode
516 ) {
517 // Use imported text, not database text.
518 $text = $message;
519 } elseif ( isset( $slots[$row->rev_id] ) ) {
520 $slot = $slots[$row->rev_id][SlotRecord::MAIN];
521 $text = MessageHandle::makeFuzzyString( $slot->blob_data );
522 } else {
523 $text = MessageHandle::makeFuzzyString(
524 Utilities::getTextFromTextContent(
525 $revStore->newRevisionFromRow( $row )->getContent( SlotRecord::MAIN )
526 )
527 );
528 }
529
530 // Do actual import
531 $changed[] = self::doImport(
532 $translationTitle,
533 $text,
534 $comment,
535 $user,
536 $messageLocalizer
537 );
538 }
539
540 // Format return text
541 $text = '';
542 foreach ( $changed as $c ) {
543 $key = array_shift( $c );
544 $text .= '* ' . $context->msg( $key, $c )->plain() . "\n";
545 }
546
547 return [ 'translate-manage-import-fuzzy', "\n" . $text ];
548 }
549
559 private function makeTranslationTitle( MessageGroup $group, string $key, string $code ): Title {
560 $ns = $group->getNamespace();
561
562 return Title::makeTitleSafe( $ns, "$key/$code" );
563 }
564
574 public static function makeSectionElement(
575 string $legend,
576 string $type,
577 string $content,
578 ?Language $lang = null
579 ): string {
580 $containerParams = [ 'class' => "mw-tpt-sp-section mw-tpt-sp-section-type-{$type}" ];
581 $legendParams = [ 'class' => 'mw-tpt-sp-legend' ];
582 $contentParams = [ 'class' => 'mw-tpt-sp-content' ];
583 if ( $lang ) {
584 $contentParams['dir'] = $lang->getDir();
585 $contentParams['lang'] = $lang->getCode();
586 }
587
588 return Html::rawElement( 'div', $containerParams,
589 Html::rawElement( 'div', $legendParams, $legend ) .
590 Html::rawElement( 'div', $contentParams, $content )
591 );
592 }
593
599 private static function escapeNameForPHP( string $name ): string {
600 $replacements = [
601 '(' => '(OP)',
602 ' ' => '(SP)',
603 "\t" => '(TAB)',
604 '.' => '(DOT)',
605 "'" => '(SQ)',
606 "\"" => '(DQ)',
607 '%' => '(PC)',
608 '&' => '(AMP)',
609 ];
610
611 return strtr( $name, $replacements );
612 }
613}
return[ 'Translate:AggregateGroupManager'=> static function(MediaWikiServices $services):AggregateGroupManager { return new AggregateGroupManager($services->getTitleFactory(), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:AggregateGroupMessageGroupFactory'=> static function(MediaWikiServices $services):AggregateGroupMessageGroupFactory { return new AggregateGroupMessageGroupFactory($services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:ConfigHelper'=> static function():ConfigHelper { return new ConfigHelper();}, 'Translate:CsvTranslationImporter'=> static function(MediaWikiServices $services):CsvTranslationImporter { return new CsvTranslationImporter( $services->getWikiPageFactory());}, 'Translate:EntitySearch'=> static function(MediaWikiServices $services):EntitySearch { return new EntitySearch($services->getMainWANObjectCache(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), MessageGroups::singleton(), $services->getNamespaceInfo(), $services->get( 'Translate:MessageIndex'), $services->getTitleParser(), $services->getTitleFormatter());}, 'Translate:ExternalMessageSourceStateComparator'=> static function(MediaWikiServices $services):ExternalMessageSourceStateComparator { return new ExternalMessageSourceStateComparator(new SimpleStringComparator(), $services->getRevisionLookup(), $services->getPageStore());}, 'Translate:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance(LogNames::GROUP_SYNCHRONIZATION), $services->get( 'Translate:MessageIndex'), $services->getTitleFactory(), $services->get( 'Translate:MessageGroupSubscription'), new ServiceOptions(ExternalMessageSourceStateImporter::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:FileBasedMessageGroupFactory'=> static function(MediaWikiServices $services):FileBasedMessageGroupFactory { return new FileBasedMessageGroupFactory(new MessageGroupConfigurationParser(), new ServiceOptions(FileBasedMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:FileFormatFactory'=> static function(MediaWikiServices $services):FileFormatFactory { return new FileFormatFactory( $services->getObjectFactory());}, 'Translate:GroupSynchronizationCache'=> static function(MediaWikiServices $services):GroupSynchronizationCache { return new GroupSynchronizationCache( $services->get( 'Translate:PersistentCache'));}, 'Translate:HookDefinedMessageGroupFactory'=> static function(MediaWikiServices $services):HookDefinedMessageGroupFactory { return new HookDefinedMessageGroupFactory( $services->get( 'Translate:HookRunner'));}, 'Translate:HookRunner'=> static function(MediaWikiServices $services):HookRunner { return new HookRunner( $services->getHookContainer());}, 'Translate:MessageBundleDependencyPurger'=> static function(MediaWikiServices $services):MessageBundleDependencyPurger { return new MessageBundleDependencyPurger( $services->get( 'Translate:TranslatableBundleFactory'));}, 'Translate:MessageBundleMessageGroupFactory'=> static function(MediaWikiServices $services):MessageBundleMessageGroupFactory { return new MessageBundleMessageGroupFactory($services->get( 'Translate:MessageGroupMetadata'), new ServiceOptions(MessageBundleMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore($services->get( 'Translate:RevTagStore'), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:MessageBundleTranslationLoader'=> static function(MediaWikiServices $services):MessageBundleTranslationLoader { return new MessageBundleTranslationLoader( $services->getLanguageFallback());}, 'Translate:MessageGroupMetadata'=> static function(MediaWikiServices $services):MessageGroupMetadata { return new MessageGroupMetadata( $services->getConnectionProvider());}, 'Translate:MessageGroupReviewStore'=> static function(MediaWikiServices $services):MessageGroupReviewStore { return new MessageGroupReviewStore($services->getConnectionProvider(), $services->get( 'Translate:HookRunner'));}, 'Translate:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getLinkRenderer(), $services->get( 'Translate:MessageGroupReviewStore'), $services->get( 'Translate:MessageGroupMetadata'), $services->getMainConfig() ->get( 'TranslateWorkflowStates') !==false);}, 'Translate:MessageGroupSubscription'=> static function(MediaWikiServices $services):MessageGroupSubscription { return new MessageGroupSubscription($services->get( 'Translate:MessageGroupSubscriptionStore'), $services->getJobQueueGroup(), $services->getUserIdentityLookup(), LoggerFactory::getInstance(LogNames::GROUP_SUBSCRIPTION), new ServiceOptions(MessageGroupSubscription::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:MessageGroupSubscriptionHookHandler'=> static function(MediaWikiServices $services):MessageGroupSubscriptionHookHandler { return new MessageGroupSubscriptionHookHandler($services->get( 'Translate:MessageGroupSubscription'), $services->getUserFactory());}, 'Translate:MessageGroupSubscriptionStore'=> static function(MediaWikiServices $services):MessageGroupSubscriptionStore { return new MessageGroupSubscriptionStore( $services->getConnectionProvider());}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=(array) $services->getMainConfig() ->get( 'TranslateMessageIndex');$class=array_shift( $params);$implementationMap=['HashMessageIndex'=> HashMessageIndex::class, 'CDBMessageIndex'=> CDBMessageIndex::class, 'DatabaseMessageIndex'=> DatabaseMessageIndex::class, 'hash'=> HashMessageIndex::class, 'cdb'=> CDBMessageIndex::class, 'database'=> DatabaseMessageIndex::class,];$messageIndexStoreClass=$implementationMap[$class] ?? $implementationMap['database'];return new MessageIndex(new $messageIndexStoreClass, $services->getMainWANObjectCache(), $services->getJobQueueGroup(), $services->get( 'Translate:HookRunner'), LoggerFactory::getInstance(LogNames::MAIN), $services->getMainObjectStash(), $services->getConnectionProvider(), new ServiceOptions(MessageIndex::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:MessagePrefixStats'=> static function(MediaWikiServices $services):MessagePrefixStats { return new MessagePrefixStats( $services->getTitleParser());}, 'Translate:ParsingPlaceholderFactory'=> static function():ParsingPlaceholderFactory { return new ParsingPlaceholderFactory();}, 'Translate:PersistentCache'=> static function(MediaWikiServices $services):PersistentCache { return new PersistentDatabaseCache($services->getConnectionProvider(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:RevTagStore'=> static function(MediaWikiServices $services):RevTagStore { return new RevTagStore( $services->getConnectionProvider());}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleDeleter'=> static function(MediaWikiServices $services):TranslatableBundleDeleter { return new TranslatableBundleDeleter($services->getMainObjectStash(), $services->getJobQueueGroup(), $services->get( 'Translate:SubpageListBuilder'), $services->get( 'Translate:TranslatableBundleFactory'));}, 'Translate:TranslatableBundleExporter'=> static function(MediaWikiServices $services):TranslatableBundleExporter { return new TranslatableBundleExporter($services->get( 'Translate:SubpageListBuilder'), $services->getWikiExporterFactory(), $services->getConnectionProvider());}, 'Translate:TranslatableBundleFactory'=> static function(MediaWikiServices $services):TranslatableBundleFactory { return new TranslatableBundleFactory($services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:MessageBundleStore'));}, 'Translate:TranslatableBundleImporter'=> static function(MediaWikiServices $services):TranslatableBundleImporter { return new TranslatableBundleImporter($services->getWikiImporterFactory(), $services->get( 'Translate:TranslatablePageParser'), $services->getRevisionLookup(), $services->getNamespaceInfo(), $services->getTitleFactory(), $services->getFormatterFactory());}, 'Translate:TranslatableBundleMover'=> static function(MediaWikiServices $services):TranslatableBundleMover { return new TranslatableBundleMover($services->getMovePageFactory(), $services->getJobQueueGroup(), $services->getLinkBatchFactory(), $services->get( 'Translate:TranslatableBundleFactory'), $services->get( 'Translate:SubpageListBuilder'), $services->getConnectionProvider(), $services->getObjectCacheFactory(), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getConnectionProvider() ->getPrimaryDatabase(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, 'Translate:TranslatablePageMarker'=> static function(MediaWikiServices $services):TranslatablePageMarker { return new TranslatablePageMarker($services->getConnectionProvider(), $services->getJobQueueGroup(), $services->getLinkRenderer(), MessageGroups::singleton(), $services->get( 'Translate:MessageIndex'), $services->getTitleFormatter(), $services->getTitleParser(), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:TranslatablePageStateStore'), $services->get( 'Translate:TranslationUnitStoreFactory'), $services->get( 'Translate:MessageGroupMetadata'), $services->getWikiPageFactory(), $services->get( 'Translate:TranslatablePageView'), $services->get( 'Translate:MessageGroupSubscription'), $services->getFormatterFactory());}, 'Translate:TranslatablePageMessageGroupFactory'=> static function(MediaWikiServices $services):TranslatablePageMessageGroupFactory { return new TranslatablePageMessageGroupFactory(new ServiceOptions(TranslatablePageMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStateStore'=> static function(MediaWikiServices $services):TranslatablePageStateStore { return new TranslatablePageStateStore($services->get( 'Translate:PersistentCache'), $services->getPageStore());}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), $services->get( 'Translate:RevTagStore'), $services->getConnectionProvider(), $services->get( 'Translate:TranslatableBundleStatusStore'), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:TranslatablePageView'=> static function(MediaWikiServices $services):TranslatablePageView { return new TranslatablePageView($services->getConnectionProvider(), $services->get( 'Translate:TranslatablePageStateStore'), new ServiceOptions(TranslatablePageView::SERVICE_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslateSandbox'=> static function(MediaWikiServices $services):TranslateSandbox { return new TranslateSandbox($services->getUserFactory(), $services->getConnectionProvider(), $services->getPermissionManager(), $services->getAuthManager(), $services->getUserGroupManager(), $services->getActorStore(), $services->getUserOptionsManager(), $services->getJobQueueGroup(), $services->get( 'Translate:HookRunner'), new ServiceOptions(TranslateSandbox::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { return new TranslationStashStorage( $services->getConnectionProvider() ->getPrimaryDatabase());}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory(), $services->getConnectionProvider());}, 'Translate:TranslationUnitStoreFactory'=> static function(MediaWikiServices $services):TranslationUnitStoreFactory { return new TranslationUnitStoreFactory( $services->getDBLoadBalancer());}, 'Translate:TranslatorActivity'=> static function(MediaWikiServices $services):TranslatorActivity { $query=new TranslatorActivityQuery($services->getMainConfig(), $services->getDBLoadBalancer());return new TranslatorActivity($services->getMainObjectStash(), $query, $services->getJobQueueGroup());}, 'Translate:TtmServerFactory'=> static function(MediaWikiServices $services):TtmServerFactory { $config=$services->getMainConfig();$default=$config->get( 'TranslateTranslationDefaultService');if( $default===false) { $default=null;} return new TtmServerFactory( $config->get( 'TranslateTranslationServices'), $default);}]
@phpcs-require-sorted-array
Factory class for accessing message groups individually by id or all of them as a list.
This file contains the class for core message collections implementation.
Class for pointing to messages, like Title class is for titles.
__construct(Title $title, User $user, MessageLocalizer $messageLocalizer, $group=null, string $code='en')
static makeSectionElement(string $legend, string $type, string $content, ?Language $lang=null)
Make section elements.
static doFuzzy(Title $title, string $message, string $comment, ?User $user, MessageLocalizer $messageLocalizer)
FuzzyBot - the misunderstood workhorse.
Definition FuzzyBot.php:15
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Definition Utilities.php:31
Interface for message groups.
Finds external changes for file based message groups.