Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
TranslationStatsSpecialPage.php
Go to the documentation of this file.
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Statistics;
5
6use FormOptions;
7use Html;
11use SpecialPage;
13use Xml;
14use XmlSelect;
15use function wfEscapeWikiText;
16
25class TranslationStatsSpecialPage extends SpecialPage {
27 private $dataProvider;
28 private const GRAPH_CONTAINER_ID = 'translationStatsGraphContainer';
29 private const GRAPH_CONTAINER_CLASS = 'mw-translate-translationstats-container';
30
31 public function __construct( TranslationStatsDataProvider $dataProvider ) {
32 parent::__construct( 'TranslationStats' );
33 $this->dataProvider = $dataProvider;
34 }
35
37 public function isIncludable(): bool {
38 return true;
39 }
40
42 protected function getGroupName(): string {
43 return 'translation';
44 }
45
47 public function execute( $par ): void {
48 $graphOpts = new TranslationStatsGraphOptions();
49 $graphOpts->bindArray( $this->getRequest()->getValues() );
50
51 $pars = explode( ';', (string)$par );
52 foreach ( $pars as $item ) {
53 if ( strpos( $item, '=' ) === false ) {
54 continue;
55 }
56
57 [ $key, $value ] = array_map( 'trim', explode( '=', $item, 2 ) );
58 if ( $graphOpts->hasValue( $key ) ) {
59 $graphOpts->setValue( $key, $value );
60 }
61 }
62
63 $graphOpts->normalize( $this->dataProvider->getGraphTypes() );
64 $opts = $graphOpts->getFormOptions();
65
66 if ( $this->including() ) {
67 $this->getOutput()->addHTML( $this->embed( $opts ) );
68 } else {
69 $this->form( $opts );
70 }
71 }
72
78 private function form( FormOptions $opts ): void {
79 $script = $this->getConfig()->get( 'Script' );
80
81 $this->setHeaders();
82 $out = $this->getOutput();
83 $out->addModules( 'ext.translate.special.translationstats' );
84 $out->addHelpLink( 'Help:Extension:Translate/Statistics_and_reporting' );
85 $out->addWikiMsg( 'translate-statsf-intro' );
86 $out->addHTML(
87 Xml::fieldset( $this->msg( 'translate-statsf-options' )->text() ) . Html::openElement(
88 'form',
89 [ 'action' => $script, 'id' => 'translationStatsConfig' ]
90 ) . Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) .
91 Html::hidden( 'preview', 1 ) . '<table>'
92 );
93 $submit = Xml::submitButton( $this->msg( 'translate-statsf-submit' )->text() );
94 $out->addHTML(
95 $this->eInput( 'width', $opts ) . $this->eInput( 'height', $opts ) .
96 '<tr><td colspan="2"><hr /></td></tr>' . $this->eInput( 'start', $opts, 24 ) .
97 $this->eInput( 'days', $opts ) .
98 $this->eRadio( 'scale', $opts, [ 'years', 'months', 'weeks', 'days', 'hours' ] ) .
99 $this->eRadio( 'count', $opts, $this->dataProvider->getGraphTypes() ) .
100 '<tr><td colspan="2"><hr /></td></tr>' . $this->eLanguage( 'language', $opts ) .
101 $this->eGroup( 'group', $opts ) . '<tr><td colspan="2"><hr /></td></tr>' .
102 '<tr><td colspan="2">' . $submit . '</td></tr>'
103 );
104 $out->addHTML( '</table></form></fieldset>' );
105 if ( !$opts['preview'] ) {
106 return;
107 }
108 $spiParams = [];
109 foreach ( $opts->getChangedValues() as $key => $v ) {
110 if ( $key === 'preview' ) {
111 continue;
112 }
113 if ( is_array( $v ) ) {
114 $v = implode( ',', $v );
115 if ( !strlen( $v ) ) {
116 continue;
117 }
118 }
119 $spiParams[] = $key . '=' . wfEscapeWikiText( $v );
120 }
121 if ( $spiParams ) {
122 $spiParams = '/' . implode( ';', $spiParams );
123 }
124 $titleText = $this->getPageTitle()->getPrefixedText();
125 $out->addHTML( Html::element( 'hr' ) );
126 // Element to render the graph
127 $out->addHTML(
128 Html::rawElement(
129 'div',
130 [
131 'id' => self::GRAPH_CONTAINER_ID,
132 'style' => 'margin: 2em auto; display: block',
133 'class' => self::GRAPH_CONTAINER_CLASS,
134 ]
135 )
136 );
137
138 $out->addHTML(
139 Html::element(
140 'pre',
141 [ 'aria-label' => $this->msg( 'translate-statsf-embed' )->text() ],
142 "{{{$titleText}{$spiParams}}}"
143 )
144 );
145 }
146
148 private function eInput( string $name, FormOptions $opts, int $width = 4 ): string {
149 $value = $opts[$name];
150 return '<tr><td>' . $this->eLabel( $name ) . '</td><td>' .
151 Xml::input( $name, $width, $value, [ 'id' => $name ] ) . '</td></tr>' . "\n";
152 }
153
155 private function eLabel( string $name ): string {
156 // Give grep a chance to find the usages:
157 // translate-statsf-width, translate-statsf-height, translate-statsf-start,
158 // translate-statsf-days, translate-statsf-scale, translate-statsf-count,
159 // translate-statsf-language, translate-statsf-group
160 $label = 'translate-statsf-' . $name;
161 $label = $this->msg( $label )->escaped();
162 return Xml::tags( 'label', [ 'for' => $name ], $label );
163 }
164
166 private function eRadio( string $name, FormOptions $opts, array $alts ): string {
167 // Give grep a chance to find the usages:
168 // translate-statsf-scale, translate-statsf-count
169 $label = 'translate-statsf-' . $name;
170 $label = $this->msg( $label )->escaped();
171 $s = '<tr><td>' . $label . '</td><td>';
172 $options = [];
173 foreach ( $alts as $alt ) {
174 $id = "$name-$alt";
175 $radio = Xml::radio(
176 $name,
177 $alt,
178 $alt === $opts[$name],
179 [ 'id' => $id ]
180 ) . ' ';
181 $options[] = $radio . ' ' . $this->eLabel( $id );
182 }
183 $s .= implode( ' ', $options );
184 $s .= '</td></tr>' . "\n";
185 return $s;
186 }
187
189 private function eLanguage( string $name, FormOptions $opts ): string {
190 $value = implode( ',', $opts[$name] );
191
192 $select = $this->languageSelector();
193 $select->setTargetId( 'language' );
194 return '<tr><td>' . $this->eLabel( $name ) . '</td><td>' . $select->getHtmlAndPrepareJS() .
195 '<br />' . Xml::input( $name, 20, $value, [ 'id' => $name ] ) . '</td></tr>' . "\n";
196 }
197
199 private function languageSelector(): JsSelectToInput {
200 $languages = TranslateUtils::getLanguageNames( $this->getLanguage()->getCode() );
201 ksort( $languages );
202 $selector = new XmlSelect( 'mw-language-selector', 'mw-language-selector' );
203 foreach ( $languages as $code => $name ) {
204 $selector->addOption( "$code - $name", $code );
205 }
206 return new JsSelectToInput( $selector );
207 }
208
210 private function eGroup( string $name, FormOptions $opts ): string {
211 $value = implode( ',', $opts[$name] );
212
213 $select = $this->groupSelector();
214 $select->setTargetId( 'group' );
215 return '<tr><td>' . $this->eLabel( $name ) . '</td><td>' . $select->getHtmlAndPrepareJS() .
216 '<br />' . Xml::input( $name, 20, $value, [ 'id' => $name ] ) . '</td></tr>' . "\n";
217 }
218
220 private function groupSelector(): JsSelectToInput {
221 $groups = MessageGroups::singleton()->getGroups();
223 foreach ( $groups as $key => $group ) {
224 if ( !$group->exists() ) {
225 unset( $groups[$key] );
226 }
227 }
228 ksort( $groups );
229 $selector = new XmlSelect( 'mw-group-selector', 'mw-group-selector' );
231 foreach ( $groups as $code => $name ) {
232 $selector->addOption( $name->getLabel(), $code );
233 }
234 return new JsSelectToInput( $selector );
235 }
236
237 private function embed( FormOptions $opts ): string {
238 $this->getOutput()->addModules( 'ext.translate.translationstats.embedded' );
239 return Html::rawElement(
240 'div',
241 [
242 'class' => self::GRAPH_CONTAINER_CLASS,
243 ],
244 Html::hidden(
245 'translationStatsGraphOptions',
246 json_encode( $opts->getAllValues() )
247 )
248 );
249 }
250}
return[ '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:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->getMainConfig(), $services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance( 'Translate.GroupSynchronization'), MessageIndex::singleton());}, 'Translate:GroupSynchronizationCache'=> static function(MediaWikiServices $services):GroupSynchronizationCache { return new GroupSynchronizationCache( $services->get( 'Translate:PersistentCache'));}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore(new RevTagStore(), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'));}, 'Translate:MessageGroupReview'=> static function(MediaWikiServices $services):MessageGroupReview { return new MessageGroupReview($services->getDBLoadBalancer(), $services->getHookContainer());}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=$services->getMainConfig() ->get( 'TranslateMessageIndex');if(is_string( $params)) { $params=(array) $params;} $class=array_shift( $params);return new $class( $params);}, 'Translate:ParsingPlaceholderFactory'=> static function():ParsingPlaceholderFactory { return new ParsingPlaceholderFactory();}, 'Translate:PersistentCache'=> static function(MediaWikiServices $services):PersistentCache { return new PersistentDatabaseCache($services->getDBLoadBalancer(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'));}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleFactory'=> static function(MediaWikiServices $services):TranslatableBundleFactory { return new TranslatableBundleFactory($services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:MessageBundleStore'));}, '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->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), new RevTagStore(), $services->getDBLoadBalancer());}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { $db=$services->getDBLoadBalancer() ->getConnectionRef(DB_REPLICA);return new TranslationStashStorage( $db);}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory());}, 'Translate:TranslationUnitStoreFactory'=> static function(MediaWikiServices $services):TranslationUnitStoreFactory { return new TranslationUnitStoreFactory( $services->getDBLoadBalancer());}, 'Translate:TranslatorActivity'=> static function(MediaWikiServices $services):TranslatorActivity { $query=new TranslatorActivityQuery($services->getMainConfig(), $services->getDBLoadBalancer());return new TranslatorActivity($services->getMainObjectStash(), $query, $services->getJobQueueGroup());}, 'Translate:TtmServerFactory'=> static function(MediaWikiServices $services):TtmServerFactory { $config=$services->getMainConfig();$default=$config->get( 'TranslateTranslationDefaultService');if( $default===false) { $default=null;} return new TtmServerFactory( $config->get( 'TranslateTranslationServices'), $default);}]
@phpcs-require-sorted-array
Code for JavaScript enhanced <option> selectors.
Factory class for accessing message groups individually by id or all of them as an list.
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Interface for message groups.