totals = MessageGroupStats::getEmptyStats(); } /// Overwritten from SpecialPage public function getDescription() { return $this->msg( 'translate-mgs-pagename' )->text(); } /// Overwritten from SpecialLanguageStats protected function loadStatistics( $target, $flags = 0 ) { return MessageGroupStats::forGroup( $target, $flags ); } /// Overwritten from SpecialLanguageStats protected function getCacheRebuildJobParameters( $target ) { return [ 'groupid' => $target ]; } /// Overwritten from SpecialLanguageStats protected function isValidValue( $value ) { $group = MessageGroups::getGroup( $value ); if ( $group ) { if ( MessageGroups::isDynamic( $group ) ) { /* Dynamic groups are not listed, but it is possible to end up * on this page with a dynamic group by navigating from * translation or proofreading activity or by giving group id * of dynamic group explicitly. Ignore dynamic group to avoid * throwing exceptions later. */ $group = false; } else { $this->target = $group->getId(); } } return (bool)$group; } /// Overwritten from SpecialLanguageStats protected function invalidTarget() { $this->getOutput()->wrapWikiMsg( "
$1
", [ 'translate-mgs-invalid-group', $this->target ] ); } /// Overwritten from SpecialLanguageStats protected function outputIntroduction() { $priorityLangs = TranslateMetadata::get( $this->target, 'prioritylangs' ); if ( $priorityLangs ) { $hasPriorityForce = TranslateMetadata::get( $this->target, 'priorityforce' ) === 'on'; if ( $hasPriorityForce ) { $this->getOutput()->addWikiMsg( 'tpt-priority-languages-force', $priorityLangs ); } else { $this->getOutput()->addWikiMsg( 'tpt-priority-languages', $priorityLangs ); } } } /// Overwriten from SpecialLanguageStats protected function addForm() { $formDescriptor = [ 'select' => [ 'type' => 'select', 'name' => 'group', 'id' => 'group', 'label' => $this->msg( 'translate-mgs-group' )->text(), 'options' => $this->getGroupOptions(), 'default' => $this->target ], 'nocomplete-check' => [ 'type' => 'check', 'name' => 'suppresscomplete', 'id' => 'suppresscomplete', 'label' => $this->msg( 'translate-mgs-nocomplete' )->text(), 'default' => $this->noComplete, ], 'noempty-check' => [ 'type' => 'check', 'name' => 'suppressempty', 'id' => 'suppressempty', 'label' => $this->msg( 'translate-mgs-noempty' )->text(), 'default' => $this->noEmpty, ] ]; $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ); /* Since these pages are in the tabgroup with Special:Translate, * it makes sense to retain the selected group/language parameter * on post requests even when not relevant to the current page. */ $val = $this->getRequest()->getVal( 'language' ); if ( $val !== null ) { $htmlForm->addHiddenField( 'language', $val ); } $htmlForm ->addHiddenField( 'x', 'D' ) // To detect submission ->setMethod( 'get' ) ->setSubmitTextMsg( 'translate-mgs-submit' ) ->setWrapperLegendMsg( 'translate-mgs-fieldset' ) ->prepareForm() ->displayForm( false ); } /// Overwritten from SpecialLanguageStats protected function getTable( $stats ) { $table = $this->table; $this->addWorkflowStatesColumn(); $out = ''; $this->numberOfShownLanguages = 0; $languages = array_keys( TranslateUtils::getLanguageNames( $this->getLanguage()->getCode() ) ); sort( $languages ); $this->filterPriorityLangs( $languages, $this->target, $stats ); foreach ( $languages as $code ) { if ( $table->isExcluded( $this->target, $code ) !== null ) { continue; } $out .= $this->makeRow( $code, $stats ); } if ( $out ) { $table->setMainColumnHeader( $this->msg( 'translate-mgs-column-language' ) ); $out = $table->createHeader() . "\n" . $out; $out .= Html::closeElement( 'tbody' ); $out .= Html::openElement( 'tfoot' ); $out .= $table->makeTotalRow( $this->msg( 'translate-mgs-totals' ) ->numParams( $this->numberOfShownLanguages ), $this->totals ); $out .= Html::closeElement( 'tfoot' ); $out .= Html::closeElement( 'table' ); return $out; } else { $this->nothing = true; return ''; } } /** * Filter an array of languages based on whether a priority set of * languages present for the passed group. If priority languages are * present, to that list add languages with more than 0% translation. * @param array &$languages Array of Languages to be filtered * @param string $group * @param array $cache */ protected function filterPriorityLangs( &$languages, $group, $cache ) { $filterLangs = TranslateMetadata::get( $group, 'prioritylangs' ); if ( strlen( $filterLangs ) === 0 ) { // No restrictions, keep everything return; } $filter = array_flip( explode( ',', $filterLangs ) ); foreach ( $languages as $id => $code ) { if ( isset( $filter[$code] ) ) { continue; } $translated = $cache[$code][1]; if ( $translated === 0 ) { unset( $languages[$id] ); } } } /** * @param string $code * @param array $cache * @return string */ protected function makeRow( $code, $cache ) { $stats = $cache[$code]; $total = $stats[MessageGroupStats::TOTAL]; $translated = $stats[MessageGroupStats::TRANSLATED]; $fuzzy = $stats[MessageGroupStats::FUZZY]; if ( $total === null ) { $this->incomplete = true; $extra = []; } else { if ( $this->noComplete && $fuzzy === 0 && $translated === $total ) { return ''; } if ( $this->noEmpty && $translated === 0 && $fuzzy === 0 ) { return ''; } // Skip below 2% if "don't show without translations" is checked. if ( $this->noEmpty && ( $translated / $total ) < 0.02 ) { return ''; } if ( $translated === $total ) { $extra = [ 'action' => 'proofread' ]; } else { $extra = []; } } $this->numberOfShownLanguages += 1; $this->totals = MessageGroupStats::multiAdd( $this->totals, $stats ); $rowParams = []; if ( $this->numberOfShownLanguages % 2 === 0 ) { $rowParams[ 'class' ] = 'tux-statstable-even'; } $out = "\t" . Html::openElement( 'tr', $rowParams ); $out .= "\n\t\t" . $this->getMainColumnCell( $code, $extra ); $out .= $this->table->makeNumberColumns( $stats ); $state = $this->getWorkflowStateValue( $code ); $out .= $this->getWorkflowStateCell( $code, $state ); $out .= "\n\t" . Html::closeElement( 'tr' ) . "\n"; return $out; } /** * @param string $code * @param array $params * @return string */ protected function getMainColumnCell( $code, $params ) { if ( !isset( $this->names ) ) { $this->names = TranslateUtils::getLanguageNames( $this->getLanguage()->getCode() ); $this->translate = SpecialPage::getTitleFor( 'Translate' ); } $queryParameters = $params + [ 'group' => $this->target, 'language' => $code ]; if ( isset( $this->names[$code] ) ) { $text = "$code: {$this->names[$code]}"; } else { $text = $code; } $link = $this->getLinkRenderer()->makeKnownLink( $this->translate, $text, [], $queryParameters ); return Html::rawElement( 'td', [], $link ); } /** * @param string $field * @param string $filter * @return array */ protected function getWorkflowStates( $field = 'tgr_lang', $filter = 'tgr_group' ) { // This override is needed because default values for $field and $filter // are different than in the parent class. return parent::getWorkflowStates( $field, $filter ); } /** * Creates a simple message group options. * * @return array $options */ protected function getGroupOptions() { $options = []; $groups = MessageGroups::getAllGroups(); foreach ( $groups as $id => $class ) { if ( MessageGroups::getGroup( $id )->exists() ) { $options[$class->getLabel()] = $id; } } return $options; } protected function getGroupName() { return 'translation'; } }