Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MoveTranslatableBundleMaintenanceScript.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\PageTranslation;
5
6use Closure;
7use MalformedTitleException;
10use MediaWiki\Language\FormatterFactory;
11use MediaWiki\MediaWikiServices;
12use MediaWiki\Status\Status;
13use MediaWiki\Title\Title;
14use Message;
15use RequestContext;
16use SplObjectStorage;
17use TitleParser;
18
20 private TranslatableBundleMover $bundleMover;
21 private TitleParser $titleParser;
22 private FormatterFactory $formatterFactory;
23
24 public function __construct() {
25 parent::__construct();
26 $this->addDescription( 'Review and move translatable bundles including their subpages' );
27
28 $this->addArg(
29 'current-page',
30 ' Current name of the page representing a translatable bundle',
31 self::REQUIRED
32 );
33
34 $this->addArg(
35 'new-page',
36 'New translatable bundle name',
37 self::REQUIRED
38 );
39
40 $this->addArg(
41 'user',
42 'User performing the move',
43 self::REQUIRED
44 );
45
46 $this->addOption(
47 'reason',
48 'Reason for moving the translatable bundle',
49 self::OPTIONAL,
50 self::HAS_ARG
51 );
52
53 $this->addOption(
54 'skip-redirect',
55 'Skip leaving a redirect behind for translatable bundle, subpages and related talk pages',
56 );
57
58 $this->addOption(
59 'skip-subpages',
60 'Skip moving subpages under the current page'
61 );
62
63 $this->addOption(
64 'skip-talkpages',
65 'Skip moving talk pages under pages being moved'
66 );
67
68 $this->requireExtension( 'Translate' );
69 }
70
72 public function execute() {
73 $this->bundleMover = Services::getInstance()->getTranslatableBundleMover();
74
75 $mwService = MediaWikiServices::getInstance();
76 $this->titleParser = $mwService->getTitleParser();
77 $this->formatterFactory = $mwService->getFormatterFactory();
78
79 $currentBundleName = $this->getArg( 0 );
80 $newBundleName = $this->getArg( 1 );
81 $username = $this->getArg( 2 );
82 $reason = $this->getOption( 'reason', '' );
83 $leaveRedirect = !$this->hasOption( 'skip-redirect' );
84 $moveSubpages = !$this->hasOption( 'skip-subpages' );
85 $moveTalkpages = !$this->hasOption( 'skip-talkpages' );
86
87 $userFactory = $mwService->getUserFactory();
88 $user = $userFactory->newFromName( $username );
89
90 if ( $user === null || !$user->isRegistered() ) {
91 $this->fatalError( "User $username does not exist." );
92 }
93
94 $outputMsg = "Check if '$currentBundleName' can be moved to '$newBundleName'";
95 $subpageMsg = 'excluding subpages';
96 if ( $moveSubpages ) {
97 $subpageMsg = 'including subpages';
98 }
99
100 $talkpageMsg = 'excluding talkpages';
101 if ( $moveTalkpages ) {
102 $talkpageMsg = 'including talkpages';
103 }
104
105 $leaveRedirectMsg = 'without leaving redirects';
106 if ( $leaveRedirect ) {
107 $leaveRedirectMsg = 'leaving redirects';
108 }
109
110 $this->output( "$outputMsg ($subpageMsg; $talkpageMsg; $leaveRedirectMsg)\n" );
111
112 try {
113 $currentTitle = $this->getTitleFromInput( $currentBundleName ?? '' );
114 $newTitle = $this->getTitleFromInput( $newBundleName ?? '' );
115 } catch ( MalformedTitleException $e ) {
116 $this->error( 'Invalid title: current-bundle or new-bundle' );
117 $this->fatalError( $e->getMessageObject()->text() );
118 }
119
120 // When moving translatable bundles from script, remove all limits on the number of
121 // pages that can be moved
122 $this->bundleMover->disablePageMoveLimit();
123 try {
124 $pageCollection = $this->bundleMover->getPageMoveCollection(
125 $currentTitle,
126 $newTitle,
127 $user,
128 $reason,
129 $moveSubpages,
130 $moveTalkpages,
131 $leaveRedirect
132 );
133 } catch ( ImpossiblePageMove $e ) {
134 $fatalErrorMsg = $this->parseErrorMessage( $e->getBlockers() );
135 $this->fatalError( $fatalErrorMsg );
136 }
137
138 $this->displayPagesToMove( $pageCollection, $leaveRedirect );
139
140 $haveConfirmation = $this->getConfirmation();
141 if ( !$haveConfirmation ) {
142 $this->output( "Exiting...\n" );
143 return;
144 }
145
146 $this->output( "Starting page move\n" );
147 $pagesToMove = $pageCollection->getListOfPages();
148 $pagesToRedirect = $pageCollection->getListOfPagesToRedirect();
149
150 $this->bundleMover->moveSynchronously(
151 $currentTitle,
152 $newTitle,
153 $pagesToMove,
154 $pagesToRedirect,
155 $user,
156 $reason,
157 Closure::fromCallable( [ $this, 'progressCallback' ] )
158 );
159
160 $this->logSeparator();
161 $this->output( "Finished moving '$currentBundleName' to '$newBundleName' $subpageMsg\n" );
162 }
163
164 private function parseErrorMessage( SplObjectStorage $errors ): string {
165 $errorMsg = wfMessage( 'pt-movepage-blockers', count( $errors ) )->text() . "\n";
166 foreach ( $errors as $title ) {
167 $titleText = $title->getPrefixedText();
168 $errorMsg .= "$titleText\n";
169 $errorMsg .= $errors[ $title ]->getWikiText( false, 'pt-movepage-error-placeholder', 'en' );
170 $errorMsg .= "\n";
171 }
172
173 return $errorMsg;
174 }
175
176 private function progressCallback( Title $previous, Title $new, Status $status, int $total, int $processed ): void {
177 $previousTitleText = $previous->getPrefixedText();
178 $newTitleText = $new->getPrefixedText();
179 $paddedProcessed = str_pad( (string)$processed, strlen( (string)$total ), ' ', STR_PAD_LEFT );
180 $progressCounter = "($paddedProcessed/$total)";
181
182 if ( $status->isOK() ) {
183 $this->output( "$progressCounter $previousTitleText --> $newTitleText\n" );
184 } else {
185 $this->output( "$progressCounter Failed to move $previousTitleText to $newTitleText\n" );
186 $this->output( "\tReason:" . $status->getWikiText() . "\n" );
187 }
188 }
189
190 private function displayPagesToMove( PageMoveCollection $pageCollection, bool $leaveRedirect ): void {
191 $infoMessage = "\nThe following pages will be moved:\n";
192 $count = 0;
193 $subpagesCount = 0;
194 $talkpagesCount = 0;
195
197 $pagesToMove = [
198 'pt-movepage-list-source' => [ $pageCollection->getTranslatablePage() ],
199 'pt-movepage-list-translation' => $pageCollection->getTranslationPagesPair(),
200 'pt-movepage-list-section' => $pageCollection->getUnitPagesPair()
201 ];
202
203 $subpages = $pageCollection->getSubpagesPair();
204 if ( $subpages ) {
205 $pagesToMove[ 'pt-movepage-list-other'] = $subpages;
206 }
207
208 foreach ( $pagesToMove as $type => $pages ) {
209 $lines = [];
210 $infoMessage .= $this->getSectionHeader( $type, $pages, $leaveRedirect );
211 if ( !count( $pages ) ) {
212 continue;
213 }
214
215 foreach ( $pages as $pagePairs ) {
216 $count++;
217
218 if ( $type === 'pt-movepage-list-other' ) {
219 $subpagesCount++;
220 }
221
222 $old = $pagePairs->getOldTitle();
223 $new = $pagePairs->getNewTitle();
224
225 if ( $new ) {
226 $line = '* ' . $old->getPrefixedText() . ' → ' . $new->getPrefixedText();
227 if ( $pagePairs->hasTalkpage() ) {
228 $count++;
229 $talkpagesCount++;
230 $line .= ' ' . $this->message( 'pt-movepage-talkpage-exists' )->text();
231 }
232
233 $lines[] = $line;
234 }
235 }
236
237 $infoMessage .= implode( "\n", $lines ) . "\n";
238 }
239
240 $translatableSubpages = $pageCollection->getTranslatableSubpages();
241 $infoMessage .= $this->getSectionHeader(
242 'pt-movepage-list-translatable', $translatableSubpages, $leaveRedirect
243 );
244
245 if ( $translatableSubpages ) {
246 $lines = [];
247 $infoMessage .= $this->message( 'pt-movepage-list-translatable-note' )->text() . "\n";
248 foreach ( $translatableSubpages as $page ) {
249 $lines[] = '* ' . $page->getPrefixedText();
250 }
251
252 $infoMessage .= implode( "\n", $lines ) . "\n";
253 }
254
255 $nonMovableSubpages = $pageCollection->getNonMovableSubpages();
256 if ( $nonMovableSubpages ) {
257 $lines = [];
258 $infoMessage .= $this->getSectionHeader(
259 'pt-movepage-list-nonmovable', $nonMovableSubpages, $leaveRedirect
260 );
261 foreach ( $nonMovableSubpages as $page => $status ) {
262 $invalidityReason = $this->formatterFactory
263 ->getStatusFormatter( RequestContext::getMain() )
264 ->getWikiText( $status );
265 $lines[] = '* ' . $page . ' (' . str_replace( "\n", " ", $invalidityReason ) . ')';
266 }
267
268 $infoMessage .= implode( "\n", $lines ) . "\n";
269 }
270
271 $this->output( $infoMessage );
272
273 $this->logSeparator();
274 $this->output(
275 $this->message( 'pt-movepage-list-count' )
276 ->numParams( $count, $subpagesCount, $talkpagesCount )
277 ->text() . "\n"
278 );
279 $this->logSeparator();
280 $this->output( "\n" );
281 }
282
283 private function getSectionHeader( string $type, array $pages, bool $leaveRedirect ): string {
284 $infoMessage = $this->getSeparator();
285 $pageCount = count( $pages );
286 $shouldRedirect = TranslatableBundleMover::shouldLeaveRedirect( $type, $leaveRedirect );
287
288 // $type can be: pt-movepage-list-source, pt-movepage-list-translation, pt-movepage-list-section
289 // pt-movepage-list-other
290 $infoMessage .= $this->message( $type )->numParams( $pageCount )->text() . ' ';
291
292 if ( $shouldRedirect ) {
293 $infoMessage .= '(leave redirect)';
294 }
295
296 $infoMessage .= "\n\n";
297
298 if ( !$pageCount ) {
299 $infoMessage .= $this->message( 'pt-movepage-list-no-pages' )->text() . "\n";
300 }
301
302 return $infoMessage;
303 }
304
305 private function getConfirmation(): bool {
306 $line = self::readconsole( 'Type "MOVE" to begin the move operation: ' );
307 return strtolower( $line ) === 'move';
308 }
309
310 private function getSeparator( int $width = 15 ): string {
311 return str_repeat( '-', $width ) . "\n";
312 }
313
314 private function logSeparator( int $width = 15 ): void {
315 $this->output( $this->getSeparator( $width ) );
316 }
317
318 private function message( string $key ): Message {
319 return ( new Message( $key ) )->inLanguage( 'en' );
320 }
321
322 private function getTitleFromInput( string $pageName ): Title {
323 $titleValue = $this->titleParser->parseTitle( $pageName );
324 return Title::newFromLinkTarget( $titleValue );
325 }
326}
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
Exception thrown when a translatable page move is not possible.
Contains the core logic to validate and move translatable bundles.
Minimal service container.
Definition Services.php:58
Base maintenance script containing constants and methods used in multiple scripts Hopefully the const...