SpecialTranslate.php

Go to the documentation of this file.
00001 <?php
00018 class SpecialTranslate extends SpecialPage {
00022     protected $task = null;
00023 
00027     protected $group = null;
00028 
00029     protected $defaults = null;
00030     protected $nondefaults = array();
00031     protected $options = null;
00032 
00033     function __construct() {
00034         parent::__construct( 'Translate' );
00035     }
00036 
00040     public function execute( $parameters ) {
00041         global $wgTranslateBlacklist, $wgContLang;
00042 
00043         $out = $this->getOutput();
00044         $out->addModules( 'ext.translate.special.translate' );
00045 
00046         $this->setHeaders();
00047 
00048         $request = $this->getRequest();
00049         // @todo Move to api or so
00050         if ( $parameters === 'editpage' ) {
00051             $editpage = TranslationEditPage::newFromRequest( $request );
00052 
00053             if ( $editpage ) {
00054                 $editpage->execute();
00055 
00056                 return;
00057             }
00058         }
00059 
00060         $this->setup( $parameters );
00061         $isBeta = self::isBeta( $request );
00062 
00063         if ( $this->options['group'] === '' || ( $isBeta && !$this->group ) ) {
00064             $this->groupInformation();
00065 
00066             return;
00067         }
00068 
00069         $errors = $this->getFormErrors();
00070 
00071         if ( $isBeta && $this->options['taction'] !== 'export' ) {
00072             $out->addHTML( Html::openElement( 'div', array(
00073                 'class' => 'grid ext-translate-container',
00074             ) ) );
00075 
00076             $out->addHTML( $this->tuxSettingsForm( $errors ) );
00077             $out->addHTML( $this->messageSelector() );
00078         } else {
00079             TranslateUtils::addSpecialHelpLink( $out, 'Help:Extension:Translate/Translation_example' );
00080             // Show errors nicely.
00081             $out->addHTML( $this->settingsForm( $errors ) );
00082         }
00083 
00084         if ( count( $errors ) ) {
00085             return;
00086         } else {
00087             $checks = array(
00088                 $this->options['group'],
00089                 strtok( $this->options['group'], '-' ),
00090                 '*'
00091             );
00092 
00093             foreach ( $checks as $check ) {
00094                 if ( isset( $wgTranslateBlacklist[$check][$this->options['language']] ) ) {
00095                     $reason = $wgTranslateBlacklist[$check][$this->options['language']];
00096                     $out->addWikiMsg( 'translate-page-disabled', $reason );
00097 
00098                     return;
00099                 }
00100             }
00101         }
00102 
00103         $params = array( $this->getContext(), $this->task, $this->group, $this->options );
00104         if ( !wfRunHooks( 'SpecialTranslate::executeTask', $params ) ) {
00105             return;
00106         }
00107 
00108         // Initialise and get output.
00109         if ( !$this->task ) {
00110             return;
00111         }
00112 
00113         $this->task->init( $this->group, $this->options, $this->nondefaults, $this->getContext() );
00114         $output = $this->task->execute();
00115 
00116         if ( $this->task->plainOutput() ) {
00117             $out->disable();
00118             header( 'Content-type: text/plain; charset=UTF-8' );
00119             echo $output;
00120         } else {
00121             $description = $this->getGroupDescription( $this->group );
00122 
00123             $taskid = $this->options['task'];
00124             if ( in_array( $taskid, array( 'untranslated', 'reviewall' ), true ) ) {
00125                 $hasOptional = count( $this->group->getTags( 'optional' ) );
00126                 if ( $hasOptional ) {
00127                     $linktext = $this->msg( 'translate-page-description-hasoptional-open' )->escaped();
00128                     $params = array( 'task' => 'optional' ) + $this->nondefaults;
00129                     $link = Linker::link( $this->getTitle(), $linktext, array(), $params );
00130                     $note = $this->msg( 'translate-page-description-hasoptional' )
00131                         ->rawParams( $link )->parseAsBlock();
00132 
00133                     if ( $description ) {
00134                         $description .= '<br />' . $note;
00135                     } else {
00136                         $description = $note;
00137                     }
00138                 }
00139             }
00140 
00141             $status = $this->getWorkflowStatus();
00142             if ( $status !== false ) {
00143                 $description = $status . $description;
00144             }
00145 
00146             $groupId = $this->group->getId();
00147             // PHP is such an awesome language
00148             $priorityLangs = TranslateMetadata::get( $groupId, 'prioritylangs' );
00149             $priorityLangs = array_flip( array_filter( explode( ',', $priorityLangs ) ) );
00150             $priorityLangsCount = count( $priorityLangs );
00151             if ( $priorityLangsCount && !isset( $priorityLangs[$this->options['language']] ) ) {
00152                 $priorityForce = TranslateMetadata::get( $groupId, 'priorityforce' );
00153                 if ( $priorityForce === 'on' ) {
00154                     // Hide table
00155                     $priorityMessageClass = 'errorbox';
00156                     $priorityMessageKey = 'tpt-discouraged-language-force';
00157                 } else {
00158                     $priorityMessageClass = 'warningbox';
00159                     $priorityMessageKey = 'tpt-discouraged-language';
00160                 }
00161 
00162                 $priorityLanguageNames = array();
00163                 $languageNames = TranslateUtils::getLanguageNames( $this->getLanguage()->getCode() );
00164                 foreach ( array_keys( $priorityLangs ) as $langCode ) {
00165                     $priorityLanguageNames[] = $languageNames[$langCode];
00166                 }
00167 
00168                 $priorityReason = TranslateMetadata::get( $groupId, 'priorityreason' );
00169                 if ( $priorityReason !== '' ) {
00170                     $priorityReason = "\n\n" . $this->msg(
00171                         'tpt-discouraged-language-reason',
00172                         Xml::element( 'span',
00173                             // The reason is probably written in the content language
00174                             array(
00175                                 'lang' => $wgContLang->getCode(),
00176                                 'dir' => $wgContLang->getDir(),
00177                             ),
00178                             $priorityReason
00179                         )
00180                     )->parse();
00181                 }
00182 
00183                 $description .= Html::RawElement( 'div',
00184                     array( 'class' => $priorityMessageClass ),
00185                     $this->msg(
00186                         $priorityMessageKey,
00187                         '', // param formerly used for reason, now empty
00188                         $languageNames[$this->options['language']],
00189                         $this->getLanguage()->listToText( $priorityLanguageNames )
00190                     )->parseAsBlock() . $priorityReason
00191                 );
00192             }
00193 
00194             if ( $description ) {
00195                 $description = Xml::fieldset(
00196                     $this->msg( 'translate-page-description-legend' )->text(),
00197                     $description,
00198                     array( 'class' => 'mw-sp-translate-description' )
00199                 );
00200             }
00201 
00202             if ( $isBeta ) {
00203                 $out->addHTML( $output );
00204             } else {
00205                 $out->addHTML( $description . $output );
00206             }
00207 
00208             ApiTranslateUser::trackGroup( $this->group, $this->getUser() );
00209         }
00210 
00211         if ( $isBeta ) {
00212             $out->addHTML( Html::closeElement( 'div' ) );
00213         }
00214     }
00215 
00219     protected function getFormErrors() {
00220         $errors = array();
00221 
00222         $codes = TranslateUtils::getLanguageNames( 'en' );
00223         if ( !$this->options['language'] || !isset( $codes[$this->options['language']] ) ) {
00224             $errors['language'] = $this->msg( 'translate-page-no-such-language' )->text();
00225             $this->options['language'] = $this->defaults['language'];
00226         }
00227 
00228         if ( !$this->group instanceof MessageGroup ) {
00229             $errors['group'] = $this->msg( 'translate-page-no-such-group' )->text();
00230             $this->options['group'] = $this->defaults['group'];
00231         } else {
00232             $languages = $this->group->getTranslatableLanguages();
00233 
00234             if ( $languages !== null && !isset( $languages[$this->options['language']] ) ) {
00235                 $errors['language'] = $this->msg( 'translate-language-disabled' )->text();
00236             }
00237         }
00238 
00239         return $errors;
00240     }
00241 
00242     protected function setup( $parameters ) {
00243         $request = $this->getRequest();
00244         $isBeta = self::isBeta( $request );
00245 
00246         $defaults = array(
00247             /* str  */'taction'  => 'translate',
00248             /* str  */'task'     => $isBeta ? 'custom' : 'untranslated',
00249             /* str  */'language' => $this->getLanguage()->getCode(),
00250             /* str  */'group'    => $isBeta ? '!additions' : '',
00251             /* str  */'offset'   => '', // Used to be int, now str
00252             /* int  */'limit'    => $isBeta ? 0 : 100,
00253             /* int  */'optional' => '0',
00254         );
00255 
00256         // Dump everything here
00257         $nondefaults = array();
00258 
00259         $parameters = array_map( 'trim', explode( ';', $parameters ) );
00260         $pars = array();
00261 
00262         foreach ( $parameters as $_ ) {
00263             if ( $_ === '' ) {
00264                 continue;
00265             }
00266 
00267             if ( strpos( $_, '=' ) !== false ) {
00268                 list( $key, $value ) = array_map( 'trim', explode( '=', $_, 2 ) );
00269             } else {
00270                 $key = 'group';
00271                 $value = $_;
00272             }
00273 
00274             $pars[$key] = $value;
00275         }
00276 
00277         foreach ( $defaults as $v => $t ) {
00278             if ( is_bool( $t ) ) {
00279                 $r = isset( $pars[$v] ) ? (bool)$pars[$v] : $defaults[$v];
00280                 $r = $request->getBool( $v, $r );
00281             } elseif ( is_int( $t ) ) {
00282                 $r = isset( $pars[$v] ) ? (int)$pars[$v] : $defaults[$v];
00283                 $r = $request->getInt( $v, $r );
00284             } elseif ( is_string( $t ) ) {
00285                 $r = isset( $pars[$v] ) ? (string)$pars[$v] : $defaults[$v];
00286                 $r = $request->getText( $v, $r );
00287             }
00288 
00289             if ( !isset( $r ) ) {
00290                 throw new MWException( '$r was not set' );
00291             }
00292 
00293             wfAppendToArrayIfNotDefault( $v, $r, $defaults, $nondefaults );
00294         }
00295 
00296         // Fix defaults based on what we got
00297         if ( isset( $nondefaults['taction'] ) ) {
00298             if ( $nondefaults['taction'] === 'proofread' ) {
00299                 if ( $this->getUser()->isAllowed( 'translate-messagereview' ) ) {
00300                     $defaults['task'] = 'acceptqueue';
00301                 } else {
00302                     $defaults['task'] = 'reviewall';
00303                 }
00304             } elseif ( $nondefaults['taction'] === 'export' ) {
00305                 $defaults['task'] = '';
00306             }
00307         }
00308 
00309         if ( $isBeta ) {
00310             /* @todo fix all the places in Translate to create correct links.
00311              * The least effort way is to change them once we totally drop the
00312              * old UI. The penalty is only http redirect in some cases. More
00313              * effort would be to create utilities like makeTranslationLink
00314              * and makeProofreadLink.
00315              */
00316             $this->rewriteLegacyUrls( $nondefaults );
00317         }
00318 
00319         $this->defaults = $defaults;
00320         $this->nondefaults = $nondefaults;
00321         wfRunHooks( 'TranslateGetSpecialTranslateOptions', array( &$defaults, &$nondefaults ) );
00322 
00323         $this->options = $nondefaults + $defaults;
00324         $this->group = MessageGroups::getGroup( $this->options['group'] );
00325         $this->task = TranslateTasks::getTask( $this->options['task'] );
00326 
00327         if ( $this->group && MessageGroups::isDynamic( $this->group ) ) {
00328             $this->group->setLanguage( $this->options['language'] );
00329         }
00330     }
00331 
00332     protected function rewriteLegacyUrls( $params ) {
00333         if (
00334             !isset( $params['task'] ) &&
00335             isset( $params['taction'] ) && $params['taction'] === 'proofread'
00336         ) {
00337             $params['task'] = 'acceptqueue';
00338         }
00339 
00340         if ( !isset( $params['task'] ) || $params['task'] === 'custom' ) {
00341             return;
00342         }
00343 
00344         // Not used in TUX
00345         unset( $params['taction'], $params['limit'], $params['offset'] );
00346 
00347         $out = $this->getOutput();
00348 
00349         switch ( $params['task'] ) {
00350             case 'reviewall':
00351             case 'acceptqueue':
00352                 // @todo handle these two separately
00353                 unset( $params['task'] );
00354                 $params['action'] = 'proofread';
00355                 $out->redirect( $this->getTitle()->getLocalUrl( $params ) );
00356                 break;
00357 
00358             case 'view':
00359                 unset( $params['task'] );
00360                 $params['filter'] = '';
00361                 $out->redirect( $this->getTitle()->getLocalUrl( $params ) );
00362                 break;
00363 
00364             // Optional does not directly map to the new UI.
00365             // Handle it as untranslated with optional filter.
00366             case 'optional':
00367                 $params['optional'] = 1;
00368             case 'untranslated':
00369                 unset( $params['task'] );
00370                 $params['filter'] = '!translated';
00371                 $out->redirect( $this->getTitle()->getLocalUrl( $params ) );
00372                 break;
00373         }
00374     }
00375 
00376     protected function settingsForm( $errors ) {
00377         global $wgScript;
00378 
00379         $taction = $this->options['taction'];
00380 
00381         $selectors = array(
00382             'group' => $this->groupSelector(),
00383             'language' => $this->languageSelector(),
00384             'limit' => $this->limitSelector(),
00385         );
00386 
00387         if ( $taction === 'export' ) {
00388             unset( $selectors['limit'] );
00389         }
00390 
00391         $options = array();
00392         foreach ( $selectors as $g => $selector ) {
00393             // Give grep a chance to find the usages:
00394             // translate-page-group, translate-page-language, translate-page-limit
00395             $options[] = self::optionRow(
00396                 $this->msg( 'translate-page-' . $g )->escaped(),
00397                 $selector,
00398                 array_key_exists( $g, $errors ) ? $errors[$g] : null
00399             );
00400         }
00401 
00402         if ( $taction === 'proofread' ) {
00403             $extra = $this->taskLinks( array( 'acceptqueue', 'reviewall' ) );
00404         } elseif ( $taction === 'translate' ) {
00405             $extra = $this->taskLinks( array( 'view', 'untranslated', 'optional' ) );
00406         } elseif ( $taction === 'export' ) {
00407             $extra = $this->taskLinks( array( 'export-as-po', 'export-to-file' ) );
00408         } else {
00409             $extra = '';
00410         }
00411 
00412         $nonEssential = Html::rawElement(
00413             'span',
00414             array( 'class' => 'mw-sp-translate-nonessential' ),
00415             implode( "", $options )
00416         );
00417 
00418         $button = Xml::submitButton( $this->msg( 'translate-submit' )->text() );
00419 
00420         $formAttributes = array( 'class' => 'mw-sp-translate-settings' );
00421         if ( $this->group ) {
00422             $formAttributes['data-grouptype'] = get_class( $this->group );
00423         }
00424         $form =
00425             Html::openElement( 'fieldset', $formAttributes ) .
00426                 Html::element( 'legend', array(), $this->msg( 'translate-page-settings-legend' )->text() ) .
00427                 Html::openElement( 'form', array( 'action' => $wgScript, 'method' => 'get' ) ) .
00428                 Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
00429                 Html::hidden( 'taction', $this->options['taction'] ) .
00430                 "$nonEssential\n$extra\n$button\n" .
00431                 Html::closeElement( 'form' ) .
00432                 Html::closeElement( 'fieldset' );
00433 
00434         return $form;
00435     }
00436 
00437     protected function tuxSettingsForm() {
00438         $attrs = array( 'class' => 'row tux-editor-header' );
00439         $selectors = $this->tuxGroupSelector() .
00440             $this->tuxLanguageSelector() .
00441             $this->tuxGroupDescription() .
00442             $this->tuxWorkflowSelector() .
00443             $this->tuxGroupWarning();
00444 
00445         return Html::rawElement( 'div', $attrs, $selectors );
00446     }
00447 
00448     protected function messageSelector() {
00449         $output = Html::openElement( 'div', array( 'class' => 'row tux-messagetable-header' ) );
00450         $output .= Html::openElement( 'div', array( 'class' => 'nine columns' ) );
00451         $output .= Html::openElement( 'ul', array( 'class' => 'row tux-message-selector' ) );
00452         $userId = $this->getUser()->getId();
00453         $tabs = array(
00454             'all' => '',
00455             'untranslated' => '!translated',
00456             //'Hardest',
00457             'outdated' => 'fuzzy',
00458             'translated' => 'translated',
00459             'unproofread' => "translated|!reviewer:$userId|!last-translator:$userId",
00460         );
00461 
00462         $params = $this->nondefaults;
00463         $params['task'] = 'custom';
00464 
00465         foreach ( $tabs as $tab => $filter ) {
00466             // Possible classes and messages, for grepping:
00467             // tux-tab-all
00468             // tux-tab-untranslated
00469             // tux-tab-outdated
00470             // tux-tab-translated
00471             // tux-tab-unproofread
00472             $tabClass = "tux-tab-$tab";
00473             $taskParams = array( 'filter' => $filter ) + $params;
00474             ksort( $taskParams );
00475             $href = $this->getTitle()->getLocalUrl( $taskParams );
00476             $link = Html::element( 'a', array( 'href' => $href ), $this->msg( $tabClass ) );
00477             $output .= Html::rawElement( 'li', array(
00478                 'class' => 'column ' . $tabClass,
00479                 'data-filter' => $filter,
00480                 'data-title' => $tab,
00481             ), $link );
00482         }
00483 
00484         // Check boxes for the "more" tab.
00485         // The array keys are used as the name attribute of the checkbox.
00486         // in the id attribute as tux-option-KEY,
00487         // and and also for the data-filter attribute.
00488         // The message is shown as the check box's label.
00489         $options = array(
00490             'optional' => $this->msg( 'tux-message-filter-optional-messages-label' )->escaped(),
00491         );
00492 
00493         $container = Html::openElement( 'ul', array( 'class' => 'column tux-message-selector' ) );
00494         foreach ( $options as $optFilter => $optLabel ) {
00495             $container .= Html::rawElement( 'li',
00496                 array( 'class' => 'column' ),
00497                 Xml::checkLabel(
00498                     $optLabel,
00499                     $optFilter,
00500                     "tux-option-$optFilter",
00501                     isset( $this->nondefaults[$optFilter] ),
00502                     array( 'data-filter' => $optFilter )
00503                 )
00504             );
00505         }
00506 
00507         $container .= Html::closeElement( 'ul' );
00508 
00509         // @todo FIXME: Hard coded "ellipsis".
00510         $output .= Html::openElement( 'li', array( 'class' => 'column more' ) ) .
00511             '...' .
00512             $container .
00513             Html::closeElement( 'li' );
00514 
00515         $output .= Html::closeElement( 'ul' );
00516         $output .= Html::closeElement( 'div' ); //close nine columns
00517         $output .= Html::openElement( 'div', array( 'class' => 'three columns' ) );
00518         $output .= Html::element( 'span', array( 'class' => 'two columns tux-message-filter-box-icon' ) );
00519         $output .= Html::element( 'input', array(
00520             'class' => 'ten columns tux-message-filter-box',
00521             'type' => 'search',
00522         ) );
00523 
00524         $output .= Html::closeElement( 'div' ); // close three columns
00525 
00526         $output .= Html::closeElement( 'div' ); // close the row
00527 
00528         return $output;
00529     }
00530 
00531     protected function tuxGroupSelector() {
00532         $group = MessageGroups::getGroup( $this->options['group'] );
00533 
00534         // @todo FIXME The selector should have expanded parent-child lists
00535         $output = Html::openElement( 'div', array(
00536             'class' => 'eight columns ext-translate-msggroup-selector',
00537             'data-language' => $this->options['language'],
00538         ) ) .
00539             Html::element( 'span',
00540                 array( 'class' => 'grouptitle' ),
00541                 $this->msg( 'translate-msggroupselector-projects' )->escaped()
00542             ) .
00543             Html::element( 'span',
00544                 array( 'class' => 'grouptitle grouplink expanded' ),
00545                 $this->msg( 'translate-msggroupselector-search-all' )->escaped()
00546             ) .
00547             Html::element( 'span',
00548                 array(
00549                     'class' => 'grouptitle grouplink tail',
00550                     'data-msggroupid' => $this->options['group'],
00551                 ),
00552                 $group->getLabel()
00553             ) .
00554             Html::closeElement( 'div' );
00555 
00556         return $output;
00557     }
00558 
00559     protected function tuxLanguageSelector() {
00560         // Changes here must also be reflected when the language
00561         // changes on the client side
00562         global $wgTranslateDocumentationLanguageCode;
00563 
00564         if ( $this->options['language'] === $wgTranslateDocumentationLanguageCode ) {
00565             // The name will be displayed in the UI language,
00566             // so use for lang and dir
00567             $targetLangCode = $this->getLanguage()->getCode();
00568             $targetLangDir = $this->getLanguage()->getDir();
00569             $targetLangName = $this->msg( 'translate-documentation-language' )->text();
00570         } else {
00571             $targetLangCode = $this->options['language'];
00572             $targetLangDir = Language::factory( $this->options['language'] )->getDir();
00573             $targetLangName = Language::fetchLanguageName( $this->options['language'] );
00574         }
00575 
00576         // No-break space is added for spacing after the label
00577         // and to ensure separation of words (in Arabic, for example)
00578         return Html::rawElement( 'div',
00579             array( 'class' => 'four columns ext-translate-language-selector' ),
00580             Html::element( 'span',
00581                 array( 'class' => 'ext-translate-language-selector-label' ),
00582                 $this->msg( 'tux-languageselector' )->text()
00583             ) .
00584                 '&#160;' . // nbsp
00585                 Html::element( 'span',
00586                     array(
00587                         'class' => 'uls',
00588                         'lang' => $targetLangCode,
00589                         'dir' => $targetLangDir,
00590                     ),
00591                     $targetLangName
00592                 )
00593         );
00594     }
00595 
00596     protected function tuxGroupDescription() {
00597         return Html::rawElement(
00598             'div',
00599             array( 'class' => 'twelve columns description' ),
00600             $this->getGroupDescription( $this->group )
00601         );
00602     }
00603 
00604     protected function tuxGroupWarning() {
00605         // Initialize an empty warning box to be filled client-side.
00606         return Html::element(
00607             'div',
00608             array( 'class' => 'twelve columns group-warning' ),
00609             ''
00610         );
00611     }
00612 
00619     private static function optionRow( $label, $option, $error = null ) {
00620         return "<label>$label&nbsp;$option</label>" .
00621             ( $error ?
00622                 Html::rawElement( 'span', array( 'class' => 'mw-sp-translate-error' ), $error ) :
00623                 ''
00624             ) . ' ';
00625     }
00626 
00627     protected function taskLinks( $tasks ) {
00628         $user = $this->getUser();
00629 
00630         foreach ( $tasks as $index => $id ) {
00631             $task = TranslateTasks::getTask( $id );
00632 
00633             if ( !$task ) {
00634                 unset( $tasks[$index] );
00635                 continue;
00636             }
00637 
00638             if ( !$task->isAllowedFor( $user ) ) {
00639                 unset( $tasks[$index] );
00640                 continue;
00641             }
00642         }
00643 
00644         $sep = Html::element( 'br' );
00645         $count = count( $tasks );
00646         if ( $count === 0 ) {
00647             return $sep . $this->msg( 'translate-taction-disabled' )->escaped();
00648         } elseif ( $count === 1 ) {
00649             $id = array_pop( $tasks );
00650 
00651             // If there is only one task, and it is the default task, hide it.
00652             // If someone disables the default task for action, we will show
00653             // a list of alternative task(s), but not showing anything
00654             // by default. */
00655             if ( $this->defaults['task'] === $id ) {
00656                 return '';
00657             }
00658 
00659             // Give grep a chance to find the usages:
00660             // translate-taskui-view, translate-taskui-untranslated, translate-taskui-optional,
00661             // translate-taskui-acceptqueue, translate-taskui-reviewall,
00662             // translate-taskui-export-to-file, translate-taskui-export-as-po
00663             return $sep . Html::rawElement( 'label', array(),
00664                 Xml::radio( 'task', $id, true ) . ' ' .
00665                     $this->msg( "translate-taskui-$id" )->escaped()
00666             );
00667         } else {
00668             $output = '';
00669 
00670             foreach ( $tasks as $id ) {
00671                 // Give grep a chance to find the usages:
00672                 // translate-taskui-view, translate-taskui-untranslated, translate-taskui-optional,
00673                 // translate-taskui-acceptqueue, translate-taskui-reviewall,
00674                 // translate-taskui-export-to-file, translate-taskui-export-as-po
00675                 $output .= Html::rawElement( 'label', array(),
00676                     Xml::radio( 'task', $id, $this->options['task'] === $id ) . ' ' .
00677                         $this->msg( "translate-taskui-$id" )->escaped()
00678                 ) . ' ';
00679             }
00680 
00681             return $sep . $output;
00682         }
00683     }
00684 
00685     protected function groupSelector() {
00686         $groups = MessageGroups::getAllGroups();
00687         uasort( $groups, array( 'MessageGroups', 'groupLabelSort' ) );
00688         $dynamic = MessageGroups::getDynamicGroups();
00689         $groups = array_keys( array_merge( $dynamic, $groups ) );
00690 
00691         $selected = $this->options['group'];
00692 
00693         $selector = new XmlSelect( 'group', 'group' );
00694         $selector->setDefault( $selected );
00695 
00696         foreach ( $groups as $id ) {
00697             $group = MessageGroups::getGroup( $id );
00698             $hide = MessageGroups::getPriority( $group ) === 'discouraged';
00699 
00700             if ( !$group->exists() || ( $hide && $id !== $selected ) ) {
00701                 continue;
00702             }
00703 
00704             $selector->addOption( $group->getLabel(), $id );
00705         }
00706 
00707         return $selector->getHTML();
00708     }
00709 
00710     protected function languageSelector() {
00711         return TranslateUtils::languageSelector(
00712             $this->getLanguage()->getCode(),
00713             $this->options['language']
00714         );
00715     }
00716 
00717     protected function limitSelector() {
00718         $items = array( 100, 1000, 5000 );
00719         $selector = new XmlSelect( 'limit', 'limit' );
00720         $selector->setDefault( $this->options['limit'] );
00721 
00722         foreach ( $items as $count ) {
00723             $selector->addOption(
00724                 $this->msg( 'translate-page-limit-option' )->numParams( $count )->text(),
00725                 $count
00726             );
00727         }
00728 
00729         return $selector->getHTML();
00730     }
00731 
00732     protected function getGroupDescription( MessageGroup $group ) {
00733         $description = $group->getDescription( $this->getContext() );
00734         if ( $description !== null ) {
00735             return $this->getOutput()->parse( $description, false );
00736         }
00737 
00738         return '';
00739     }
00740 
00745     public function groupInformation() {
00746         $output = $this->getOutput();
00747 
00748         // If we get here in the TUX mode, it means that invalid group
00749         // was requested. There is default group for no params case.
00750         if ( self::isBeta( $this->getRequest() ) ) {
00751             $output->addHtml( Html::rawElement(
00752                 'div',
00753                 array( 'class' => 'twelve columns group-warning' ),
00754                 $this->msg( 'tux-translate-page-no-such-group' )->parse()
00755             ) );
00756         }
00757 
00758         $output->addHtml(
00759             Html::openElement( 'div', array(
00760                 'class' => 'eight columns ext-translate-msggroup-selector',
00761                 'data-language' => $this->options['language'],
00762             ) ) .
00763                 '<span class="grouptitle">' .
00764                 $this->msg( 'translate-msggroupselector-projects' )->escaped() .
00765                 '</span>
00766             <span class="grouptitle grouplink tail">' .
00767                 $this->msg( 'translate-msggroupselector-search-all' )->escaped() .
00768                 '</span>
00769             </div>'
00770         );
00771     }
00772 
00773     protected function tuxWorkflowSelector() {
00774         return Html::element( 'div', array( 'class' => 'tux-workflow twelve columns' ) );
00775     }
00776 
00777     protected function getWorkflowStatus() {
00778         $stateConfig = $this->group->getMessageGroupStates()->getStates();
00779         if ( !$stateConfig ) {
00780             return false;
00781         }
00782 
00783         if ( MessageGroups::isDynamic( $this->group ) ) {
00784             return false;
00785         }
00786 
00787         $dbr = wfGetDB( DB_SLAVE );
00788         $current = $dbr->selectField(
00789             'translate_groupreviews',
00790             'tgr_state',
00791             array( 'tgr_group' => $this->options['group'], 'tgr_lang' => $this->options['language'] ),
00792             __METHOD__
00793         );
00794 
00795         $options = array();
00796         $stateConfig = array_merge(
00797             array( '' => array( 'right' => 'impossible-right' ) ),
00798             $stateConfig
00799         );
00800 
00801         $user = $this->getUser();
00802         if ( $user->isAllowed( 'translate-groupreview' ) ) {
00803             // Add an option for every state
00804             foreach ( $stateConfig as $state => $config ) {
00805                 $stateMessage = $this->msg( "translate-workflow-state-$state" );
00806                 $stateText = $stateMessage->isBlank() ? $state : $stateMessage->text();
00807 
00808                 $attributes = array(
00809                     'value' => $state,
00810                 );
00811 
00812                 if ( $state === strval( $current ) ) {
00813                     $attributes['selected'] = 'selected';
00814                 }
00815 
00816                 if ( is_array( $config ) && isset( $config['right'] )
00817                     && !$user->isAllowed( $config['right'] )
00818                 ) {
00819                     // Grey out the forbidden option
00820                     $attributes['disabled'] = 'disabled';
00821                 }
00822 
00823                 $options[] = Html::element( 'option', $attributes, $stateText );
00824             }
00825             $stateIndicator = Html::rawElement( 'select',
00826                 array(
00827                     'class' => 'mw-translate-workflowselector',
00828                     'name' => 'workflow',
00829                 ),
00830                 implode( "\n", $options )
00831             );
00832 
00833             $setButtonAttributes = array(
00834                 'type' => 'button',
00835                 'id' => 'mw-translate-workflowset',
00836                 'data-token' => ApiGroupReview::getToken( 0, '' ),
00837                 'data-group' => $this->options['group'],
00838                 'data-language' => $this->options['language'],
00839                 'style' => 'visibility: hidden;',
00840                 'value' => 'Set',
00841             );
00842             $stateIndicator .= Html::element( 'input', $setButtonAttributes );
00843         } elseif ( strval( $current ) !== '' ) {
00844             $stateIndicator = $current;
00845         } else {
00846             $stateIndicator = $this->msg( 'translate-workflow-state-' )->escaped();
00847         }
00848 
00849         $message = $this->msg( 'translate-workflowstatus' )->rawParams( $stateIndicator );
00850         $box = Html::rawElement(
00851             'div',
00852             array( 'id' => 'mw-sp-translate-workflow' ),
00853             $message->escaped()
00854         );
00855 
00856         return $box;
00857     }
00858 
00864     static function tabify( Skin $skin, array &$tabs ) {
00865         $title = $skin->getTitle();
00866         list( $alias, $sub ) = SpecialPageFactory::resolveAlias( $title->getText() );
00867 
00868         $pagesInGroup = array( 'Translate', 'LanguageStats', 'MessageGroupStats' );
00869         if ( !in_array( $alias, $pagesInGroup, true ) ) {
00870             return true;
00871         }
00872 
00873         $skin->getOutput()->addModules( 'ext.translate.tabgroup' );
00874 
00875         // Extract subpage syntax, otherwise the values are not passed forward
00876         $params = array();
00877         if ( trim( $sub ) !== '' ) {
00878             if ( $alias === 'Translate' || $alias === 'MessageGroupStats' ) {
00879                 $params['group'] = $sub;
00880             } elseif ( $alias === 'LanguageStats' ) {
00881                 // Breaks if additional parameters besides language are code provided
00882                 $params['language'] = $sub;
00883             }
00884         }
00885 
00886         $request = $skin->getRequest();
00887         // However, query string params take precedence
00888         $params['language'] = $request->getVal( 'language' );
00889         $params['group'] = $request->getVal( 'group' );
00890 
00891         $taction = $request->getVal( 'taction', 'translate' );
00892 
00893         $translate = SpecialPage::getTitleFor( 'Translate' );
00894         $languagestats = SpecialPage::getTitleFor( 'LanguageStats' );
00895         $messagegroupstats = SpecialPage::getTitleFor( 'MessageGroupStats' );
00896 
00897         // Clear the special page tab that might be there already
00898         $tabs['namespaces'] = array();
00899 
00900         $tabs['namespaces']['translate'] = array(
00901             'text' => wfMessage( 'translate-taction-translate' )->text(),
00902             'href' => $translate->getLocalUrl( $params ),
00903             'class' => 'tux-tab',
00904         );
00905 
00906         if ( $alias === 'Translate' && $taction === 'translate' ) {
00907             $tabs['namespaces']['translate']['class'] .= ' selected';
00908         }
00909 
00910         if ( !self::isBeta( $request ) ) {
00911             $tabs['namespaces']['proofread'] = array(
00912                 'text' => wfMessage( 'translate-taction-proofread' )->text(),
00913                 'href' => $translate->getLocalUrl( array( 'taction' => 'proofread' ) + $params ),
00914                 'class' => 'tux-tab',
00915             );
00916 
00917             if ( $alias === 'Translate' && $taction === 'proofread' ) {
00918                 $tabs['namespaces']['proofread']['class'] .= ' selected';
00919             }
00920         }
00921 
00922         $tabs['views']['lstats'] = array(
00923             'text' => wfMessage( 'translate-taction-lstats' )->text(),
00924             'href' => $languagestats->getLocalUrl( $params ),
00925             'class' => 'tux-tab',
00926         );
00927         if ( $alias === 'LanguageStats' ) {
00928             $tabs['views']['lstats']['class'] .= ' selected';
00929         }
00930 
00931         $tabs['views']['mstats'] = array(
00932             'text' => wfMessage( 'translate-taction-mstats' )->text(),
00933             'href' => $messagegroupstats->getLocalUrl( $params ),
00934             'class' => 'tux-tab',
00935         );
00936 
00937         if ( $alias === 'MessageGroupStats' ) {
00938             $tabs['views']['mstats']['class'] .= ' selected';
00939         }
00940 
00941         // Kind of hackish, but works for now
00942         global $wgTranslateTasks;
00943         foreach ( array_keys( $wgTranslateTasks ) as $taskname ) {
00944             if ( !preg_match( '/^export-/', $taskname ) ) {
00945                 continue;
00946             }
00947 
00948             $tabs['views']['export'] = array(
00949                 'text' => wfMessage( 'translate-taction-export' )->text(),
00950                 'href' => $translate->getLocalUrl( array( 'taction' => 'export' ) + $params ),
00951                 'class' => 'tux-tab',
00952             );
00953 
00954             if ( $alias === 'Translate' && $taction === 'export' ) {
00955                 $tabs['views']['export']['class'] .= ' selected';
00956             }
00957 
00958             // We only need the tab to apper once ;)
00959             break;
00960         }
00961 
00962         return true;
00963     }
00964 
00965     public static function isBeta( WebRequest $request ) {
00966         global $wgTranslateUseTux;
00967 
00968         $tux = $request->getVal( 'tux', null );
00969 
00970         if ( $tux === null ) {
00971             $tux = $request->getCookie( 'tux', null, $wgTranslateUseTux );
00972         } elseif ( $tux ) {
00973             $request->response()->setCookie( 'tux', 1 );
00974         } else {
00975             $request->response()->setCookie( 'tux', 0 );
00976         }
00977 
00978         return $tux;
00979     }
00980 }
Generated on Tue Oct 29 00:00:24 2013 for MediaWiki Translate Extension by  doxygen 1.6.3