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 MediaWiki\Context\RequestContext;
10use MediaWiki\Language\FormatterFactory;
11use MediaWiki\MediaWikiServices;
12use MediaWiki\Message\Message;
13use MediaWiki\Status\Status;
14use MediaWiki\Title\MalformedTitleException;
15use MediaWiki\Title\Title;
16use MediaWiki\Title\TitleParser;
17use SplObjectStorage;
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 $reason = $this->formatterFactory
186 ->getStatusFormatter( RequestContext::getMain() )
187 ->getWikiText( $status );
188 $this->output( "$progressCounter Failed to move $previousTitleText to $newTitleText\n" );
189 $this->output( "\tReason: $reason\n" );
190 }
191 }
192
193 private function displayPagesToMove( PageMoveCollection $pageCollection, bool $leaveRedirect ): void {
194 $infoMessage = "\nThe following pages will be moved:\n";
195 $count = 0;
196 $subpagesCount = 0;
197 $talkpagesCount = 0;
198
200 $pagesToMove = [
201 'pt-movepage-list-source' => [ $pageCollection->getTranslatablePage() ],
202 'pt-movepage-list-translation' => $pageCollection->getTranslationPagesPair(),
203 'pt-movepage-list-section' => $pageCollection->getUnitPagesPair()
204 ];
205
206 $subpages = $pageCollection->getSubpagesPair();
207 if ( $subpages ) {
208 $pagesToMove[ 'pt-movepage-list-other'] = $subpages;
209 }
210
211 foreach ( $pagesToMove as $type => $pages ) {
212 $lines = [];
213 $infoMessage .= $this->getSectionHeader( $type, $pages, $leaveRedirect );
214 if ( !count( $pages ) ) {
215 continue;
216 }
217
218 foreach ( $pages as $pagePairs ) {
219 $count++;
220
221 if ( $type === 'pt-movepage-list-other' ) {
222 $subpagesCount++;
223 }
224
225 $old = $pagePairs->getOldTitle();
226 $new = $pagePairs->getNewTitle();
227
228 if ( $new ) {
229 $line = '* ' . $old->getPrefixedText() . ' → ' . $new->getPrefixedText();
230 if ( $pagePairs->hasTalkpage() ) {
231 $count++;
232 $talkpagesCount++;
233 $line .= ' ' . $this->message( 'pt-movepage-talkpage-exists' )->text();
234 }
235
236 $lines[] = $line;
237 }
238 }
239
240 $infoMessage .= implode( "\n", $lines ) . "\n";
241 }
242
243 $translatableSubpages = $pageCollection->getTranslatableSubpages();
244 $infoMessage .= $this->getSectionHeader(
245 'pt-movepage-list-translatable', $translatableSubpages, $leaveRedirect
246 );
247
248 if ( $translatableSubpages ) {
249 $lines = [];
250 $infoMessage .= $this->message( 'pt-movepage-list-translatable-note' )->text() . "\n";
251 foreach ( $translatableSubpages as $page ) {
252 $lines[] = '* ' . $page->getPrefixedText();
253 }
254
255 $infoMessage .= implode( "\n", $lines ) . "\n";
256 }
257
258 $nonMovableSubpages = $pageCollection->getNonMovableSubpages();
259 if ( $nonMovableSubpages ) {
260 $lines = [];
261 $infoMessage .= $this->getSectionHeader(
262 'pt-movepage-list-nonmovable', $nonMovableSubpages, $leaveRedirect
263 );
264 $infoMessage .= $this->message( 'pt-movepage-list-nonmovable-note' )
265 ->numParams( count( $nonMovableSubpages ) )->text() . "\n";
266 foreach ( $nonMovableSubpages as $page => $status ) {
267 $invalidityReason = $this->formatterFactory
268 ->getStatusFormatter( RequestContext::getMain() )
269 ->getWikiText( $status );
270 $lines[] = '* ' . $page . ' (' . str_replace( "\n", " ", $invalidityReason ) . ')';
271 }
272
273 $infoMessage .= implode( "\n", $lines ) . "\n";
274 }
275
276 $this->output( $infoMessage );
277
278 $this->logSeparator();
279 $this->output(
280 $this->message( 'pt-movepage-list-count' )
281 ->numParams( $count, $subpagesCount, $talkpagesCount )
282 ->text() . "\n"
283 );
284 $this->logSeparator();
285 $this->output( "\n" );
286 }
287
288 private function getSectionHeader( string $type, array $pages, bool $leaveRedirect ): string {
289 $infoMessage = $this->getSeparator();
290 $pageCount = count( $pages );
291 $shouldRedirect = TranslatableBundleMover::shouldLeaveRedirect( $type, $leaveRedirect );
292
293 // $type can be: pt-movepage-list-source, pt-movepage-list-translation, pt-movepage-list-section
294 // pt-movepage-list-other
295 $infoMessage .= $this->message( $type )->numParams( $pageCount )->text() . ' ';
296
297 if ( $shouldRedirect ) {
298 $infoMessage .= '(leave redirect)';
299 }
300
301 $infoMessage .= "\n\n";
302
303 if ( !$pageCount ) {
304 $infoMessage .= $this->message( 'pt-movepage-list-no-pages' )->text() . "\n";
305 }
306
307 return $infoMessage;
308 }
309
310 private function getConfirmation(): bool {
311 $line = self::readconsole( 'Type "MOVE" to begin the move operation: ' );
312 return strtolower( $line ) === 'move';
313 }
314
315 private function getSeparator( int $width = 15 ): string {
316 return str_repeat( '-', $width ) . "\n";
317 }
318
319 private function logSeparator( int $width = 15 ): void {
320 $this->output( $this->getSeparator( $width ) );
321 }
322
323 private function message( string $key ): Message {
324 return ( new Message( $key ) )->inLanguage( 'en' );
325 }
326
327 private function getTitleFromInput( string $pageName ): Title {
328 $titleValue = $this->titleParser->parseTitle( $pageName );
329 return Title::newFromLinkTarget( $titleValue );
330 }
331}
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
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:59
Base maintenance script containing constants and methods used in multiple scripts Hopefully the const...