37 private string $oldText;
38 private string $reason;
39 private bool $moveTalkpages =
true;
40 private bool $moveSubpages =
true;
41 private bool $leaveRedirect =
true;
42 private ObjectFactory $objectFactory;
44 private PermissionManager $permissionManager;
46 private FormatterFactory $formatterFactory;
47 private $movePageSpec;
49 private ?Title $oldTitle;
51 public function __construct(
52 ObjectFactory $objectFactory,
53 PermissionManager $permissionManager,
56 FormatterFactory $formatterFactory,
59 parent::__construct(
'Movepage' );
60 $this->objectFactory = $objectFactory;
61 $this->permissionManager = $permissionManager;
62 $this->bundleMover = $bundleMover;
63 $this->bundleFactory = $bundleFactory;
64 $this->formatterFactory = $formatterFactory;
65 $this->movePageSpec = $movePageSpec;
68 public function doesWrites():
bool {
72 protected function getGroupName():
string {
78 $request = $this->getRequest();
79 $user = $this->getUser();
80 $this->addHelpLink(
'Help:Extension:Translate/Move_translatable_page' );
81 $out = $this->getOutput();
82 $out->addModuleStyles(
'ext.translate.special.movetranslatablebundles.styles' );
84 $this->oldText = $request->getText(
86 $request->getText(
'target', $par ??
'' )
88 $newText = $request->getText(
'wpNewTitle' );
90 $this->oldTitle = Title::newFromText( $this->oldText );
91 $newTitle = Title::newFromText( $newText );
93 if ( $this->oldTitle ) {
94 $this->oldText = $this->oldTitle->getPrefixedText();
97 $this->reason = $request->getText(
'reason' );
103 $bundle = $this->bundleFactory->getBundle( $this->oldTitle );
104 if ( $bundle && $bundle->isMoveable() ) {
105 $this->getOutput()->setPageTitleMsg( $this->getSpecialPageTitle( $bundle ) );
107 if ( !$user->isAllowed(
'pagetranslation' ) ) {
108 throw new PermissionsError(
'pagetranslation' );
111 $subaction = $this->getSubactionFromRequest( $request->getText(
'subaction' ) );
113 $isValidPostRequest = $this->
checkToken() && $request->wasPosted();
114 if ( $isValidPostRequest && $subaction ===
'check' ) {
116 $pageCollection = $this->bundleMover->getPageMoveCollection(
122 $this->moveTalkpages,
132 } elseif ( $isValidPostRequest && $subaction ===
'perform' ) {
133 $this->moveSubpages = $request->getBool(
'subpages' );
134 $this->moveTalkpages = $request->getBool(
'talkpages' );
135 $this->leaveRedirect = $request->getBool(
'redirect' );
140 $this->bundleMover->moveAsynchronously(
146 $this->moveTalkpages,
149 $this->getOutput()->addWikiMsg(
150 'pt-movepage-started',
151 $this->getLogPageWikiLink( $this->bundleFactory->getValidBundle( $this->oldTitle ) )
158 $sp = $this->objectFactory->createObject( $this->movePageSpec );
159 $sp->execute( $par );
169 $this->checkReadOnly();
171 if ( $this->oldTitle ===
null ) {
172 throw new ErrorPageError(
'notargettitle',
'notargettext' );
175 if ( !$this->oldTitle->exists() ) {
176 throw new ErrorPageError(
'nopagetitle',
'nopagetext' );
180 $status = PermissionStatus::newEmpty();
181 if ( !$this->getAuthority()
182 ->definitelyCan(
'move', $this->oldTitle, $status )
184 throw new PermissionsError(
'move', $status );
190 $status = PermissionStatus::newEmpty();
191 $this->getAuthority()
192 ->authorizeWrite(
'move', $this->oldTitle, $status );
194 if ( !$status->isOK() ) {
195 if ( $status->isRateLimitExceeded() ) {
196 throw new ThrottledError;
198 throw new PermissionsError(
'move', $status );
205 return $this->getContext()->getCsrfTokenSet()->matchTokenField(
'wpEditToken' );
209 protected function showErrors( SplObjectStorage $errors ): void {
212 $context =
'pt-movepage-error-placeholder';
213 foreach ( $errors as $title ) {
214 $titleText = $title->getPrefixedText();
215 $s .=
"'''$titleText'''\n\n";
216 $s .= $errors[ $title ]->getWikiText(
false, $context );
219 $out = $this->getOutput();
223 'pt-movepage-blockers',
224 $this->getLanguage()->formatNum( count( $errors ) )
226 $out->parseAsContent( $s )
233 $this->getOutput()->addBacklinkSubtitle( $this->oldTitle );
234 $this->getOutput()->addWikiMsg(
236 $this->getLogPageWikiLink(
237 $this->bundleFactory->getBundle( Title::newFromText( $this->oldText ) )
241 HTMLForm::factory(
'ooui', $this->getCommonFormFields(), $this->getContext() )
242 ->setMethod(
'post' )
243 ->setAction( $this->getPageTitle( $this->oldText )->getLocalURL() )
244 ->setSubmitName(
'subaction' )
245 ->setSubmitTextMsg(
'pt-movepage-action-check' )
246 ->setWrapperLegendMsg(
247 $bundle instanceof
MessageBundle ?
'pt-movepage-messagebundle-legend' :
'pt-movepage-legend'
250 ->displayForm(
false );
258 $out = $this->getOutput();
259 $out->addBacklinkSubtitle( $this->oldTitle );
262 $this->getLogPageWikiLink(
263 $this->bundleFactory->getBundle( Title::newFromText( $this->oldText ) )
273 'pt-movepage-list-source' => [ $pageCollection->getTranslatablePage() ],
280 $pagesToMove[
'pt-movepage-list-other'] = $subpages;
283 $out->wrapWikiMsg(
'== $1 ==', [
'pt-movepage-list-pages' ] );
285 foreach ( $pagesToMove as $type => $pages ) {
286 $this->addSectionHeaderAndMessage( $out, $type, $pages );
294 foreach ( $pages as $pagePairs ) {
297 if ( $type ===
'pt-movepage-list-other' ) {
301 $old = $pagePairs->getOldTitle();
302 $new = $pagePairs->getNewTitle();
303 $line =
'* ' . $old->getPrefixedText() .
' → ' . $new->getPrefixedText();
304 if ( $pagePairs->hasTalkpage() ) {
307 $line .=
' ' . $this->msg(
'pt-movepage-talkpage-exists' )->text();
313 $out->addWikiTextAsInterface( implode(
"\n", $lines ) );
317 if ( $nonMovableSubpages ) {
318 $this->addSectionHeaderAndMessage( $out,
'pt-movepage-list-nonmovable', $nonMovableSubpages );
320 $out->wrapWikiMsg(
"'''$1'''", $this->msg(
'pt-movepage-list-nonmovable-note' ) );
321 foreach ( $nonMovableSubpages as $page => $status ) {
322 $invalidityReason = $this->formatterFactory
323 ->getStatusFormatter( $this->getContext() )
324 ->getWikiText( $status );
325 $lines[] =
'* ' . $page .
' (' . str_replace(
"\n",
" ", $invalidityReason ) .
')';
328 $out->addWikiTextAsInterface( implode(
"\n", $lines ) );
332 $sectionType =
'pt-movepage-list-translatable';
333 $this->addSectionHeaderAndMessage( $out, $sectionType, $translatableSubpages );
334 if ( $translatableSubpages ) {
336 $out->wrapWikiMsg(
"'''$1'''", $this->msg(
'pt-movepage-list-translatable-note' ) );
337 foreach ( $translatableSubpages as $page ) {
338 $lines[] =
'* ' . $page->getPrefixedText();
340 $out->addWikiTextAsInterface( implode(
"\n", $lines ) );
343 $out->addWikiTextAsInterface(
"----\n" );
345 'pt-movepage-list-count',
346 $this->getLanguage()->formatNum( $count ),
347 $this->getLanguage()->formatNum( $subpagesCount ),
348 $this->getLanguage()->formatNum( $talkpagesCount )
351 $formDescriptor = array_merge(
352 $this->getCommonFormFields(),
356 'name' =>
'subpages',
357 'id' =>
'mw-subpages',
358 'label-message' =>
'pt-movepage-subpages',
359 'default' => $this->moveSubpages && !count( $nonMovableSubpages ),
360 'disabled' => count( $nonMovableSubpages )
364 'name' =>
'redirect',
365 'id' =>
'mw-leave-redirect',
366 'label-message' =>
'pt-leave-redirect',
367 'default' => $this->leaveRedirect,
371 'name' =>
'talkpages',
372 'id' =>
'mw-talkpages',
373 'label-message' =>
'pt-movepage-talkpages',
374 'default' => $this->moveTalkpages
379 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->getContext() );
382 'name' =>
'subaction',
383 'value' => $this->msg(
'pt-movepage-action-other' )->text(),
385 ->setMethod(
'post' )
386 ->setAction( $this->getPageTitle( $this->oldText )->getLocalURL() )
387 ->setSubmitName(
'subaction' )
388 ->setSubmitTextMsg(
'pt-movepage-action-perform' )
389 ->setWrapperLegendMsg(
390 $bundle instanceof MessageBundle ?
'pt-movepage-messagebundle-legend' :
'pt-movepage-legend'
393 ->displayForm( false );
397 private function addSectionHeaderAndMessage( OutputPage $out,
string $type, array $pages ): void {
398 $leaveRedirect = TranslatableBundleMover::shouldLeaveRedirect( $type, $this->leaveRedirect );
400 $pageCount = count( $pages );
401 if ( $leaveRedirect ) {
402 $headingRedirectLabel = $this->msg(
403 'pt-leave-redirect-label',
404 $this->msg( $type, $pageCount )->text()
406 $out->addWikiTextAsInterface(
"<h3 class=\"mw-translate-leave-redirect\">$headingRedirectLabel</h3>" );
408 $out->wrapWikiMsg(
'=== $1 ===', [ $type, $pageCount ] );
412 $out->addWikiMsg(
'pt-movepage-list-no-pages' );
416 private function getSubactionFromRequest(
string $subactionText ): string {
417 switch ( $subactionText ) {
418 case $this->msg(
'pt-movepage-action-check' )->text():
420 case $this->msg(
'pt-movepage-action-perform' )->text():
422 case $this->msg(
'pt-movepage-action-other' )->text():
429 private function getCommonFormFields(): array {
433 'name' =>
'wpOldTitle',
434 'label-message' =>
'pt-movepage-current',
435 'default' => $this->oldText,
440 'name' =>
'wpNewTitle',
441 'label-message' =>
'pt-movepage-new',
446 'label-message' =>
'pt-movepage-reason',
447 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
448 'default' => $this->reason,
452 'name' =>
'redirect',
453 'id' =>
'mw-leave-redirect',
454 'label-message' =>
'pt-leave-redirect',
455 'default' => $this->leaveRedirect,
459 'name' =>
'subpages',
460 'default' => $this->moveSubpages,
464 'name' =>
'talkpages',
465 'default' => $this->moveTalkpages
470 private function getSpecialPageTitle( TranslatableBundle $bundle ): Message {
471 if ( $bundle instanceof TranslatablePage ) {
472 return $this->msg(
'pt-movepage-title', $this->oldText );
473 } elseif ( $bundle instanceof MessageBundle ) {
474 return $this->msg(
'pt-movepage-messagebundle-title', $this->oldText );
477 throw new InvalidArgumentException(
'TranslatableBundle is neither a TranslatablePage or MessageBundle' );
480 private function getLogPageWikiLink( ?TranslatableBundle $bundle ): string {
481 if ( $bundle instanceof MessageBundle ) {
482 return 'Special:Log/messagebundle';
486 return 'Special:Log/pagetranslation';
return[ 'Translate:AggregateGroupManager'=> static function(MediaWikiServices $services):AggregateGroupManager { return new AggregateGroupManager( $services->getTitleFactory());}, '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( 'Translate.GroupSynchronization'), $services->get( 'Translate:MessageIndex'), $services->getTitleFactory(), 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: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->getDBLoadBalancer());}, 'Translate:MessageGroupReviewStore'=> static function(MediaWikiServices $services):MessageGroupReviewStore { return new MessageGroupReviewStore($services->getDBLoadBalancer(), $services->get( 'Translate:HookRunner'));}, 'Translate:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getDBLoadBalancer(), $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( 'Translate.MessageGroupSubscription'), 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->getDBLoadBalancerFactory());}, '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( 'Translate'), $services->getMainObjectStash(), $services->getDBLoadBalancerFactory(), $services->get( 'Translate:MessageGroupSubscription'), 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->getDBLoadBalancer(), $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->getDBLoadBalancer());}, '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->getDBLoadBalancer());}, '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());}, '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->getDBLoadBalancerFactory(), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getDBLoadBalancer() ->getConnection(DB_PRIMARY), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, 'Translate:TranslatablePageMarker'=> static function(MediaWikiServices $services):TranslatablePageMarker { return new TranslatablePageMarker($services->getDBLoadBalancer(), $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'));}, '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->getDBLoadBalancer(), $services->get( 'Translate:TranslatableBundleStatusStore'), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:TranslatablePageView'=> static function(MediaWikiServices $services):TranslatablePageView { return new TranslatablePageView($services->getDBLoadBalancerFactory(), $services->get( 'Translate:TranslatablePageStateStore'), new ServiceOptions(TranslatablePageView::SERVICE_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslateSandbox'=> static function(MediaWikiServices $services):TranslateSandbox { return new TranslateSandbox($services->getUserFactory(), $services->getDBLoadBalancer(), $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 { $db=$services->getDBLoadBalancer() ->getConnection(DB_REPLICA);return new TranslationStashStorage( $db);}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory(), $services->getDBLoadBalancer());}, '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