48 public const DISPLAY_TITLE_UNIT_ID =
'Page display title';
58 protected $pageDisplayTitle;
60 private $targetLanguage;
62 protected function __construct(
63 private readonly PageIdentity $page,
65 $this->revTagStore = Services::getInstance()->getRevTagStore();
73 public static function newFromText( PageIdentity $page,
string $text ): self {
74 $obj = new self( $page );
76 $obj->source =
'text';
86 public static function newFromRevision( PageIdentity $page,
int $revision ): self {
87 $rev = MediaWikiServices::getInstance()
89 ->getRevisionByTitle( $page, $revision );
90 if ( $rev ===
null ) {
91 throw new RuntimeException(
'Revision is null' );
94 $obj =
new self( $page );
95 $obj->source =
'revision';
96 $obj->revision = $revision;
106 $obj = new self( $page );
107 $obj->source =
'title';
114 return Title::newFromPageIdentity( $this->page );
117 public function getPageIdentity(): PageIdentity {
123 if ( $this->text !== null ) {
127 if ( $this->source ===
'title' ) {
128 $revision = $this->getMarkedTag();
129 if ( !is_int( $revision ) ) {
130 throw new LogicException(
131 "Trying to load a text for {$this->getPageIdentity()} which is not marked for translation"
134 $this->revision = $revision;
137 $flags = Utilities::shouldReadFromPrimary()
138 ? IDBAccessObject::READ_LATEST
139 : IDBAccessObject::READ_NORMAL;
140 $rev = MediaWikiServices::getInstance()
141 ->getRevisionLookup()
142 ->getRevisionByTitle( $this->getPageIdentity(), $this->revision, $flags );
143 $content = $rev->getContent( SlotRecord::MAIN );
144 $text = ( $content instanceof TextContent ) ? $content->getText() :
null;
146 if ( !is_string( $text ) ) {
147 throw new RuntimeException(
"Failed to load text for {$this->getPageIdentity()}" );
169 return $this->getTitle()->getPageLanguage()->getCode();
174 return self::getMessageGroupIdFromTitle( $this->getPageIdentity() );
179 return 'page-' . MediaWikiServices::getInstance()->getTitleFormatter()->getPrefixedText( $page );
187 $groupId = $this->getMessageGroupId();
188 $group = MessageGroups::getGroup( $groupId );
193 throw new RuntimeException(
194 "Expected $groupId to be of type WikiPageMessageGroup; got " .
202 if ( $this->pageDisplayTitle !== null ) {
203 return $this->pageDisplayTitle;
207 $factory = Services::getInstance()->getTranslationUnitStoreFactory();
208 $store = $factory->getReader( $this->getPageIdentity() );
209 $this->pageDisplayTitle = in_array( self::DISPLAY_TITLE_UNIT_ID, $store->getNames() );
211 return $this->pageDisplayTitle;
217 if ( !$this->hasPageDisplayTitle() ) {
222 $section = str_replace(
' ',
'_', self::DISPLAY_TITLE_UNIT_ID );
223 $page = MediaWikiServices::getInstance()->getTitleFormatter()->getPrefixedDBkey( $this->getPageIdentity() );
226 $group = $this->getMessageGroup();
227 }
catch ( RuntimeException ) {
236 return $group->getMessage(
"$page/$section", $languageCode, IDBAccessObject::READ_NORMAL );
239 public function getStrippedSourcePageText(): string {
240 $parser = Services::getInstance()->getTranslatablePageParser();
241 $text = $parser->cleanupTags( $this->getText() );
242 $text = preg_replace(
'~<languages\s*/>\n?~s',
'', $text );
247 public static function getTranslationPageFromTitle( Title $title ): ?TranslationPage {
248 $self = self::isTranslationPage( $title );
249 return $self ? $self->getTranslationPage( $self->targetLanguage ) :
null;
252 public function getTranslationPage(
string $targetLanguage ): TranslationPage {
254 $this->getMessageGroupId(),
258 $mwServices = MediaWikiServices::getInstance();
259 $config = $mwServices->getMainConfig();
260 $services = Services::getInstance();
261 $parser = $services->getTranslatablePageParser();
262 $parserOutput = $parser->parse( $this->getText() );
263 $pageVersion = (int)$services->getMessageGroupMetadata()
264 ->get( $this->getMessageGroupId(),
'version' );
265 $wrapUntranslated = $pageVersion >= 2;
266 $languageFactory = $mwServices->getLanguageFactory();
268 return new TranslationPage(
271 $languageFactory->getLanguage( $targetLanguage ),
272 $languageFactory->getLanguage( $this->getSourceLanguageCode() ),
273 $config->get(
'TranslateKeepOutdatedTranslations' ),
281 $this->revTagStore->replaceTag( $this->getPageIdentity(), RevTagStore::TP_MARK_TAG, $revision, $value );
282 self::clearSourcePageCache();
287 $this->revTagStore->replaceTag( $this->getPageIdentity(),
RevTagStore::TP_READY_TAG, $revision );
288 if ( !self::isSourcePage( $this->getPageIdentity() ) ) {
289 self::clearSourcePageCache();
295 return $this->revTagStore->getLatestRevisionWithTag( $this->getPageIdentity(),
RevTagStore::TP_MARK_TAG );
300 return $this->revTagStore->getLatestRevisionWithTag( $this->getPageIdentity(),
RevTagStore::TP_READY_TAG );
310 'group' => $this->getMessageGroupId(),
316 $translate = SpecialPage::getTitleFor(
'Translate' );
318 return $translate->getLocalURL( $params );
323 $mwServices = MediaWikiServices::getInstance();
325 $knownLanguageCodes = $this->getMessageGroup()?->getTranslatableLanguages() ??
326 Utilities::getLanguageNames( LanguageNameUtils::AUTONYMS );
328 $prefixedDbTitleKey = $this->getPageIdentity()->getDBkey() .
'/';
329 $baseNamespace = $this->getPageIdentity()->getNamespace();
332 $linkBatch = $mwServices->getLinkBatchFactory()->newLinkBatch();
333 foreach ( array_keys( $knownLanguageCodes ) as $code ) {
334 $linkBatch->add( $baseNamespace, $prefixedDbTitleKey . $code );
337 $translationPages = [];
338 foreach ( $linkBatch->getPageIdentities() as $pageIdentity ) {
339 if ( $pageIdentity->exists() ) {
340 $translationPages[] = Title::newFromPageIdentity( $pageIdentity );
344 return $translationPages;
349 return $this->getTranslationUnitPagesByTitle( $this->page, $code );
352 public function getTranslationPercentages(): array {
355 $group = $this->getMessageGroup();
356 }
catch ( RuntimeException ) {
364 $titles = $this->getTranslationPages();
365 $temp = MessageGroupStats::forGroup( $this->getMessageGroupId(), MessageGroupStats::FLAG_CACHE_ONLY );
368 foreach ( $titles as $t ) {
369 $handle =
new MessageHandle( $t );
370 $code = $handle->getCode();
374 $stats[$code] = 0.00;
375 if ( ( $temp[$code][MessageGroupStats::TOTAL] ?? 0 ) > 0 ) {
376 $total = $temp[$code][MessageGroupStats::TOTAL];
377 $translated = $temp[$code][MessageGroupStats::TRANSLATED];
378 $percentage = $translated / $total;
379 $stats[$code] = sprintf(
'%.2f', $percentage );
384 $stats[$this->getSourceLanguageCode()] = 1.00;
389 public function supportsTransclusion(): ?bool {
390 $transclusion = Services::getInstance()
391 ->getMessageGroupMetadata()
392 ->get( $this->getMessageGroupId(),
'transclusion' );
393 if ( $transclusion ===
false ) {
397 return $transclusion ===
'1';
400 public function getRevisionRecordWithFallback(): ?RevisionRecord {
401 $title = $this->getTitle();
402 $store = MediaWikiServices::getInstance()->getRevisionStore();
403 $revRecord = $store->getRevisionByTitle( $title->getSubpage( $this->targetLanguage ) );
409 return $store->getRevisionByTitle( $title->getSubpage( $this->getSourceLanguageCode() ) );
414 return $this->getMarkedTag() !== null;
419 return $this->getMarkedTag() !== null;
425 if ( !Utilities::isTranslationPage( $handle ) ) {
429 $languageCode = $handle->getCode();
430 $newTitle = $handle->getTitleForBase();
432 $page = self::newFromTitle( $newTitle );
434 if ( $page->getMarkedTag() ===
null ) {
438 $page->targetLanguage = $languageCode;
447 $parts = explode(
'/', $translationUnit->getText() );
450 $language = array_pop( $parts );
451 $section = array_pop( $parts );
452 $sourcepage = implode(
'/', $parts );
455 'sourcepage' => $sourcepage,
456 'section' => $section,
457 'language' => $language
461 public static function isSourcePage( PageIdentity $page ): bool {
462 if ( !$page->exists() ) {
470 $localCache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
471 $localKey = $localCache->makeKey(
'pagetranslation',
'sourcepages',
'local' );
474 $translatablePageIds = $localCache->getWithSetCallback(
476 $localCache::TTL_SECOND * 8,
478 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
479 $cacheKey = $cache->makeKey(
'pagetranslation',
'sourcepages' );
481 return $cache->getWithSetCallback(
483 $cache::TTL_HOUR * 2,
484 [ TranslatablePage::class,
'getCacheValue' ],
486 'checkKeys' => [ $cacheKey ],
487 'pcTTL' => $cache::TTL_PROC_SHORT,
488 'pcGroup' => __CLASS__ .
':1',
493 $localCache::READ_LATEST
496 return str_contains( $translatablePageIds, (
',' . $page->getId() .
',' ) );
499 public function isBroken(): bool {
500 $marked = $this->getMarkedTag();
501 $ready = $this->getReadyTag();
502 $latest = $this->getTitle()->getLatestRevID();
503 return $marked !==
null && $marked !== $latest && $ready !== $latest;
508 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
509 $cache->touchCheckKey( $cache->makeKey(
'pagetranslation',
'sourcepages' ) );
512 public static function determineStatus(
513 ?
int $readyRevisionId,
514 ?
int $markRevisionId,
515 int $latestRevisionId
518 if ( $markRevisionId ===
null ) {
520 if ( $readyRevisionId === $latestRevisionId ) {
521 $status = TranslatablePageStatus::PROPOSED;
526 } elseif ( $readyRevisionId === $latestRevisionId ) {
527 if ( $markRevisionId === $readyRevisionId ) {
529 $status = TranslatablePageStatus::ACTIVE;
531 $status = TranslatablePageStatus::OUTDATED;
535 $status = TranslatablePageStatus::BROKEN;
538 return new TranslatablePageStatus( $status );
556 return ',' . implode(
',', $ids ) .
',';
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(), $services->getContentLanguageCode() ->toString(), 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 { if(! $services->getExtensionRegistry() ->isLoaded( 'Echo')) { return null;} 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(), $services->get( 'Translate:HookRunner'),);}, '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->getConnectionProvider());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);}, 'Translate:WorkflowStatesMessageGroupLoader'=> static function(MediaWikiServices $services):WorkflowStatesMessageGroupLoader { return new WorkflowStatesMessageGroupLoader(new ServiceOptions(WorkflowStatesMessageGroupLoader::CONSTRUCTOR_OPTIONS, $services->getMainConfig()),);},]
@phpcs-require-sorted-array