setHeaders(); $user = $this->getUser(); $request = $this->getRequest(); $target = $request->getText( 'target', $parameters ); $revision = $request->getInt( 'revision', 0 ); $action = $request->getVal( 'do' ); $out = $this->getOutput(); $out->addModules( 'ext.translate.special.pagetranslation' ); $out->addHelpLink( 'Help:Extension:Translate/Page_translation_example' ); if ( $target === '' ) { $this->listPages(); return; } // Anything else than listing the pages need permissions if ( !$user->isAllowed( 'pagetranslation' ) ) { throw new PermissionsError( 'pagetranslation' ); } $title = Title::newFromText( $target ); if ( !$title ) { $out->addWikiMsg( 'tpt-badtitle' ); return; } elseif ( !$title->exists() ) { $out->addWikiMsg( 'tpt-nosuchpage', $title->getPrefixedText() ); return; } // Check token for all POST actions here if ( $request->wasPosted() && !$user->matchEditToken( $request->getText( 'token' ) ) ) { throw new PermissionsError( 'pagetranslation' ); } if ( $action === 'mark' ) { // Has separate form $this->onActionMark( $title, $revision ); return; } // On GET requests, show form which has token if ( !$request->wasPosted() ) { if ( $action === 'unlink' ) { $this->showUnlinkConfirmation( $title, $target ); } else { $params = [ 'do' => $action, 'target' => $title->getPrefixedText(), 'revision' => $revision ]; $this->showGenericConfirmation( $params ); } return; } if ( $action === 'discourage' || $action === 'encourage' ) { $id = TranslatablePage::getMessageGroupIdFromTitle( $title ); $current = MessageGroups::getPriority( $id ); if ( $action === 'encourage' ) { $new = ''; } else { $new = 'discouraged'; } if ( $new !== $current ) { MessageGroups::setPriority( $id, $new ); $entry = new ManualLogEntry( 'pagetranslation', $action ); $entry->setPerformer( $user ); $entry->setTarget( $title ); $logid = $entry->insert(); $entry->publish( $logid ); } $this->listPages(); $group = MessageGroups::getGroup( $id ); $parents = MessageGroups::getSharedGroups( $group ); MessageGroupStats::clearGroup( $parents ); return; } if ( $action === 'unlink' ) { $page = TranslatablePage::newFromTitle( $title ); $content = ContentHandler::makeContent( self::getStrippedSourcePageText( $page->getParse() ), $title ); $status = WikiPage::factory( $title )->doEditContent( $content, $this->msg( 'tpt-unlink-summary' )->inContentLanguage()->text(), EDIT_FORCE_BOT | EDIT_UPDATE ); if ( !$status->isOK() ) { $out->wrapWikiMsg( '
$1
', [ 'tpt-edit-failed', $status->getWikiText() ] ); return; } $page = TranslatablePage::newFromTitle( $title ); $this->unmarkPage( $page, $user ); $out->wrapWikiMsg( '
$1
', [ 'tpt-unmarked', $title->getPrefixedText() ] ); $this->listPages(); return; } if ( $action === 'unmark' ) { $page = TranslatablePage::newFromTitle( $title ); $this->unmarkPage( $page, $user ); $out->wrapWikiMsg( '
$1
', [ 'tpt-unmarked', $title->getPrefixedText() ] ); $this->listPages(); return; } } protected function onActionMark( Title $title, $revision ) { $request = $this->getRequest(); $out = $this->getOutput(); $out->addModuleStyles( 'ext.translate.special.pagetranslation.styles' ); if ( $revision === 0 ) { // Get the latest revision $revision = (int)$title->getLatestRevID(); } $page = TranslatablePage::newFromRevision( $title, $revision ); if ( !$page instanceof TranslatablePage ) { $out->wrapWikiMsg( '
$1
', [ 'tpt-notsuitable', $title->getPrefixedText(), $revision ] ); return; } if ( $revision !== (int)$title->getLatestRevID() ) { // We do want to notify the reviewer if the underlying page changes during review $target = $title->getFullURL( [ 'oldid' => $revision ] ); $link = "[$target $revision]"; $out->wrapWikiMsg( '
$1
', [ 'tpt-oldrevision', $title->getPrefixedText(), $link ] ); $this->listPages(); return; } $lastRev = $page->getMarkedTag(); $firstMark = $lastRev === false; if ( !$firstMark && $lastRev === $revision ) { $out->wrapWikiMsg( '
$1
', [ 'tpt-already-marked' ] ); $this->listPages(); return; } // This will modify the sections to include name property $error = false; $sections = $this->checkInput( $page, $error ); // Non-fatal error which prevents saving if ( $error === false && $request->wasPosted() ) { // Check if user wants to translate title // If not, remove it from the list of sections if ( !$request->getCheck( 'translatetitle' ) ) { $sections = array_filter( $sections, function ( $s ) { return $s->id !== 'Page display title'; } ); } $err = $this->markForTranslation( $page, $sections ); if ( $err ) { call_user_func_array( [ $out, 'addWikiMsg' ], $err ); } else { $this->showSuccess( $page, $firstMark ); $this->listPages(); } return; } $this->showPage( $page, $sections ); } /** * Displays success message and other instructions after a page has been marked for translation. * @param TranslatablePage $page * @param bool $firstMark true if it is the first time the page is being marked for translation. */ public function showSuccess( TranslatablePage $page, $firstMark = false ) { $titleText = $page->getTitle()->getPrefixedText(); $num = $this->getLanguage()->formatNum( $page->getParse()->countSections() ); $link = SpecialPage::getTitleFor( 'Translate' )->getFullURL( [ 'group' => $page->getMessageGroupId(), 'action' => 'page', 'filter' => '', ] ); $this->getOutput()->wrapWikiMsg( '
$1
', [ 'tpt-saveok', $titleText, $num, $link ] ); // If the page is being marked for translation for the first time // add a link to Special:PageMigration. if ( $firstMark ) { $this->getOutput()->addWikiMsg( 'tpt-saveok-first' ); } // If TranslationNotifications is installed, and the user can notify // translators, add a convenience link. if ( method_exists( 'SpecialNotifyTranslators', 'execute' ) && $this->getUser()->isAllowed( SpecialNotifyTranslators::$right ) ) { $link = SpecialPage::getTitleFor( 'NotifyTranslators' )->getFullURL( [ 'tpage' => $page->getTitle()->getArticleID() ] ); $this->getOutput()->addWikiMsg( 'tpt-offer-notify', $link ); } } protected function showGenericConfirmation( array $params ) { $formParams = [ 'method' => 'post', 'action' => $this->getPageTitle()->getFullURL(), ]; $params['title'] = $this->getPageTitle()->getPrefixedText(); $params['token'] = $this->getUser()->getEditToken(); $hidden = ''; foreach ( $params as $key => $value ) { $hidden .= Html::hidden( $key, $value ); } $this->getOutput()->addHTML( Html::openElement( 'form', $formParams ) . $hidden . $this->msg( 'tpt-generic-confirm' )->parseAsBlock() . Xml::submitButton( $this->msg( 'tpt-generic-button' )->text(), [ 'class' => 'mw-ui-button mw-ui-progressive' ] ) . Html::closeElement( 'form' ) ); } protected function showUnlinkConfirmation( Title $target ) { $formParams = [ 'method' => 'post', 'action' => $this->getPageTitle()->getFullURL(), ]; $this->getOutput()->addHTML( Html::openElement( 'form', $formParams ) . Html::hidden( 'do', 'unlink' ) . Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) . Html::hidden( 'target', $target->getPrefixedText() ) . Html::hidden( 'token', $this->getUser()->getEditToken() ) . $this->msg( 'tpt-unlink-confirm', $target->getPrefixedText() )->parseAsBlock() . Xml::submitButton( $this->msg( 'tpt-unlink-button' )->text(), [ 'class' => 'mw-ui-button mw-ui-destructive' ] ) . Html::closeElement( 'form' ) ); } protected function unmarkPage( TranslatablePage $page, $user ) { $page->unmarkTranslatablePage(); $page->getTitle()->invalidateCache(); $entry = new ManualLogEntry( 'pagetranslation', 'unmark' ); $entry->setPerformer( $user ); $entry->setTarget( $page->getTitle() ); $logid = $entry->insert(); $entry->publish( $logid ); } public function loadPagesFromDB() { $dbr = TranslateUtils::getSafeReadDB(); $tables = [ 'page', 'revtag' ]; $vars = [ 'page_id', 'page_title', 'page_namespace', 'page_latest', 'MAX(rt_revision) AS rt_revision', 'rt_type' ]; $conds = [ 'page_id=rt_page', 'rt_type' => [ RevTag::getType( 'tp:mark' ), RevTag::getType( 'tp:tag' ) ], ]; $options = [ 'ORDER BY' => 'page_namespace, page_title', 'GROUP BY' => 'page_id, rt_type', ]; $res = $dbr->select( $tables, $vars, $conds, __METHOD__, $options ); return $res; } protected function buildPageArray( /*db result*/$res ) { $pages = []; foreach ( $res as $r ) { // We have multiple rows for same page, because of different tags if ( !isset( $pages[$r->page_id] ) ) { $pages[$r->page_id] = []; $title = Title::newFromRow( $r ); $pages[$r->page_id]['title'] = $title; $pages[$r->page_id]['latest'] = (int)$title->getLatestRevID(); } $tag = RevTag::typeToTag( $r->rt_type ); $pages[$r->page_id][$tag] = (int)$r->rt_revision; } return $pages; } /** * @param array $in * @return array */ protected function classifyPages( array $in ) { $out = [ 'proposed' => [], 'active' => [], 'broken' => [], 'discouraged' => [], ]; foreach ( $in as $index => $page ) { if ( !isset( $page['tp:mark'] ) ) { // Never marked, check that the latest version is ready if ( $page['tp:tag'] === $page['latest'] ) { $out['proposed'][$index] = $page; } // Otherwise ignore such pages } elseif ( $page['tp:tag'] === $page['latest'] ) { // Marked and latest version if fine $out['active'][$index] = $page; } else { // Marked but latest version if not fine $out['broken'][$index] = $page; } } // broken and proposed take preference over discouraged status foreach ( $out['active'] as $index => $page ) { $id = TranslatablePage::getMessageGroupIdFromTitle( $page['title'] ); $group = MessageGroups::getGroup( $id ); if ( MessageGroups::getPriority( $group ) === 'discouraged' ) { $out['discouraged'][$index] = $page; unset( $out['active'][$index] ); } } return $out; } public function listPages() { $out = $this->getOutput(); $res = $this->loadPagesFromDB(); $allPages = $this->buildPageArray( $res ); if ( !count( $allPages ) ) { $out->addWikiMsg( 'tpt-list-nopages' ); return; } $lb = new LinkBatch(); $lb->setCaller( __METHOD__ ); foreach ( $allPages as $page ) { $lb->addObj( $page['title'] ); } $lb->execute(); $types = $this->classifyPages( $allPages ); $pages = $types['proposed']; if ( count( $pages ) ) { $out->wrapWikiMsg( '== $1 ==', 'tpt-new-pages-title' ); $out->addWikiMsg( 'tpt-new-pages', count( $pages ) ); $out->addHTML( '
    ' ); foreach ( $pages as $page ) { $link = Linker::link( $page['title'] ); $acts = $this->actionLinks( $page, 'proposed' ); $out->addHTML( "
  1. $link $acts
  2. " ); } $out->addHTML( '
