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 );
146 public static function forGroup(
string $groupId,
int $flags = 0 ): array {
148 if ( !self::isValidMessageGroup( $group ) ) {
149 return array_fill_keys( self::getLanguages(), self::getUnknownStats() );
152 $stats = self::forGroupInternal( $group, [], $flags );
154 self::queueUpdates( $flags );
156 return $stats[$groupId];
165 $code = $handle->getCode();
166 if ( !self::isValidLanguage( $code ) ) {
169 $groups = self::getSortedGroupsForClearing( $handle->
getGroupIds() );
170 self::internalClearGroups( $code, $groups, 0 );
179 public static function clearGroup( $id,
int $flags = 0 ): void {
180 $languages = self::getLanguages();
181 $groups = self::getSortedGroupsForClearing( (array)$id );
184 foreach ( $languages as $code ) {
185 self::internalClearGroups( $code, $groups, $flags );
196 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
197 return $cache->getWithSetCallback(
198 self::LANGUAGE_STATS_KEY,
199 WANObjectCache::TTL_INDEFINITE,
200 function ( $oldValue, &$ttl, array &$setOpts ) {
201 $dbr = Utilities::getSafeReadDB();
202 $setOpts += Database::getCacheSetOptions( $dbr );
204 return self::getAllLanguageStats();
207 'checkKeys' => [ self::LANGUAGE_STATS_KEY ],
208 'pcTTL' => $cache::TTL_PROC_SHORT,
213 private static function getAllLanguageStats(): array {
215 $res = $dbr->newSelectQueryBuilder()
216 ->table( self::TABLE )
219 'tgs_translated' =>
'SUM(tgs_translated)',
220 'tgs_fuzzy' =>
'SUM(tgs_fuzzy)',
221 'tgs_total' =>
'SUM(tgs_total)',
222 'tgs_proofread' =>
'SUM(tgs_proofread)'
224 ->groupBy(
'tgs_lang' )
225 ->caller( __METHOD__ )
229 $languagesCodes = array_flip( self::getLanguages() );
232 foreach ( $res as $row ) {
233 $allStats[ $row->tgs_lang ] = self::extractNumbers( $row );
234 unset( $languagesCodes[ $row->tgs_lang ] );
238 foreach ( array_keys( $languagesCodes ) as $code ) {
239 $allStats[ $code ] = self::getEmptyStats();
251 private static function internalClearGroups(
string $code, array $groups,
int $flags ): void {
253 foreach ( $groups as $group ) {
255 self::forItemInternal( $stats, $group, $code, $flags );
257 self::queueUpdates( 0 );
270 private static function getSortedGroupsForClearing( array $ids ): array {
271 $groups = array_map( [ MessageGroups::class,
'getGroup' ], $ids );
273 $groups = array_filter( $groups );
277 foreach ( $groups as $group ) {
279 $aggregates[$group->getId()] = $group;
281 $sorted[$group->getId()] = $group;
285 return array_merge( $sorted, $aggregates );
293 if ( self::$languages === null ) {
294 $languages = array_keys( Utilities::getLanguageNames(
'en' ) );
296 self::$languages = $languages;
299 return self::$languages;
310 private static function extractResults( iterable $res, array $ids, array $stats = [] ): array {
312 $idMap = array_combine( array_map( [ self::class,
'getDatabaseIdForGroupId' ], $ids ), $ids );
314 foreach ( $res as $row ) {
315 if ( !isset( $idMap[$row->tgs_group] ) ) {
321 $realId = $idMap[$row->tgs_group];
322 $stats[$realId][$row->tgs_lang] = self::extractNumbers( $row );
329 private static function extractNumbers( stdClass $row ): array {
331 self::TOTAL => (int)$row->tgs_total,
332 self::TRANSLATED => (int)$row->tgs_translated,
333 self::FUZZY => (int)$row->tgs_fuzzy,
334 self::PROOFREAD => (int)$row->tgs_proofread,
344 private static function forLanguageInternal(
string $languageCode, array $stats,
int $flags ): array {
345 $groups = MessageGroups::singleton()->getGroups();
347 $ids = array_keys( $groups );
348 $res = self::selectRowsIdLang(
null, [ $languageCode ], $flags );
349 $stats = self::extractResults( $res, $ids, $stats );
351 foreach ( $groups as $id => $group ) {
352 if ( isset( $stats[$id][$languageCode] ) ) {
355 $stats[$id][$languageCode] = self::forItemInternal( $stats, $group, $languageCode, $flags );
365 foreach ( $agg->
getGroups() as $group ) {
367 $flattened += self::expandAggregates( $group );
369 $flattened[$group->getId()] = $group;
382 private static function forGroupInternal(
MessageGroup $group, array $stats,
int $flags ): array {
383 $id = $group->getId();
385 $res = self::selectRowsIdLang( [ $id ],
null, $flags );
386 $stats = self::extractResults( $res, [ $id ], $stats );
389 $languages = self::getLanguages();
390 foreach ( $languages as $code ) {
391 if ( isset( $stats[$id][$code] ) ) {
394 $stats[$id][$code] = self::forItemInternal( $stats, $group, $code, $flags );
398 foreach ( array_keys( $stats ) as $key ) {
399 ksort( $stats[$key] );
412 private static function selectRowsIdLang( ?array $ids, ?array $codes,
int $flags ): iterable {
413 if ( $flags & self::FLAG_NO_CACHE ) {
418 if ( $ids !==
null ) {
419 $dbids = array_map( [ self::class,
'getDatabaseIdForGroupId' ], $ids );
420 $conditions[
'tgs_group'] = $dbids;
423 if ( $codes !==
null ) {
424 $conditions[
'tgs_lang'] = $codes;
427 $dbr = Utilities::getSafeReadDB();
428 return $dbr->newSelectQueryBuilder()
430 ->from( self::TABLE )
431 ->where( $conditions )
432 ->caller( __METHOD__ )
443 private static function forItemInternal(
446 string $languageCode,
449 $id = $group->getId();
451 if ( $flags & self::FLAG_CACHE_ONLY ) {
452 $stats[$id][$languageCode] = self::getUnknownStats();
453 return $stats[$id][$languageCode];
461 $databaseGroupId = self::getDatabaseIdForGroupId( $id );
462 $uniqueKey =
"$databaseGroupId|$languageCode";
463 $queuedValue = self::$updates[$uniqueKey] ??
null;
464 if ( $queuedValue && !( $flags & self::FLAG_NO_CACHE ) ) {
466 self::TOTAL => $queuedValue[
'tgs_total'],
467 self::TRANSLATED => $queuedValue[
'tgs_translated'],
468 self::FUZZY => $queuedValue[
'tgs_fuzzy'],
469 self::PROOFREAD => $queuedValue[
'tgs_proofread'],
474 $aggregates = self::calculateAggregateGroup( $stats, $group, $languageCode, $flags );
476 $aggregates = self::calculateGroup( $group, $languageCode );
479 $stats[$id][$languageCode] = $aggregates;
482 if ( $aggregates[self::TOTAL] ===
null ) {
486 self::$updates[$uniqueKey] = [
487 'tgs_group' => $databaseGroupId,
488 'tgs_lang' => $languageCode,
489 'tgs_total' => $aggregates[self::TOTAL],
490 'tgs_translated' => $aggregates[self::TRANSLATED],
491 'tgs_fuzzy' => $aggregates[self::FUZZY],
492 'tgs_proofread' => $aggregates[self::PROOFREAD],
497 if ( count( self::$updates ) % 100 === 0 ) {
498 self::queueUpdates( $flags );
504 private static function calculateAggregateGroup(
510 $aggregates = self::getEmptyStats();
512 $expanded = self::expandAggregates( $group );
513 $subGroupIds = array_keys( $expanded );
516 foreach ( $subGroupIds as $index => $sid ) {
517 if ( isset( $stats[$sid][$code] ) ) {
518 unset( $subGroupIds[ $index ] );
522 if ( $subGroupIds !== [] ) {
523 $res = self::selectRowsIdLang( $subGroupIds, [ $code ], $flags );
524 $stats = self::extractResults( $res, $subGroupIds, $stats );
527 $messageGroupMetadata = Services::getInstance()->getMessageGroupMetadata();
528 foreach ( $expanded as $sid => $subgroup ) {
535 if ( !isset( $stats[$sid][$code] ) ) {
536 $stats[$sid][$code] = self::forItemInternal( $stats, $subgroup, $code, $flags );
539 if ( !$messageGroupMetadata->isExcluded( $sid, $code ) ) {
540 $aggregates = self::multiAdd( $aggregates, $stats[$sid][$code] );
547 public static function multiAdd( array $a, array $b ): array {
548 if ( $a[0] === null || $b[0] === null ) {
549 return array_fill( 0, count( $a ),
null );
551 foreach ( $a as $i => &$v ) {
563 private static function calculateGroup(
MessageGroup $group,
string $languageCode ): array {
564 global $wgTranslateDocumentationLanguageCode;
569 $languageCode === $wgTranslateDocumentationLanguageCode
573 if ( $cache->exists() ) {
574 $template = $cache->getExtra()[
'TEMPLATE'] ?? [];
576 foreach ( $template as $key => $data ) {
577 if ( isset( $data[
'comments'][
'.'] ) ) {
581 $collection->setInFile( $infile );
585 return self::getStatsForCollection( $collection );
588 private static function queueUpdates(
int $flags ): void {
589 $mwInstance = MediaWikiServices::getInstance();
590 if ( self::$updates === [] || $mwInstance->getReadOnlyMode()->isReadOnly() ) {
594 $dbw = $mwInstance->getConnectionProvider()->getPrimaryDatabase();
595 $callers = wfGetAllCallers( 50 );
596 $functionName = __METHOD__;
597 $callback =
static function ( IDatabase $dbw, $method ) use ( $callers, $mwInstance ) {
599 if ( count( self::$updates ) > 100 ) {
600 $groups = array_unique( array_column( self::$updates,
'tgs_group' ) );
601 LoggerFactory::getInstance( LogNames::MAIN )->warning(
602 "Huge translation update of {count} rows for group(s) {groups}",
604 'count' => count( self::$updates ),
605 'groups' => implode(
', ', $groups ),
606 'callers' => $callers,
611 $dbw->newReplaceQueryBuilder()
612 ->replaceInto( self::TABLE )
613 ->uniqueIndexFields( [
'tgs_group',
'tgs_lang' ] )
614 ->rows( array_values( self::$updates ) )
619 $mwInstance->getMainWANObjectCache()->touchCheckKey( self::LANGUAGE_STATS_KEY );
621 $updateOp =
static function () use ( $dbw, $functionName, $callback ) {
623 if ( self::$updates === [] ) {
627 $lockName =
'MessageGroupStats:updates';
628 if ( !$dbw->lock( $lockName, $functionName, 1 ) ) {
629 $groups = array_unique( array_column( self::$updates,
'tgs_group' ) );
630 LoggerFactory::getInstance( LogNames::MAIN )->warning(
631 'Message group stats update of {count} rows failed for group(s) {groups} due to lock',
633 'count' => count( self::$updates ),
634 'groups' => implode(
', ', $groups ),
641 $dbw->commit( $functionName,
'flush' );
642 $callback( $dbw, $functionName );
643 $dbw->commit( $functionName,
'flush' );
645 $dbw->unlock( $lockName, $functionName );
648 if ( $flags & self::FLAG_IMMEDIATE_WRITES ) {
651 DeferredUpdates::addCallableUpdate( $updateOp );
655 public static function getDatabaseIdForGroupId(
string $id ): string {
657 if ( strlen( $id ) <= 72 ) {
661 $hash = hash(
'sha256', $id,
false );
662 return substr( $id, 0, 50 ) .
'||' . substr( $hash, 0, 20 );
668 $collection->filterUntranslatedOptional();
670 $total = count( $collection );
673 $collection->
filter( MessageCollection::FILTER_FUZZY, MessageCollection::EXCLUDE_MATCHING );
674 $fuzzy = $total - count( $collection );
677 $collection->
filter( MessageCollection::FILTER_HAS_TRANSLATION, MessageCollection::INCLUDE_MATCHING );
678 $translated = count( $collection );
682 $collection->
filter( MessageCollection::FILTER_REVIEWER, MessageCollection::INCLUDE_MATCHING );
683 $proofread = count( $collection );
686 self::TOTAL => $total,
687 self::TRANSLATED => $translated,
688 self::FUZZY => $fuzzy,
689 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