00001 <?php
00016 class PageTranslationHooks {
00017
00018 public static $allowTargetEdit = false;
00019
00027 public static function renderTagPage( $parser, &$text, $state ) {
00028 $title = $parser->getTitle();
00029
00030 if ( strpos( $text, '<translate>' ) !== false ) {
00031 try {
00032 $parse = TranslatablePage::newFromText( $parser->getTitle(), $text )->getParse();
00033 $text = $parse->getTranslationPageText( null );
00034 } catch ( TPException $e ) {
00035
00036 wfDebug( 'TPException caught; expected' );
00037 }
00038 }
00039
00040
00041 $page = TranslatablePage::isTranslationPage( $title );
00042 if ( !$page ) {
00043 return true;
00044 }
00045
00046 list( , $code ) = TranslateUtils::figureMessage( $title->getText() );
00047 $name = $page->getPageDisplayTitle( $code );
00048
00049 if ( $name ) {
00050 $name = $parser->recursivePreprocess( $name );
00051 $parser->getOutput()->setDisplayTitle( $name );
00052 }
00053
00054
00055 $parser->getOptions()->setEditSection( false );
00056
00057 return true;
00058 }
00059
00064 public static function onPageContentLanguage( Title $title, &$pageLang ) {
00065
00066
00067 if ( TranslatablePage::isTranslationPage( $title ) ) {
00068 list( , $code ) = TranslateUtils::figureMessage( $title->getText() );
00069 $pageLang = $code;
00070 }
00071
00072 return true;
00073 }
00074
00076 public static function injectCss( OutputPage $out, $text ) {
00077 global $wgTranslatePageTranslationULS;
00078
00079 $title = $out->getTitle();
00080 if ( TranslatablePage::isSourcePage( $title ) ||
00081 TranslatablePage::isTranslationPage( $title )
00082 ) {
00083 $out->addModules( 'ext.translate' );
00084 if ( $wgTranslatePageTranslationULS ) {
00085 $out->addModules( 'ext.translate.pagetranslation.uls' );
00086 }
00087 }
00088
00089 return true;
00090 }
00091
00098 public static function onSectionSave( $wikiPage, User $user, $content, $summary,
00099 $minor, $_, $_, $flags, $revision
00100 ) {
00101 $title = $wikiPage->getTitle();
00102
00103 if ( $content instanceof TextContent ) {
00104 $text = $content->getNativeData();
00105 } elseif ( is_string( $content ) ) {
00106
00107 $text = $content;
00108 } else {
00109
00110 return true;
00111 }
00112
00113
00114 $handle = new MessageHandle( $title );
00115
00116
00117 if ( !$handle->isPageTranslation() || !$handle->isValid() ) {
00118 return true;
00119 }
00120
00121
00122 if ( strpos( $text, TRANSLATE_FUZZY ) !== false ) {
00123 return true;
00124 }
00125
00126 $group = $handle->getGroup();
00127 if ( !$group instanceof WikiPageMessageGroup ) {
00128 return true;
00129 }
00130
00131
00132 $page = TranslatablePage::newFromTitle( $group->getTitle() );
00133
00134
00135 if ( !$handle->isDoc() ) {
00136 $code = $handle->getCode();
00137 self::updateTranslationPage( $page, $code, $user, $flags, $summary );
00138 }
00139
00140 return true;
00141 }
00142
00143 public static function updateTranslationPage( TranslatablePage $page,
00144 $code, $user, $flags, $summary
00145 ) {
00146 $source = $page->getTitle();
00147 $target = Title::makeTitle( $source->getNamespace(), $source->getDBkey() . "/$code" );
00148
00149
00150 $flags &= ~EDIT_NEW & ~EDIT_UPDATE;
00151
00152
00153 $job = TranslateRenderJob::newJob( $target );
00154 $job->setUser( $user );
00155 $job->setSummary( $summary );
00156 $job->setFlags( $flags );
00157 $job->run();
00158
00159
00160 $page->getTranslationPercentages( 'force' );
00161
00162
00163 $pages = $page->getTranslationPages();
00164 foreach ( $pages as $title ) {
00165 $article = new Article( $title, 0 );
00166 $article->doPurge();
00167 }
00168
00169
00170 $article = new Article( $page->getTitle(), 0 );
00171 $article->doPurge();
00172 }
00173
00180 public static function languages( $data, $params, $parser ) {
00181 $currentTitle = $parser->getTitle();
00182
00183
00184 $page = TranslatablePage::newFromTitle( $currentTitle );
00185 if ( $page->getMarkedTag() === false ) {
00186 $page = TranslatablePage::isTranslationPage( $currentTitle );
00187 }
00188
00189 if ( $page === false || $page->getMarkedTag() === false ) {
00190 return '';
00191 }
00192
00193 $status = $page->getTranslationPercentages();
00194 if ( !$status ) {
00195 return '';
00196 }
00197
00198
00199 $priorityLangs = TranslateMetadata::get( $page->getMessageGroupId(), 'prioritylangs' );
00200 $priorityForce = TranslateMetadata::get( $page->getMessageGroupId(), 'priorityforce' );
00201 $filter = null;
00202 if ( strlen( $priorityLangs ) > 0 ) {
00203 $filter = array_flip( explode( ',', $priorityLangs ) );
00204 }
00205 if ( $filter !== null ) {
00206
00207 if ( $priorityForce === 'on' ) {
00208
00209 $filter[$page->getMessageGroup()->getSourceLanguage()] = true;
00210 $status = array_intersect_key( $status, $filter );
00211 }
00212 foreach ( $filter as $langCode => $value ) {
00213 if ( !isset( $status[$langCode] ) ) {
00214
00215 $status[$langCode] = 0;
00216 }
00217 }
00218 }
00219
00220
00221 $pageTitle = $page->getTitle();
00222
00223
00224 ksort( $status );
00225
00226
00227 $userLangCode = $parser->getOptions()->getUserLang();
00228 $userLangDir = $parser->getOptions()->getUserLangObj()->getDir();
00229
00230
00231
00232 $sourceLanguage = $pageTitle->getPageLanguage()->getCode();
00233
00234 $languages = array();
00235 foreach ( $status as $code => $percent ) {
00236
00237 $name = TranslateUtils::getLanguageName( $code, $code );
00238 $name = htmlspecialchars( $name );
00239
00240
00241
00242 $percent *= 100;
00243 if ( $percent < 20 ) {
00244 $image = 1;
00245 } elseif ( $percent < 40 ) {
00246 $image = 2;
00247 } elseif ( $percent < 60 ) {
00248 $image = 3;
00249 } elseif ( $percent < 80 ) {
00250 $image = 4;
00251 } else {
00252 $image = 5;
00253 }
00254
00255 $percentImage = Xml::element( 'img', array(
00256 'src' => TranslateUtils::assetPath( "resources/images/prog-$image.png" ),
00257 'alt' => wfMessage( 'percent', $percent )->text(),
00258 'title' => wfMessage( 'percent', $percent )->text(),
00259 'width' => '9',
00260 'height' => '9',
00261 ) );
00262
00263
00264 $suffix = ( $code === $sourceLanguage ) ? '' : "/$code";
00265 $targetTitleString = $pageTitle->getDBkey() . $suffix;
00266 $subpage = Title::makeTitle( $pageTitle->getNamespace(), $targetTitleString );
00267
00268 $classes = array();
00269 if ( $code === $userLangCode ) {
00270 $classes[] = 'mw-pt-languages-ui';
00271 }
00272
00273 if ( $currentTitle->equals( $subpage ) ) {
00274 $classes[] = 'mw-pt-languages-selected';
00275 }
00276
00277 if ( count( $classes ) ) {
00278 $attribs = array( 'class' => implode( ' ', $classes ) );
00279 $name = Html::rawElement( 'span', $attribs, $name );
00280 }
00281
00282 if ( $currentTitle->equals( $subpage ) ) {
00283
00284 } elseif ( $subpage->isKnown() ) {
00285 $name = Linker::linkKnown( $subpage, $name );
00286 } else {
00287
00288
00289
00290 $specialTranslateTitle = SpecialPage::getTitleFor( 'Translate' );
00291 $params = array(
00292 'group' => $page->getMessageGroupId(),
00293 'language' => $code,
00294 'task' => 'view'
00295 );
00296 $attribs = array(
00297 'title' => wfMessage( 'tpt-languages-zero' )->text(),
00298 'class' => 'new',
00299 );
00300 $name = Linker::link( $specialTranslateTitle, $name, $attribs, $params );
00301 }
00302
00303 $languages[] = "$name $percentImage";
00304 }
00305
00306
00307
00308 $lang = Language::factory( $userLangCode );
00309 $sep = wfMessage( 'tpt-languages-separator' )->inLanguage( $lang )->plain();
00310 $sep .= $lang->getDirMark();
00311 $languages = implode( $sep, $languages );
00312
00313 $out = Html::openElement( 'div', array(
00314 'class' => 'mw-pt-languages noprint',
00315 'lang' => $userLangCode,
00316 'dir' => $userLangDir
00317 ) );
00318 $out .= Html::openElement( 'table' );
00319 $out .= Html::openElement( 'tbody' );
00320 $out .= Html::openElement( 'tr', array( 'valign' => 'top' ) );
00321 $out .= Html::rawElement( 'td',
00322 array( 'class' => 'mw-pt-languages-label' ),
00323 wfMessage( 'tpt-languages-legend' )->escaped()
00324 );
00325 $out .= Html::rawElement( 'td',
00326 array( 'class' => 'mw-pt-languages-list autonym' ),
00327 $languages
00328 );
00329 $out .= Html::closeElement( 'tr' );
00330 $out .= Html::closeElement( 'tbody' );
00331 $out .= Html::closeElement( 'table' );
00332 $out .= Html::closeElement( 'div' );
00333
00334 return $out;
00335 }
00336
00341 public static function tpSyntaxCheckForEditContent( $context, $content, $status, $summary ) {
00342 if ( !( $content instanceof TextContent ) ) {
00343 return true;
00344 }
00345
00346 $text = $content->getNativeData();
00347 $title = $context->getTitle();
00348
00349 $e = self::tpSyntaxError( $title, $text );
00350
00351 if ( $e ) {
00352 $msg = $e->getMsg();
00353
00354
00355
00356 call_user_func_array( array( $status, 'fatal' ), $msg );
00357 }
00358
00359 return true;
00360 }
00361
00366 public static function tpSyntaxCheckForEditPage( $editpage, $text, &$error, $summary ) {
00367 $title = $editpage->getTitle();
00368 $e = self::tpSyntaxError( $title, $text );
00369
00370 if ( $e ) {
00371 $error .= Html::rawElement( 'div', array( 'class' => 'error' ), $e->getMessage() );
00372 }
00373
00374 return true;
00375 }
00376
00380 protected static function tpSyntaxError( $title, $text ) {
00381 if ( strpos( $text, '<translate>' ) === false ) {
00382 return null;
00383 }
00384
00385 $page = TranslatablePage::newFromText( $title, $text );
00386 try {
00387 $page->getParse();
00388
00389 return null;
00390 } catch ( TPException $e ) {
00391 return $e;
00392 }
00393 }
00394
00400 public static function tpSyntaxCheck( $wikiPage, $user, $content, $summary,
00401 $minor, $_, $_, $flags, $status
00402 ) {
00403 if ( $content instanceof TextContent ) {
00404 $text = $content->getNativeData();
00405 } elseif ( is_string( $content ) ) {
00406
00407 $text = $content;
00408 } else {
00409
00410 return true;
00411 }
00412
00413
00414 if ( strpos( $text, '<translate>' ) === false ) {
00415 return true;
00416 }
00417
00418 $page = TranslatablePage::newFromText( $wikiPage->getTitle(), $text );
00419 try {
00420 $page->getParse();
00421 } catch ( TPException $e ) {
00422 call_user_func_array( array( $status, 'fatal' ), $e->getMsg() );
00423
00424 return false;
00425 }
00426
00427 return true;
00428 }
00429
00433 public static function addTranstag( $wikiPage, $user, $content, $summary,
00434 $minor, $_, $_, $flags, $revision
00435 ) {
00436
00437 if ( $revision === null ) {
00438 return true;
00439 }
00440
00441 if ( $content instanceof TextContent ) {
00442 $text = $content->getNativeData();
00443 } elseif ( is_string( $content ) ) {
00444
00445 $text = $content;
00446 } else {
00447
00448 return true;
00449 }
00450
00451
00452 if ( strpos( $text, '</translate>' ) === false ) {
00453 return true;
00454 }
00455
00456
00457 $page = TranslatablePage::newFromTitle( $wikiPage->getTitle() );
00458 $page->addReadyTag( $revision->getId() );
00459
00460 return true;
00461 }
00462
00479 public static function updateTranstagOnNullRevisions( Revision $rev, $text, $flags ) {
00480 $title = $rev->getTitle();
00481
00482
00483
00484
00485 if ( !$title ) {
00486 return true;
00487 }
00488
00489 $newRevId = $rev->getId();
00490 $oldRevId = $rev->getParentId();
00491 $newTextId = $rev->getTextId();
00492
00493
00494
00495 $dbw = wfGetDB( DB_MASTER );
00496 $table = 'revision';
00497 $field = 'rev_text_id';
00498 $conds = array(
00499 'rev_page' => $rev->getPage(),
00500 'rev_id' => $oldRevId,
00501 );
00502
00503 $oldTextId = $dbw->selectField( $table, $field, $conds, __METHOD__ );
00504
00505 if ( strval( $newTextId ) !== strval( $oldTextId ) ) {
00506
00507 return true;
00508 }
00509
00510 $page = TranslatablePage::newFromTitle( $title );
00511 if ( $page->getReadyTag() === $oldRevId ) {
00512 $page->addReadyTag( $newRevId );
00513 }
00514
00515 return true;
00516 }
00517
00522 public static function preventUnknownTranslations( Title $title, User $user,
00523 $action, &$result
00524 ) {
00525 $handle = new MessageHandle( $title );
00526 if ( $handle->isPageTranslation() && $action === 'edit' ) {
00527 if ( !$handle->isValid() ) {
00528 $result = array( 'tpt-unknown-page' );
00529
00530 return false;
00531 }
00532 }
00533
00534 return true;
00535 }
00536
00542 public static function preventRestrictedTranslations( Title $title, User $user,
00543 $action, &$result
00544 ) {
00545 global $wgTranslateDocumentationLanguageCode;
00546
00547 if ( $action !== 'edit' ) {
00548 return true;
00549 }
00550
00551 $handle = new MessageHandle( $title );
00552 if ( !$handle->isValid() ) {
00553 return true;
00554 }
00555
00556
00557 $ids = $handle->getGroupIds();
00558 $groupId = $ids[0];
00559
00560
00561 $force = TranslateMetadata::get( $groupId, 'priorityforce' );
00562 if ( $force !== 'on' ) {
00563 return true;
00564 }
00565
00566
00567 if ( $handle->getCode() === $wgTranslateDocumentationLanguageCode ) {
00568 return true;
00569 }
00570
00571
00572 $languages = TranslateMetadata::get( $groupId, 'prioritylangs' );
00573 $filter = array_flip( explode( ',', $languages ) );
00574 if ( !isset( $filter[$handle->getCode()] ) ) {
00575
00576 $reason = TranslateMetadata::get( $groupId, 'priorityreason' );
00577 $result = array( 'tpt-translation-restricted', $reason );
00578
00579 return false;
00580 }
00581
00582 return true;
00583 }
00584
00589 public static function preventDirectEditing( Title $title, User $user, $action, &$result ) {
00590 $page = TranslatablePage::isTranslationPage( $title );
00591 $whitelist = array(
00592 'read' => true,
00593 'delete' => true,
00594 'review' => true,
00595 );
00596
00597 if ( $page !== false && !isset( $whitelist[$action] ) ) {
00598 if ( self::$allowTargetEdit ) {
00599 return true;
00600 }
00601
00602 if ( $page->getMarkedTag() ) {
00603 list( , $code ) = TranslateUtils::figureMessage( $title->getText() );
00604 $result = array(
00605 'tpt-target-page',
00606 $page->getTitle()->getPrefixedText(),
00607
00608 wfExpandUrl( $page->getTranslationUrl( $code ) )
00609 );
00610
00611 return false;
00612 }
00613 }
00614
00615 return true;
00616 }
00617
00628 public static function disableDelete( $article, $out, &$reason ) {
00629 $title = $article->getTitle();
00630 if ( TranslatablePage::isSourcePage( $title ) ||
00631 TranslatablePage::isTranslationPage( $title )
00632 ) {
00633 $new = SpecialPage::getTitleFor(
00634 'PageTranslationDeletePage',
00635 $title->getPrefixedText()
00636 );
00637 $out->redirect( $new->getFullUrl() );
00638 }
00639
00640 return true;
00641 }
00642
00651 public static function translatablePageHeader( &$article, &$outputDone, &$pcache ) {
00652 if ( $article->getOldID() ) {
00653 return true;
00654 }
00655
00656 $title = $article->getTitle();
00657
00658 if ( TranslatablePage::isTranslationPage( $title ) ) {
00659 self::translationPageHeader( $title );
00660 } else {
00661
00662 self::sourcePageHeader( $title );
00663 }
00664
00665 return true;
00666 }
00667
00668 protected static function sourcePageHeader( Title $title ) {
00669 $context = RequestContext::getMain();
00670
00671 $page = TranslatablePage::newFromTitle( $title );
00672
00673 $marked = $page->getMarkedTag();
00674 $ready = $page->getReadyTag();
00675
00676 $title = $page->getTitle();
00677
00678 $latest = $title->getLatestRevId();
00679 $canmark = $ready === $latest && $marked !== $latest;
00680
00681 $actions = array();
00682
00683 if ( $marked && $context->getUser()->isAllowed( 'translate' ) ) {
00684 $par = array(
00685 'group' => $page->getMessageGroupId(),
00686 'language' => $context->getLanguage()->getCode(),
00687 'task' => 'view'
00688 );
00689
00690 $translate = SpecialPage::getTitleFor( 'Translate' );
00691 $linkDesc = $context->msg( 'translate-tag-translate-link-desc' )->escaped();
00692 $actions[] = Linker::link( $translate, $linkDesc, array(), $par );
00693 }
00694
00695 if ( $canmark ) {
00696 $diffUrl = $title->getFullUrl( array( 'oldid' => $marked, 'diff' => $latest ) );
00697 $par = array( 'target' => $title->getPrefixedText() );
00698 $translate = SpecialPage::getTitleFor( 'PageTranslation' );
00699
00700 if ( $context->getUser()->isAllowed( 'pagetranslation' ) ) {
00701
00702 if ( $marked === false ) {
00703 $linkDesc = $context->msg( 'translate-tag-markthis' )->escaped();
00704 $actions[] = Linker::link( $translate, $linkDesc, array(), $par );
00705 } else {
00706 $markUrl = $translate->getFullUrl( $par );
00707 $actions[] = $context->msg( 'translate-tag-markthisagain', $diffUrl, $markUrl )
00708 ->parse();
00709 }
00710 } else {
00711 $actions[] = $context->msg( 'translate-tag-hasnew', $diffUrl )->parse();
00712 }
00713 }
00714
00715 if ( !count( $actions ) ) {
00716 return;
00717 }
00718
00719 $legend = Html::rawElement(
00720 'div',
00721 array( 'class' => 'mw-pt-translate-header noprint nomobile' ),
00722 $context->getLanguage()->semicolonList( $actions )
00723 ) . Html::element( 'hr' );
00724
00725 $context->getOutput()->addHTML( $legend );
00726 }
00727
00728 protected static function translationPageHeader( Title $title ) {
00729 if ( !$title->exists() ) {
00730 return;
00731 }
00732
00733
00734 $page = TranslatablePage::isTranslationPage( $title );
00735 if ( $page === false ) {
00736 return;
00737 }
00738
00739 list( , $code ) = TranslateUtils::figureMessage( $title->getText() );
00740
00741
00742 $pers = $page->getTranslationPercentages();
00743 $per = 0;
00744 if ( isset( $pers[$code] ) ) {
00745 $per = $pers[$code] * 100;
00746 }
00747 $titleText = $page->getTitle()->getPrefixedText();
00748
00749
00750 $url = wfExpandUrl( $page->getTranslationUrl( $code ), PROTO_RELATIVE );
00751
00752
00753 $wrap = '<div class="mw-translate-page-info">$1</div>';
00754 $out = RequestContext::getMain()->getOutput();
00755
00756 $out->wrapWikiMsg( $wrap, array( 'tpt-translation-intro', $url, $titleText, $per ) );
00757 $out->addHTML( '<hr />' );
00758 }
00759
00761 public static function replaceMovePage( &$list ) {
00762 $old = is_array( $list['Movepage'] );
00763 $list['Movepage'] = array( 'SpecialPageTranslationMovePage', $old );
00764
00765 return true;
00766 }
00767
00769 public static function lockedPagesCheck( Title $title, User $user, $action, &$result ) {
00770 if ( $action == 'read' ) {
00771 return true;
00772 }
00773
00774 $cache = wfGetCache( CACHE_ANYTHING );
00775 $key = wfMemcKey( 'pt-lock', sha1( $title->getPrefixedText() ) );
00776
00777 if ( $cache->get( $key ) == true ) {
00778 $result = array( 'pt-locked-page' );
00779
00780 return false;
00781 }
00782
00783 return true;
00784 }
00785
00787 public static function replaceSubtitle( &$subpages, $skin = null, OutputPage $out ) {
00788 if ( !TranslatablePage::isTranslationPage( $out->getTitle() )
00789 && !TranslatablePage::isSourcePage( $out->getTitle() )
00790 ) {
00791 return true;
00792 }
00793
00794
00795 if ( $out->isArticle() && MWNamespace::hasSubpages( $out->getTitle()->getNamespace() ) ) {
00796 $ptext = $out->getTitle()->getPrefixedText();
00797 if ( preg_match( '/\//', $ptext ) ) {
00798 $links = explode( '/', $ptext );
00799 array_pop( $links );
00800
00801 if ( TranslatablePage::isTranslationPage( $out->getTitle() ) ) {
00802 array_pop( $links );
00803 }
00804 $c = 0;
00805 $growinglink = '';
00806 $display = '';
00807
00808 foreach ( $links as $link ) {
00809 $growinglink .= $link;
00810 $display .= $link;
00811 $linkObj = Title::newFromText( $growinglink );
00812
00813 if ( is_object( $linkObj ) && $linkObj->exists() ) {
00814 $getlink = Linker::linkKnown(
00815 SpecialPage::getTitleFor( 'MyLanguage', $growinglink ),
00816 htmlspecialchars( $display )
00817 );
00818
00819 $c++;
00820
00821 if ( $c > 1 ) {
00822 $subpages .= wfMessage( 'pipe-separator' )->plain();
00823 } else {
00824
00825
00826 }
00827
00828 $subpages .= $getlink;
00829 $display = '';
00830 } else {
00831 $display .= '/';
00832 }
00833
00834 $growinglink .= '/';
00835 }
00836 }
00837
00838 return false;
00839 }
00840
00841 return true;
00842 }
00843
00845 public static function sourceExport( RequestContext $context,
00846 TranslateTask $task = null, MessageGroup $group, array $options
00847 ) {
00848 if ( $task || $options['taction'] !== 'export'
00849 || !$group instanceof WikiPageMessageGroup
00850 ) {
00851 return true;
00852 }
00853
00854 $page = TranslatablePage::newFromTitle( $group->getTitle() );
00855 $collection = $group->initCollection( $options['language'] );
00856 $collection->loadTranslations( DB_MASTER );
00857 $text = $page->getParse()->getTranslationPageText( $collection );
00858 $display = $page->getPageDisplayTitle( $options['language'] );
00859 if ( $display ) {
00860 $text = "{{DISPLAYTITLE:$display}}$text";
00861 }
00862 $output = Html::element( 'textarea', array( 'rows' => 25 ), $text );
00863 $context->getOutput()->addHtml( $output );
00864
00865 return false;
00866 }
00867
00873 static function translateTab( Skin $skin, array &$tabs ) {
00874 $title = $skin->getTitle();
00875
00876 $page = TranslatablePage::isTranslationPage( $title );
00877 if ( !$page ) {
00878 return true;
00879 }
00880
00881 $handle = new MessageHandle( $title );
00882 $code = $handle->getCode();
00883
00884 if ( isset( $tabs['views']['edit'] ) ) {
00885 $tabs['views']['edit']['text'] = $skin->msg( 'tpt-tab-translate' )->text();
00886 $tabs['views']['edit']['href'] = $page->getTranslationUrl( $code );
00887 }
00888
00889 return true;
00890 }
00891 }