' ); } $pages = $types['active']; if ( count( $pages ) ) { $out->wrapWikiMsg( '== $1 ==', 'tpt-old-pages-title' ); $out->addWikiMsg( 'tpt-old-pages', count( $pages ) ); $out->addHTML( '
    ' ); foreach ( $pages as $page ) { $link = Linker::link( $page['title'] ); if ( $page['tp:mark'] !== $page['tp:tag'] ) { $link = "$link"; } $acts = $this->actionLinks( $page, 'active' ); $out->addHTML( "
  1. $link $acts
  2. " ); } $out->addHTML( '
' ); } $pages = $types['broken']; if ( count( $pages ) ) { $out->wrapWikiMsg( '== $1 ==', 'tpt-other-pages-title' ); $out->addWikiMsg( 'tpt-other-pages', count( $pages ) ); $out->addHTML( '
    ' ); foreach ( $pages as $page ) { $link = Linker::link( $page['title'] ); $acts = $this->actionLinks( $page, 'broken' ); $out->addHTML( "
  1. $link $acts
  2. " ); } $out->addHTML( '
' ); } $pages = $types['discouraged']; if ( count( $pages ) ) { $out->wrapWikiMsg( '== $1 ==', 'tpt-discouraged-pages-title' ); $out->addWikiMsg( 'tpt-discouraged-pages', count( $pages ) ); $out->addHTML( '
    ' ); foreach ( $pages as $page ) { $link = Linker::link( $page['title'] ); if ( $page['tp:mark'] !== $page['tp:tag'] ) { $link = "$link"; } $acts = $this->actionLinks( $page, 'discouraged' ); $out->addHTML( "
  1. $link $acts
  2. " ); } $out->addHTML( '
