36 private const TABLE =
'translate_groupstats';
38 private const LANGUAGE_STATS_KEY =
'translate-all-language-stats';
53 private static array $updates = [];
55 private static ?array $languages =
null;
69 private static function getUnknownStats(): array {
70 return [ null, null, null, null ];
73 private static function isValidLanguage(
string $languageCode ): bool {
74 $languages = self::getLanguages();
75 return in_array( $languageCode, $languages );
82 private static function isValidMessageGroup( ?
MessageGroup $group ): bool {
83 return $group && !MessageGroups::isDynamic( $group );
93 public static function forItem(
string $groupId,
string $languageCode,
int $flags = 0 ): array {
95 if ( !self::isValidMessageGroup( $group ) || !self::isValidLanguage( $languageCode ) ) {
96 return self::getUnknownStats();
99 $res = self::selectRowsIdLang( [ $groupId ], [ $languageCode ], $flags );
100 $stats = self::extractResults( $res, [ $groupId ] );
102 if ( !isset( $stats[$groupId][$languageCode] ) ) {
103 $stats[$groupId][$languageCode] = self::forItemInternal( $stats, $group, $languageCode, $flags );
106 self::queueUpdates( $flags );
108 return $stats[$groupId][$languageCode];
117 public static function forLanguage(
string $languageCode,
int $flags = 0 ): array {
118 if ( !self::isValidLanguage( $languageCode ) ) {
120 $groups = MessageGroups::singleton()->getGroups();
121 $ids = array_keys( $groups );
122 foreach ( $ids as $id ) {
123 $stats[$id] = self::getUnknownStats();
129 $stats = self::forLanguageInternal( $languageCode, [], $flags );
131 foreach ( $stats as $group => $languages ) {
132 $flattened[$group] = $languages[$languageCode];
135 self::queueUpdates( $flags );
148 $group = MessageGroups::getGroup( $group );
151 if ( !self::isValidMessageGroup( $group ) ) {
152 return array_fill_keys( self::getLanguages(), self::getUnknownStats() );
155 $stats = self::forGroupInternal( $group, [], $flags );
157 self::queueUpdates( $flags );
159 return $stats[$group->getId()];
168 $code = $handle->getCode();
169 if ( !self::isValidLanguage( $code ) ) {
172 $groups = self::getSortedGroupsForClearing( $handle->
getGroupIds() );
173 self::internalClearGroups( $code, $groups, 0 );
182 public static function clearGroup( $id,
int $flags = 0 ): void {
183 $languages = self::getLanguages();
184 $groups = self::getSortedGroupsForClearing( (array)$id );
187 foreach ( $languages as $code ) {
188 self::internalClearGroups( $code, $groups, $flags );
199 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
200 return $cache->getWithSetCallback(
201 self::LANGUAGE_STATS_KEY,
202 WANObjectCache::TTL_INDEFINITE,
203 function ( $oldValue, &$ttl, array &$setOpts ) {
204 $dbr = Utilities::getSafeReadDB();
205 $setOpts += Database::getCacheSetOptions( $dbr );
207 return self::getAllLanguageStats();
210 'checkKeys' => [ self::LANGUAGE_STATS_KEY ],
211 'pcTTL' => $cache::TTL_PROC_SHORT,
216 private static function getAllLanguageStats(): array {
218 $res = $dbr->newSelectQueryBuilder()
219 ->table( self::TABLE )
222 'tgs_translated' =>
'SUM(tgs_translated)',
223 'tgs_fuzzy' =>
'SUM(tgs_fuzzy)',
224 'tgs_total' =>
'SUM(tgs_total)',
225 'tgs_proofread' =>
'SUM(tgs_proofread)'
227 ->groupBy(
'tgs_lang' )
228 ->caller( __METHOD__ )
232 $languagesCodes = array_flip( self::getLanguages() );
235 foreach ( $res as $row ) {
236 $allStats[ $row->tgs_lang ] = self::extractNumbers( $row );
237 unset( $languagesCodes[ $row->tgs_lang ] );
241 foreach ( array_keys( $languagesCodes ) as $code ) {
242 $allStats[ $code ] = self::getEmptyStats();
254 private static function internalClearGroups(
string $code, array $groups,
int $flags ): void {
256 foreach ( $groups as $group ) {
258 self::forItemInternal( $stats, $group, $code, $flags );
260 self::queueUpdates( 0 );
273 private static function getSortedGroupsForClearing( array $ids ): array {
274 $groups = array_map( [ MessageGroups::class,
'getGroup' ], $ids );
276 $groups = array_filter( $groups );
280 foreach ( $groups as $group ) {
282 $aggregates[$group->getId()] = $group;
284 $sorted[$group->getId()] = $group;
288 return array_merge( $sorted, $aggregates );
296 if ( self::$languages === null ) {
297 $languages = array_keys( Utilities::getLanguageNames(
'en' ) );
299 self::$languages = $languages;
302 return self::$languages;
313 private static function extractResults( iterable $res, array $ids, array $stats = [] ): array {
315 $idMap = array_combine( array_map( [ self::class,
'getDatabaseIdForGroupId' ], $ids ), $ids );
317 foreach ( $res as $row ) {
318 if ( !isset( $idMap[$row->tgs_group] ) ) {
324 $realId = $idMap[$row->tgs_group];
325 $stats[$realId][$row->tgs_lang] = self::extractNumbers( $row );
332 private static function extractNumbers( stdClass $row ): array {
334 self::TOTAL => (int)$row->tgs_total,
335 self::TRANSLATED => (int)$row->tgs_translated,
336 self::FUZZY => (int)$row->tgs_fuzzy,
337 self::PROOFREAD => (int)$row->tgs_proofread,
347 private static function forLanguageInternal(
string $languageCode, array $stats,
int $flags ): array {
348 $groups = MessageGroups::singleton()->getGroups();
350 $ids = array_keys( $groups );
351 $res = self::selectRowsIdLang(
null, [ $languageCode ], $flags );
352 $stats = self::extractResults( $res, $ids, $stats );
354 foreach ( $groups as $id => $group ) {
355 if ( isset( $stats[$id][$languageCode] ) ) {
358 $stats[$id][$languageCode] = self::forItemInternal( $stats, $group, $languageCode, $flags );
368 foreach ( $agg->
getGroups() as $group ) {
370 $flattened += self::expandAggregates( $group );
372 $flattened[$group->getId()] = $group;
385 private static function forGroupInternal(
MessageGroup $group, array $stats,
int $flags ): array {
386 $id = $group->getId();
388 $res = self::selectRowsIdLang( [ $id ],
null, $flags );
389 $stats = self::extractResults( $res, [ $id ], $stats );
392 $languages = self::getLanguages();
393 foreach ( $languages as $code ) {
394 if ( isset( $stats[$id][$code] ) ) {
397 $stats[$id][$code] = self::forItemInternal( $stats, $group, $code, $flags );
401 foreach ( array_keys( $stats ) as $key ) {
402 ksort( $stats[$key] );
415 private static function selectRowsIdLang( ?array $ids, ?array $codes,
int $flags ): iterable {
416 if ( $flags & self::FLAG_NO_CACHE ) {
421 if ( $ids !==
null ) {
422 $dbids = array_map( [ self::class,
'getDatabaseIdForGroupId' ], $ids );
423 $conditions[
'tgs_group'] = $dbids;
426 if ( $codes !==
null ) {
427 $conditions[
'tgs_lang'] = $codes;
430 $dbr = Utilities::getSafeReadDB();
431 return $dbr->newSelectQueryBuilder()
433 ->from( self::TABLE )
434 ->where( $conditions )
435 ->caller( __METHOD__ )
446 private static function forItemInternal(
449 string $languageCode,
452 $id = $group->getId();
454 if ( $flags & self::FLAG_CACHE_ONLY ) {
455 $stats[$id][$languageCode] = self::getUnknownStats();
456 return $stats[$id][$languageCode];
464 $databaseGroupId = self::getDatabaseIdForGroupId( $id );
465 $uniqueKey =
"$databaseGroupId|$languageCode";
466 $queuedValue = self::$updates[$uniqueKey] ??
null;
467 if ( $queuedValue && !( $flags & self::FLAG_NO_CACHE ) ) {
469 self::TOTAL => $queuedValue[
'tgs_total'],
470 self::TRANSLATED => $queuedValue[
'tgs_translated'],
471 self::FUZZY => $queuedValue[
'tgs_fuzzy'],
472 self::PROOFREAD => $queuedValue[
'tgs_proofread'],
477 $aggregates = self::calculateAggregateGroup( $stats, $group, $languageCode, $flags );
479 $aggregates = self::calculateGroup( $group, $languageCode );
482 $stats[$id][$languageCode] = $aggregates;
485 if ( $aggregates[self::TOTAL] ===
null ) {
489 self::$updates[$uniqueKey] = [
490 'tgs_group' => $databaseGroupId,
491 'tgs_lang' => $languageCode,
492 'tgs_total' => $aggregates[self::TOTAL],
493 'tgs_translated' => $aggregates[self::TRANSLATED],
494 'tgs_fuzzy' => $aggregates[self::FUZZY],
495 'tgs_proofread' => $aggregates[self::PROOFREAD],
500 if ( count( self::$updates ) % 100 === 0 ) {
501 self::queueUpdates( $flags );
507 private static function calculateAggregateGroup(
513 $aggregates = self::getEmptyStats();
515 $expanded = self::expandAggregates( $group );
516 $subGroupIds = array_keys( $expanded );
519 foreach ( $subGroupIds as $index => $sid ) {
520 if ( isset( $stats[$sid][$code] ) ) {
521 unset( $subGroupIds[ $index ] );
525 if ( $subGroupIds !== [] ) {
526 $res = self::selectRowsIdLang( $subGroupIds, [ $code ], $flags );
527 $stats = self::extractResults( $res, $subGroupIds, $stats );
530 $messageGroupMetadata = Services::getInstance()->getMessageGroupMetadata();
531 foreach ( $expanded as $sid => $subgroup ) {
538 if ( !isset( $stats[$sid][$code] ) ) {
539 $stats[$sid][$code] = self::forItemInternal( $stats, $subgroup, $code, $flags );
542 if ( !$messageGroupMetadata->isExcluded( $sid, $code ) ) {
543 $aggregates = self::multiAdd( $aggregates, $stats[$sid][$code] );
550 public static function multiAdd( array $a, array $b ): array {
551 if ( $a[0] === null || $b[0] === null ) {
552 return array_fill( 0, count( $a ),
null );
554 foreach ( $a as $i => &$v ) {
566 private static function calculateGroup(
MessageGroup $group,
string $languageCode ): array {
567 global $wgTranslateDocumentationLanguageCode;
572 $languageCode === $wgTranslateDocumentationLanguageCode
576 if ( $cache->exists() ) {
577 $template = $cache->getExtra()[
'TEMPLATE'] ?? [];
579 foreach ( $template as $key => $data ) {
580 if ( isset( $data[
'comments'][
'.'] ) ) {
584 $collection->setInFile( $infile );
588 return self::getStatsForCollection( $collection );
591 private static function queueUpdates(
int $flags ): void {
592 $mwInstance = MediaWikiServices::getInstance();
593 if ( self::$updates === [] || $mwInstance->getReadOnlyMode()->isReadOnly() ) {
597 $dbw = $mwInstance->getConnectionProvider()->getPrimaryDatabase();
598 $callers = wfGetAllCallers( 50 );
599 $functionName = __METHOD__;
600 $callback =
static function ( IDatabase $dbw, $method ) use ( $callers, $mwInstance ) {
602 if ( count( self::$updates ) > 100 ) {
603 $groups = array_unique( array_column( self::$updates,
'tgs_group' ) );
604 LoggerFactory::getInstance( LogNames::MAIN )->warning(
605 "Huge translation update of {count} rows for group(s) {groups}",
607 'count' => count( self::$updates ),
608 'groups' => implode(
', ', $groups ),
609 'callers' => $callers,
614 $dbw->newReplaceQueryBuilder()
615 ->replaceInto( self::TABLE )
616 ->uniqueIndexFields( [
'tgs_group',
'tgs_lang' ] )
617 ->rows( array_values( self::$updates ) )
622 $mwInstance->getMainWANObjectCache()->touchCheckKey( self::LANGUAGE_STATS_KEY );
624 $updateOp =
static function () use ( $dbw, $functionName, $callback ) {
626 if ( self::$updates === [] ) {
630 $lockName =
'MessageGroupStats:updates';
631 if ( !$dbw->lock( $lockName, $functionName, 1 ) ) {
632 $groups = array_unique( array_column( self::$updates,
'tgs_group' ) );
633 LoggerFactory::getInstance( LogNames::MAIN )->warning(
634 'Message group stats update of {count} rows failed for group(s) {groups} due to lock',
636 'count' => count( self::$updates ),
637 'groups' => implode(
', ', $groups ),
644 $dbw->commit( $functionName,
'flush' );
645 $callback( $dbw, $functionName );
646 $dbw->commit( $functionName,
'flush' );
648 $dbw->unlock( $lockName, $functionName );
651 if ( $flags & self::FLAG_IMMEDIATE_WRITES ) {
654 DeferredUpdates::addCallableUpdate( $updateOp );
658 public static function getDatabaseIdForGroupId(
string $id ): string {
660 if ( strlen( $id ) <= 72 ) {
664 $hash = hash(
'sha256', $id,
false );
665 return substr( $id, 0, 50 ) .
'||' . substr( $hash, 0, 20 );
671 $collection->filterUntranslatedOptional();
673 $total = count( $collection );
676 $collection->
filter( MessageCollection::FILTER_FUZZY, MessageCollection::EXCLUDE_MATCHING );
677 $fuzzy = $total - count( $collection );
680 $collection->
filter( MessageCollection::FILTER_HAS_TRANSLATION, MessageCollection::INCLUDE_MATCHING );
681 $translated = count( $collection );
685 $collection->
filter( MessageCollection::FILTER_REVIEWER, MessageCollection::INCLUDE_MATCHING );
686 $proofread = count( $collection );
689 self::TOTAL => $total,
690 self::TRANSLATED => $translated,
691 self::FUZZY => $fuzzy,
692 self::PROOFREAD => $proofread,
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