Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
TranslateSpecialPage.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\TranslatorInterface;
5
6use MediaWiki\Config\Config;
12use MediaWiki\Html\Html;
13use MediaWiki\Language\Language;
14use MediaWiki\Language\LanguageFactory;
15use MediaWiki\Language\LanguageNameUtils;
16use MediaWiki\Logger\LoggerFactory;
17use MediaWiki\MediaWikiServices;
18use MediaWiki\Skin\Skin;
19use MediaWiki\SpecialPage\SpecialPage;
20use Psr\Log\LoggerInterface;
21
31class TranslateSpecialPage extends SpecialPage {
32 private ?MessageGroup $group = null;
33 private array $options = [];
34 private LoggerInterface $logger;
35 private bool $isMessageGroupSubscriptionEnabled;
36
37 public function __construct(
38 private readonly Language $contentLanguage,
39 private readonly LanguageFactory $languageFactory,
40 private readonly LanguageNameUtils $languageNameUtils,
41 private readonly HookRunner $hookRunner,
42 Config $config
43 ) {
44 parent::__construct( 'Translate' );
45 $this->logger = LoggerFactory::getInstance( LogNames::MAIN );
46 $this->isMessageGroupSubscriptionEnabled = $config->get( 'TranslateEnableMessageGroupSubscription' );
47 }
48
50 public function doesWrites() {
51 return true;
52 }
53
54 protected function getGroupName(): string {
55 return 'translation';
56 }
57
59 public function execute( $parameters ) {
60 $out = $this->getOutput();
61 $out->addModuleStyles( [
62 'ext.translate.special.translate.styles',
63 'jquery.uls.grid',
64 'codex-styles',
65 "mediawiki.codex.messagebox.styles",
66 ] );
67
68 $this->setHeaders();
69
70 $this->setup( $parameters );
71
72 // Redirect old export URLs to Special:ExportTranslations
73 if ( $this->getRequest()->getText( 'taction' ) === 'export' ) {
74 $exportPage = SpecialPage::getTitleFor( 'ExportTranslations' );
75 $out->redirect( $exportPage->getLocalURL( $this->options ) );
76 }
77
78 $out->addModules( 'ext.translate.special.translate' );
79 $out->addJsConfigVars( [
80 'wgTranslateEnableMessageGroupSubscription' => $this->isMessageGroupSubscriptionEnabled
81 ] );
82
83 $out->addHTML( Html::openElement( 'div', [
84 // FIXME: Temporary hack. Add better support for dark mode.
85 'class' => 'grid ext-translate-container',
86 ] ) );
87
88 $out->addHTML( $this->tuxSettingsForm() );
89 $out->addHTML( $this->messageSelector() );
90
91 if ( $this->group ) {
92 $table = new MessageTable( $this->getContext(), $this->group, $this->options['language'] );
93 $output = $table->fullTable();
94
95 $out->addHTML( $output );
96 }
97 $out->addHTML( Html::closeElement( 'div' ) );
98 }
99
100 private function setup( ?string $parameters ): void {
101 $request = $this->getRequest();
102
103 $defaults = [
104 'language' => $this->getLanguage()->getCode(),
105 'group' => '!additions',
106 ];
107
108 // Dump everything here
109 $nonDefaults = [];
110 $parameters = array_map( 'trim', explode( ';', (string)$parameters ) );
111
112 foreach ( $parameters as $_ ) {
113 if ( $_ === '' ) {
114 continue;
115 }
116
117 if ( str_contains( $_, '=' ) ) {
118 [ $key, $value ] = array_map( 'trim', explode( '=', $_, 2 ) );
119 } else {
120 $key = 'group';
121 $value = $_;
122 }
123
124 if ( isset( $defaults[$key] ) ) {
125 $nonDefaults[$key] = $value;
126 }
127 }
128
129 foreach ( array_keys( $defaults ) as $key ) {
130 $value = $request->getVal( $key );
131 if ( is_string( $value ) ) {
132 $nonDefaults[$key] = $value;
133 }
134 }
135
136 $this->hookRunner->onTranslateGetSpecialTranslateOptions( $defaults, $nonDefaults );
137
138 $this->options = $nonDefaults + $defaults;
139 $this->group = MessageGroups::getGroup( $this->options['group'] );
140 if ( $this->group ) {
141 $this->options['group'] = $this->group->getId();
142 } else {
143 $this->group = MessageGroups::getGroup( $defaults['group'] );
144 if (
145 isset( $nonDefaults['group'] ) &&
146 str_starts_with( $nonDefaults['group'], 'page-' ) &&
147 !str_contains( $nonDefaults['group'], '+' )
148 ) {
149 // https://phabricator.wikimedia.org/T320220
150 $this->logger->debug(
151 "[Special:Translate] Requested group {groupId} doesn't exist.",
152 [ 'groupId' => $nonDefaults['group'] ]
153 );
154 }
155 }
156
157 if ( !$this->languageNameUtils->isKnownLanguageTag( $this->options['language'] ) ) {
158 $this->options['language'] = $defaults['language'];
159 }
160
161 if ( MessageGroups::isDynamic( $this->group ) ) {
162 // @phan-suppress-next-line PhanUndeclaredMethod
163 $this->group->setLanguage( $this->options['language'] );
164 }
165 }
166
167 private function tuxSettingsForm(): string {
168 $noJs = Html::errorBox(
169 $this->msg( 'tux-nojs' )->escaped(),
170 '',
171 'tux-nojs'
172 );
173
174 $attrs = [ 'class' => 'row tux-editor-header' ];
175 $selectors = $this->tuxGroupSelector() .
176 $this->tuxLanguageSelector() .
177 $this->tuxGroupSubscription() .
178 $this->tuxGroupDescription() .
179 $this->tuxWorkflowSelector() .
180 $this->tuxGroupWarning();
181
182 return Html::rawElement( 'div', $attrs, $selectors ) . $noJs;
183 }
184
185 private function messageSelector(): string {
186 $output = Html::openElement( 'div', [ 'class' => 'row tux-messagetable-header hide' ] );
187 $output .= Html::openElement( 'div', [ 'class' => 'nine columns' ] );
188 $output .= Html::openElement( 'ul', [ 'class' => 'row tux-message-selector' ] );
189 $userId = $this->getUser()->getId();
190 $tabs = [
191 'all' => '',
192 'untranslated' => '!translated',
193 'outdated' => 'fuzzy',
194 'translated' => 'translated',
195 'unproofread' => "translated|!reviewer:$userId|!last-translator:$userId",
196 ];
197
198 foreach ( $tabs as $tab => $filter ) {
199 // Possible classes and messages, for grepping:
200 // tux-tab-all
201 // tux-tab-untranslated
202 // tux-tab-outdated
203 // tux-tab-translated
204 // tux-tab-unproofread
205 $tabClass = "tux-tab-$tab";
206 $link = Html::element(
207 'span',
208 [
209 'role' => 'button',
210 'tabindex' => '0',
211 ],
212 $this->msg( $tabClass )->text()
213 );
214 $output .= Html::rawElement( 'li', [
215 'class' => 'column ' . $tabClass,
216 'data-filter' => $filter,
217 'data-title' => $tab,
218 ], $link );
219 }
220
221 // Check boxes for the "more" tab.
222 $container = Html::openElement( 'ul', [ 'class' => 'column tux-message-selector' ] );
223 $container .= Html::rawElement( 'li',
224 [ 'class' => 'column' ],
225 Html::check( 'optional', false, [
226 'id' => 'tux-option-optional',
227 'data-filter' => 'optional'
228 ] ) . "\u{00A0}" . Html::label(
229 $this->msg( 'tux-message-filter-optional-messages-label' )->text(),
230 'tux-option-optional'
231 )
232 );
233
234 $container .= Html::closeElement( 'ul' );
235 $output .= Html::rawElement( 'li', [ 'class' => 'column more' ],
236 $this->msg( 'ellipsis' )->escaped() .
237 $container
238 );
239
240 $output .= Html::closeElement( 'ul' );
241 $output .= Html::closeElement( 'div' ); // close nine columns
242 $output .= Html::openElement( 'div', [ 'class' => 'three columns' ] );
243 $output .= Html::rawElement(
244 'div',
245 [ 'class' => 'tux-message-filter-wrapper' ],
246 Html::input(
247 '',
248 '',
249 'search',
250 [
251 'class' => 'tux-message-filter-box',
252 'placeholder' => $this->msg( 'tux-message-filter-placeholder' )->text(),
253 ]
254 )
255 );
256
257 // close three columns and the row
258 $output .= Html::closeElement( 'div' ) . Html::closeElement( 'div' );
259
260 return $output;
261 }
262
263 private function tuxGroupSelector(): string {
264 $groupClass = [ 'grouptitle', 'grouplink' ];
265 $subGroupCount = null;
266 if ( $this->group instanceof AggregateMessageGroup ) {
267 $groupClass[] = 'tux-breadcrumb__item--aggregate';
268 $subGroupCount = count( $this->group->getGroups() );
269 }
270
271 // @todo FIXME The selector should have expanded parent-child lists
272 return Html::openElement( 'div', [
273 'class' => 'eight columns tux-breadcrumb',
274 'data-language' => $this->options['language'],
275 ] ) .
276 Html::element( 'span',
277 [ 'class' => 'grouptitle grouplink tux-breadcrumb__item--aggregate' ],
278 $this->msg( 'translate-msggroupselector-search-all' )->text()
279 ) .
280 Html::element( 'span',
281 [
282 'class' => $groupClass,
283 'data-msggroupid' => $this->group->getId(),
284 'data-msggroup-subgroup-count' => $subGroupCount
285 ],
286 $this->group->getLabel( $this->getContext() )
287 ) .
288 Html::closeElement( 'div' );
289 }
290
291 private function tuxLanguageSelector(): string {
292 if ( $this->options['language'] === $this->getConfig()->get( 'TranslateDocumentationLanguageCode' ) ) {
293 $targetLanguage = $this->contentLanguage;
294 $targetLangName = $this->msg( 'translate-documentation-language' )->text();
295 } else {
296 $targetLanguage = $this->languageFactory->getLanguage( $this->options['language'] );
297 $targetLangName = $this->languageNameUtils->getLanguageName( $targetLanguage->getCode() );
298 }
299
300 $label = Html::element( 'span', [], $this->msg( 'tux-languageselector' )->text() );
301
302 $languageIcon = Html::element(
303 'span',
304 [ 'class' => 'ext-translate-language-icon' ]
305 );
306
307 $targetLanguageName = Html::element(
308 'span',
309 [
310 'class' => 'ext-translate-target-language',
311 'dir' => $targetLanguage->getDir(),
312 'lang' => $targetLanguage->getHtmlCode()
313 ],
314 $targetLangName
315 );
316
317 $expandIcon = Html::element(
318 'span',
319 [ 'class' => 'ext-translate-language-selector-expand' ]
320 );
321
322 $value = Html::rawElement(
323 'button',
324 [
325 'class' => 'uls cdx-button',
326 'title' => $this->msg( 'tux-select-target-language' )->text()
327 ],
328 $languageIcon . $targetLanguageName . $expandIcon
329 );
330
331 return Html::rawElement(
332 'div',
333 [ 'class' => 'four columns ext-translate-language-selector' ],
334 "$label $value"
335 );
336 }
337
338 private function tuxGroupSubscription(): string {
339 return Html::rawElement(
340 'div',
341 [ 'class' => 'twelve columns tux-watch-group' ]
342 );
343 }
344
345 private function tuxGroupDescription(): string {
346 // Initialize an empty warning box to be filled client-side.
347 return Html::rawElement(
348 'div',
349 [ 'class' => 'twelve columns description' ],
350 $this->group ? $this->getGroupDescription( $this->group ) : ''
351 );
352 }
353
354 private function getGroupDescription( MessageGroup $group ): string {
355 $description = $group->getDescription( $this->getContext() );
356 return $description === null ?
357 '' : $this->getOutput()->parseAsInterface( $description );
358 }
359
360 private function tuxGroupWarning(): string {
361 // Outer container is always present; message boxes are children only.
362 $warning = '';
363 if ( $this->options['group'] === '' ) {
364 $warning = Html::warningBox(
365 $this->msg( 'tux-translate-page-no-such-group' )->parse()
366 );
367 }
368
369 return Html::rawElement( 'div', [ 'class' => 'tux-group-warning twelve column' ], $warning );
370 }
371
372 private function tuxWorkflowSelector(): string {
373 return Html::element( 'div', [ 'class' => 'tux-workflow twelve columns' ] );
374 }
375
380 public static function tabify( Skin $skin, array &$tabs ): bool {
381 $title = $skin->getTitle();
382 if ( !$title->isSpecialPage() ) {
383 return true;
384 }
385 [ $alias, $sub ] = MediaWikiServices::getInstance()
386 ->getSpecialPageFactory()->resolveAlias( $title->getText() );
387
388 $pagesInGroup = [ 'Translate', 'LanguageStats', 'MessageGroupStats', 'ExportTranslations' ];
389 if ( !in_array( $alias, $pagesInGroup, true ) ) {
390 return true;
391 }
392
393 // Extract subpage syntax, otherwise the values are not passed forward
394 $params = [];
395 if ( $sub !== null && trim( $sub ) !== '' ) {
396 if ( $alias === 'Translate' || $alias === 'MessageGroupStats' ) {
397 $params['group'] = $sub;
398 } elseif ( $alias === 'LanguageStats' ) {
399 // Breaks if additional parameters besides language are code provided
400 $params['language'] = $sub;
401 }
402 }
403
404 $request = $skin->getRequest();
405 // However, query string params take precedence
406 $params['language'] = $request->getRawVal( 'language' ) ?? '';
407 $params['group'] = $request->getRawVal( 'group' ) ?? '';
408
409 // Remove empty values from params
410 $params = array_filter( $params, static function ( string $param ) {
411 return $param !== '';
412 } );
413
414 $translate = SpecialPage::getTitleFor( 'Translate' );
415 $languageStatistics = SpecialPage::getTitleFor( 'LanguageStats' );
416 $messageGroupStatistics = SpecialPage::getTitleFor( 'MessageGroupStats' );
417
418 // Clear the special page tab that might be there already
419 $tabs['associated-pages'] = [];
420
421 $tabs['associated-pages']['translate'] = [
422 'text' => wfMessage( 'translate-taction-translate' )->text(),
423 'href' => $translate->getLocalURL( $params ),
424 'class' => 'tux-tab',
425 ];
426
427 if ( $alias === 'Translate' ) {
428 $tabs['associated-pages']['translate']['class'] .= ' selected';
429 }
430
431 $tabs['views']['lstats'] = [
432 'text' => wfMessage( 'translate-taction-lstats' )->text(),
433 'href' => $languageStatistics->getLocalURL( $params ),
434 'class' => 'tux-tab',
435 ];
436 if ( $alias === 'LanguageStats' ) {
437 $tabs['views']['lstats']['class'] .= ' selected';
438 }
439
440 $tabs['views']['mstats'] = [
441 'text' => wfMessage( 'translate-taction-mstats' )->text(),
442 'href' => $messageGroupStatistics->getLocalURL( $params ),
443 'class' => 'tux-tab',
444 ];
445
446 if ( $alias === 'MessageGroupStats' ) {
447 $tabs['views']['mstats']['class'] .= ' selected';
448 }
449
450 $tabs['views']['export'] = [
451 'text' => wfMessage( 'translate-taction-export' )->text(),
452 'href' => SpecialPage::getTitleFor( 'ExportTranslations' )->getLocalURL( $params ),
453 'class' => 'tux-tab',
454 ];
455
456 return true;
457 }
458}
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'), $services->get( 'Translate:MessageGroupFactory'),);}, '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->get( 'Translate:MessageGroupFactory'), $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:MessageGroupFactory'=> static function(MediaWikiServices $services):MessageGroupFactory { return new MessageGroupFactory($services->get( 'Translate:MessageGroupTypeRegistry'));}, '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(), $services->getNotificationService(), 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();}, 'Translate:MessageGroupSubscriptionStore'=> static function(MediaWikiServices $services):MessageGroupSubscriptionStore { return new MessageGroupSubscriptionStore( $services->getConnectionProvider());}, 'Translate:MessageGroupTypeRegistry'=> static function():MessageGroupTypeRegistry { return new MessageGroupTypeRegistry();}, '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
Hook runner for the Translate extension.
Constants for log channel names used in this extension.
Definition LogNames.php:13
const MAIN
Default log channel for the extension.
Definition LogNames.php:15
Factory class for accessing message groups individually by id or all of them as a list.
Groups multiple message groups together as one group.
getGroup()
Get the primary MessageGroup this message belongs to.
Implements the core of Translate extension - a special page which shows a list of messages in a forma...
static tabify(Skin $skin, array &$tabs)
Adds the task-based tabs on Special:Translate and few other special pages.