' ); } } /** * @param array $page * @param string $type * @return string */ protected function actionLinks( array $page, $type ) { $actions = []; /** * @var Title $title */ $title = $page['title']; $user = $this->getUser(); // Class to allow one-click POSTs $js = [ 'class' => 'mw-translate-jspost' ]; if ( $user->isAllowed( 'pagetranslation' ) ) { $pending = $type === 'active' && $page['latest'] !== $page['tp:mark']; if ( $type === 'proposed' || $pending ) { $actions[] = Linker::linkKnown( $this->getPageTitle(), $this->msg( 'tpt-rev-mark' )->escaped(), [ 'title' => $this->msg( 'tpt-rev-mark-tooltip' )->text() ], [ 'do' => 'mark', 'target' => $title->getPrefixedText(), 'revision' => $title->getLatestRevID(), ] ); } if ( $type === 'active' ) { $actions[] = Linker::linkKnown( $this->getPageTitle(), $this->msg( 'tpt-rev-discourage' )->escaped(), [ 'title' => $this->msg( 'tpt-rev-discourage-tooltip' )->text() ] + $js, [ 'do' => 'discourage', 'target' => $title->getPrefixedText(), 'revision' => -1, ] ); } elseif ( $type === 'discouraged' ) { $actions[] = Linker::linkKnown( $this->getPageTitle(), $this->msg( 'tpt-rev-encourage' )->escaped(), [ 'title' => $this->msg( 'tpt-rev-encourage-tooltip' )->text() ] + $js, [ 'do' => 'encourage', 'target' => $title->getPrefixedText(), 'revision' => -1, ] ); } if ( $type !== 'proposed' ) { $actions[] = Linker::linkKnown( $this->getPageTitle(), $this->msg( 'tpt-rev-unmark' )->escaped(), [ 'title' => $this->msg( 'tpt-rev-unmark-tooltip' )->text() ], [ 'do' => $type === 'broken' ? 'unmark' : 'unlink', 'target' => $title->getPrefixedText(), 'revision' => -1, ] ); } } if ( !count( $actions ) ) { return ''; } $flattened = $this->getLanguage()->semicolonList( $actions ); return Html::rawElement( 'span', [ 'class' => 'mw-tpt-actions' ], $this->msg( 'parentheses' )->rawParams( $flattened )->escaped() ); } /** * @param TranslatablePage $page * @param bool &$error * @return TPSection[] The array has string keys. */ public function checkInput( TranslatablePage $page, &$error ) { $usedNames = []; $highest = (int)TranslateMetadata::get( $page->getMessageGroupId(), 'maxid' ); $parse = $page->getParse(); $sections = $parse->getSectionsForSave( $highest ); foreach ( $sections as $s ) { // We need to do checks for both new and existing sections. // Someone might have tampered with the page source adding // duplicate or invalid markers. if ( isset( $usedNames[$s->id] ) ) { $this->getOutput()->addWikiMsg( 'tpt-duplicate', $s->id ); $error = true; } $usedNames[$s->id] = true; $s->name = $s->id; } return $sections; } /** * Displays the sections and changes for the user to review * @param TranslatablePage $page * @param TPSection[] $sections */ public function showPage( TranslatablePage $page, array $sections ) { $out = $this->getOutput(); $out->setSubtitle( Linker::link( $page->getTitle() ) ); $out->addWikiMsg( 'tpt-showpage-intro' ); $formParams = [ 'method' => 'post', 'action' => $this->getPageTitle()->getFullURL(), 'class' => 'mw-tpt-sp-markform', ]; $out->addHTML( Xml::openElement( 'form', $formParams ) . Html::hidden( 'do', 'mark' ) . Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) . Html::hidden( 'revision', $page->getRevision() ) . Html::hidden( 'target', $page->getTitle()->getPrefixedText() ) . Html::hidden( 'token', $this->getUser()->getEditToken() ) ); $out->wrapWikiMsg( '==$1==', 'tpt-sections-oldnew' ); $diffOld = $this->msg( 'tpt-diff-old' )->escaped(); $diffNew = $this->msg( 'tpt-diff-new' )->escaped(); $hasChanges = false; // Check whether page title was previously marked for translation. // If the page is marked for translation the first time, default to checked. $defaultChecked = $page->hasPageDisplayTitle(); $sourceLanguage = Language::factory( $page->getSourceLanguageCode() ); foreach ( $sections as $s ) { if ( $s->name === 'Page display title' ) { // Set section type as new if title previously unchecked $s->type = $defaultChecked ? $s->type : 'new'; // Checkbox for page title optional translation $this->getOutput()->addHTML( Xml::checkLabel( $this->msg( 'tpt-translate-title' )->text(), 'translatetitle', 'mw-translate-title', $defaultChecked ) ); } if ( $s->type === 'new' ) { $hasChanges = true; $name = $this->msg( 'tpt-section-new', $s->name )->escaped(); } else { $name = $this->msg( 'tpt-section', $s->name )->escaped(); } if ( $s->type === 'changed' ) { $hasChanges = true; $diff = new DifferenceEngine; $diff->setTextLanguage( $sourceLanguage ); $diff->setReducedLineNumbers(); $oldContent = ContentHandler::makeContent( $s->getOldText(), $diff->getTitle() ); $newContent = ContentHandler::makeContent( $s->getText(), $diff->getTitle() ); $diff->setContent( $oldContent, $newContent ); $text = $diff->getDiff( $diffOld, $diffNew ); $diffOld = $diffNew = null; $diff->showDiffStyle(); $id = "tpt-sect-{$s->id}-action-nofuzzy"; $checkLabel = Xml::checkLabel( $this->msg( 'tpt-action-nofuzzy' )->text(), $id, $id, false ); $text = $checkLabel . $text; } else { $text = TranslateUtils::convertWhiteSpaceToHTML( $s->getText() ); } # For changed text, the language is set by $diff->setTextLanguage() $lang = $s->type === 'changed' ? null : $sourceLanguage; $out->addHTML( MessageWebImporter::makeSectionElement( $name, $s->type, $text, $lang ) ); } $deletedSections = $page->getParse()->getDeletedSections(); if ( count( $deletedSections ) ) { $hasChanges = true; $out->wrapWikiMsg( '==$1==', 'tpt-sections-deleted' ); /** * @var TPSection $s */ foreach ( $deletedSections as $s ) { $name = $this->msg( 'tpt-section-deleted', $s->id )->escaped(); $text = TranslateUtils::convertWhiteSpaceToHTML( $s->getText() ); $out->addHTML( MessageWebImporter::makeSectionElement( $name, $s->type, $text, $sourceLanguage ) ); } } // Display template changes if applicable if ( $page->getMarkedTag() !== false ) { $hasChanges = true; $newTemplate = $page->getParse()->getTemplatePretty(); $oldPage = TranslatablePage::newFromRevision( $page->getTitle(), $page->getMarkedTag() ); $oldTemplate = $oldPage->getParse()->getTemplatePretty(); if ( $oldTemplate !== $newTemplate ) { $out->wrapWikiMsg( '==$1==', 'tpt-sections-template' ); $diff = new DifferenceEngine; $diff->setTextLanguage( $sourceLanguage ); $oldContent = ContentHandler::makeContent( $oldTemplate, $diff->getTitle() ); $newContent = ContentHandler::makeContent( $newTemplate, $diff->getTitle() ); $diff->setContent( $oldContent, $newContent ); $text = $diff->getDiff( $this->msg( 'tpt-diff-old' )->escaped(), $this->msg( 'tpt-diff-new' )->escaped() ); $diff->showDiffStyle(); $diff->setReducedLineNumbers(); $contentParams = [ 'class' => 'mw-tpt-sp-content' ]; $out->addHTML( Xml::tags( 'div', $contentParams, $text ) ); } } if ( !$hasChanges ) { $out->wrapWikiMsg( '
$1
', 'tpt-mark-nochanges' ); } $this->priorityLanguagesForm( $page ); $out->addHTML( Xml::submitButton( $this->msg( 'tpt-submit' )->text() ) . Xml::closeElement( 'form' ) ); } /** * @param TranslatablePage $page */ protected function priorityLanguagesForm( TranslatablePage $page ) { global $wgContLang; $groupId = $page->getMessageGroupId(); $this->getOutput()->wrapWikiMsg( '==$1==', 'tpt-sections-prioritylangs' ); $langSelector = Xml::languageSelector( $wgContLang->getCode(), false, $this->getLanguage()->getCode() ); $hLangs = Xml::inputLabelSep( $this->msg( 'tpt-select-prioritylangs' )->text(), 'prioritylangs', // name 'tpt-prioritylangs', // id 50, TranslateMetadata::get( $groupId, 'prioritylangs' ) ); $hForce = Xml::checkLabel( $this->msg( 'tpt-select-prioritylangs-force' )->text(), 'forcelimit', // name 'tpt-priority-forcelimit', // id TranslateMetadata::get( $groupId, 'priorityforce' ) === 'on' ); $hReason = Xml::inputLabelSep( $this->msg( 'tpt-select-prioritylangs-reason' )->text(), 'priorityreason', // name 'tpt-priority-reason', // id 50, // size TranslateMetadata::get( $groupId, 'priorityreason' ) ); $this->getOutput()->addHTML( '' . '' . "" . "" . '' . "" . '' . "" . "" . '' . '
$hLangs[0]$hLangs[1]$langSelector[1]
$hForce
$hReason[0]$hReason[1]
' ); } /** * This function does the heavy duty of marking a page. * - Updates the source page with section markers. * - Updates translate_sections table * - Updates revtags table * - Setups renderjobs to update the translation pages * - Invalidates caches * @param TranslatablePage $page * @param TPSection[] $sections * @return array|bool */ public function markForTranslation( TranslatablePage $page, array $sections ) { // Add the section markers to the source page $wikiPage = WikiPage::factory( $page->getTitle() ); $content = ContentHandler::makeContent( $page->getParse()->getSourcePageText(), $page->getTitle() ); $status = $wikiPage->doEditContent( $content, $this->msg( 'tpt-mark-summary' )->inContentLanguage()->text(), EDIT_FORCE_BOT | EDIT_UPDATE ); if ( !$status->isOK() ) { return [ 'tpt-edit-failed', $status->getWikiText() ]; } $newrevision = $status->value['revision']; // In theory it is either null or Revision object, // never revision object with null id, but who knows if ( $newrevision instanceof Revision ) { $newrevision = $newrevision->getId(); } if ( $newrevision === null ) { // Probably a no-change edit, so no new revision was assigned. // Get the latest revision manually $newrevision = $page->getTitle()->getLatestRevID(); } $inserts = []; $changed = []; $maxid = (int)TranslateMetadata::get( $page->getMessageGroupId(), 'maxid' ); $pageId = $page->getTitle()->getArticleID(); /** * @var TPSection $s */ foreach ( array_values( $sections ) as $index => $s ) { $maxid = max( $maxid, (int)$s->name ); $changed[] = $s->name; if ( $this->getRequest()->getCheck( "tpt-sect-{$s->id}-action-nofuzzy" ) ) { // TranslationsUpdateJob will only fuzzy when type is changed $s->type = 'old'; } $inserts[] = [ 'trs_page' => $pageId, 'trs_key' => $s->name, 'trs_text' => $s->getText(), 'trs_order' => $index ]; } $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'translate_sections', [ 'trs_page' => $page->getTitle()->getArticleID() ], __METHOD__ ); $dbw->insert( 'translate_sections', $inserts, __METHOD__ ); TranslateMetadata::set( $page->getMessageGroupId(), 'maxid', $maxid ); $page->addMarkedTag( $newrevision ); MessageGroups::singleton()->recache(); $job = TranslationsUpdateJob::newFromPage( $page, $sections ); JobQueueGroup::singleton()->push( $job ); // Logging $this->handlePriorityLanguages( $this->getRequest(), $page ); $entry = new ManualLogEntry( 'pagetranslation', 'mark' ); $entry->setPerformer( $this->getUser() ); $entry->setTarget( $page->getTitle() ); $entry->setParameters( [ 'revision' => $newrevision, 'changed' => count( $changed ), ] ); $logid = $entry->insert(); $entry->publish( $logid ); // Clear more caches $page->getTitle()->invalidateCache(); return false; } /** * @param WebRequest $request * @param TranslatablePage $page */ protected function handlePriorityLanguages( WebRequest $request, TranslatablePage $page ) { // new priority languages $npLangs = rtrim( trim( $request->getVal( 'prioritylangs' ) ), ',' ); $npForce = $request->getCheck( 'forcelimit' ) ? 'on' : 'off'; $npReason = trim( $request->getText( 'priorityreason' ) ); // Normalize $npLangs = array_map( 'trim', explode( ',', $npLangs ) ); $npLangs = array_unique( $npLangs ); // Remove invalid language codes. $languages = Language::fetchLanguageNames(); foreach ( $npLangs as $index => $language ) { if ( !array_key_exists( $language, $languages ) ) { unset( $npLangs[$index] ); } } $npLangs = implode( ',', $npLangs ); if ( $npLangs === '' ) { $npLangs = false; $npForce = false; $npReason = false; } $groupId = $page->getMessageGroupId(); // old priority languages $opLangs = TranslateMetadata::get( $groupId, 'prioritylangs' ); $opForce = TranslateMetadata::get( $groupId, 'priorityforce' ); $opReason = TranslateMetadata::get( $groupId, 'priorityreason' ); TranslateMetadata::set( $groupId, 'prioritylangs', $npLangs ); TranslateMetadata::set( $groupId, 'priorityforce', $npForce ); TranslateMetadata::set( $groupId, 'priorityreason', $npReason ); if ( $opLangs !== $npLangs || $opForce !== $npForce || $opReason !== $npReason ) { $params = [ 'languages' => $npLangs, 'force' => $npForce, 'reason' => $npReason, ]; $entry = new ManualLogEntry( 'pagetranslation', 'prioritylanguages' ); $entry->setPerformer( $this->getUser() ); $entry->setTarget( $page->getTitle() ); $entry->setParameters( $params ); $entry->setComment( $npReason ); $logid = $entry->insert(); $entry->publish( $logid ); } } /** * Returns the source page without any translation markup. * * @param TPParse $parse * @return string * @since 2014.09 */ public static function getStrippedSourcePageText( TPParse $parse ) { $text = $parse->getTranslationPageText( [] ); $text = preg_replace( '~\n?~s', '', $text ); return $text; } }