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( "- $link $acts
" );
}
$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( "- $link $acts
" );
}
$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( "- $link $acts
" );
}
$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( "- $link $acts
" );
}
$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;
}
}