Merge "Expose the log_id of the deletion log entry in the action=delete API"
authorSiebrand <s.mazeland@xs4all.nl>
Sun, 1 Jul 2012 15:55:29 +0000 (15:55 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sun, 1 Jul 2012 15:55:29 +0000 (15:55 +0000)
1  2 
docs/hooks.txt
includes/Article.php
includes/FileDeleteForm.php
includes/Title.php
includes/WikiPage.php
includes/api/ApiDelete.php
includes/specials/SpecialMovepage.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc

diff --combined docs/hooks.txt
@@@ -331,11 -331,6 +331,11 @@@ descriptions
  &$module: ApiBase Module object
  &$desc: Array of parameter descriptions
  
 +'APIGetResultProperties': use this hook to mofify the properties
 +in a module's result.
 +&$module: ApiBase Module object
 +&$properties: Array of properties
 +
  'APIQueryAfterExecute': after calling the execute() method of an
  action=query submodule. Use this to extend core API modules.
  &$module: Module object
@@@ -427,6 -422,8 +427,8 @@@ $user: the user (object) deleting the a
  $reason: the reason (string) the article is being deleted
  $error: if the deletion was prohibited, the (raw HTML) error message to display
    (added in 1.13)
+ $status: Status object, modify this to throw an error. Overridden by $error
+   (added in 1.20)
  
  'ArticleDeleteComplete': after an article is deleted
  $article: the WikiPage that was deleted
@@@ -677,10 -674,6 +679,10 @@@ $output: OutputPage object in us
  'CategoryPageView': before viewing a categorypage in CategoryPage::view
  $catpage: CategoryPage instance
  
 +'ChangePasswordForm': For extensions that need to add a field to the ChangePassword form
 +via the Preferences form
 +&$extraFields: An array of arrays that hold fields like would be passed to the pretty function.
 +
  'ChangesListInsertArticleLink': Override or augment link to article in RC list.
  &$changesList: ChangesList instance.
  &$articlelink: HTML of link to article (already filled-in).
@@@ -930,14 -923,6 +932,14 @@@ $fileVersions: array of undeleted versi
  $user: user who performed the undeletion
  $reason: reason
  
 +'FormatAutocomments': When an autocomment is formatted by the Linker
 + &$comment: Reference to the accumulated comment. Initially null, when set the default code will be skipped.
 + $pre: Initial part of the parsed comment before the call to the hook.
 + $auto: The extracted part of the parsed comment before the call to the hook.
 + $post: The final part of the parsed comment before the call to the hook.
 + $title: An optional title object used to links to sections. Can be null.
 + $local: Boolean indicating whether section links should refer to local page.
 +
  'GetAutoPromoteGroups': When determining which autopromote groups a user
  is entitled to be in.
  &$user: user to promote.
@@@ -1368,11 -1353,6 +1370,11 @@@ using this hook
        BaseTemplate::makeListItem for details on the format of individual
        items inside of this array
  
 +'NamespaceIsMovable': Called when determining if it is possible to pages in a namespace.
 +$index: Integer; the index of the namespace being checked.
 +$result: Boolean; whether MediaWiki currently thinks that pages in this namespace are movable.
 +Hooks may change this value to override the return value of MWNamespace::isMovable()
 +
  'NewRevisionFromEditComplete': called when a revision was inserted
  due to an edit
  $article: the WikiPage edited
diff --combined includes/Article.php
@@@ -1,22 -1,6 +1,22 @@@
  <?php
  /**
 - * File for articles
 + * User interface for page actions.
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + * http://www.gnu.org/copyleft/gpl.html
 + *
   * @file
   */
  
@@@ -25,7 -9,7 +25,7 @@@
   *
   * This maintains WikiPage functions for backwards compatibility.
   *
 - * @TODO: move and rewrite code to an Action class
 + * @todo move and rewrite code to an Action class
   *
   * See design.txt for an overview.
   * Note: edit user interface and cache support functions have been
@@@ -39,69 -23,42 +39,69 @@@ class Article extends Page 
         */
  
        /**
 -       * @var IContextSource
 +       * The context this Article is executed in
 +       * @var IContextSource $mContext
         */
        protected $mContext;
  
        /**
 -       * @var WikiPage
 +       * The WikiPage object of this instance
 +       * @var WikiPage $mPage
         */
        protected $mPage;
  
        /**
 -       * @var ParserOptions: ParserOptions object for $wgUser articles
 +       * ParserOptions object for $wgUser articles
 +       * @var ParserOptions $mParserOptions
         */
        public $mParserOptions;
  
 +      /**
 +       * Content of the revision we are working on
 +       * @var string $mContent
 +       */
        var $mContent;                    // !<
 +
 +      /**
 +       * Is the content ($mContent) already loaded?
 +       * @var bool $mContentLoaded
 +       */
        var $mContentLoaded = false;      // !<
 +
 +      /**
 +       * The oldid of the article that is to be shown, 0 for the
 +       * current revision
 +       * @var int|null $mOldId
 +       */
        var $mOldId;                      // !<
  
        /**
 -       * @var Title
 +       * Title from which we were redirected here
 +       * @var Title $mRedirectedFrom
         */
        var $mRedirectedFrom = null;
  
        /**
 -       * @var mixed: boolean false or URL string
 +       * URL to redirect to or false if none
 +       * @var string|false $mRedirectUrl
         */
        var $mRedirectUrl = false;        // !<
 +
 +      /**
 +       * Revision ID of revision we are working on
 +       * @var int $mRevIdFetched
 +       */
        var $mRevIdFetched = 0;           // !<
  
        /**
 -       * @var Revision
 +       * Revision we are working on
 +       * @var Revision $mRevision
         */
        var $mRevision = null;
  
        /**
 -       * @var ParserOutput
 +       * ParserOutput object
 +       * @var ParserOutput $mParserOutput
         */
        var $mParserOutput;
  
                if ( $outputPage->isPrintable() ) {
                        $parserOptions->setIsPrintable( true );
                        $parserOptions->setEditSection( false );
 -              } elseif ( !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit' ) ) {
 +              } elseif ( !$this->isCurrent() || !$this->getTitle()->quickUserCan( 'edit', $user ) ) {
                        $parserOptions->setEditSection( false );
                }
  
         * merging of several policies using array_merge().
         * @param $policy Mixed, returns empty array on null/false/'', transparent
         *            to already-converted arrays, converts String.
 -       * @return Array: 'index' => <indexpolicy>, 'follow' => <followpolicy>
 +       * @return Array: 'index' => \<indexpolicy\>, 'follow' => \<followpolicy\>
         */
        public static function formatRobotPolicy( $policy ) {
                if ( is_array( $policy ) ) {
                $user = $this->getContext()->getUser();
                $rcid = $request->getVal( 'rcid' );
  
 -              if ( !$rcid || !$this->getTitle()->quickUserCan( 'patrol' ) ) {
 +              if ( !$rcid || !$this->getTitle()->quickUserCan( 'patrol', $user ) ) {
                        return;
                }
  
                } elseif ( $this->getTitle()->getNamespace() === NS_MEDIAWIKI ) {
                        // Use the default message text
                        $text = $this->getTitle()->getDefaultMessageText();
 +              } elseif ( $this->getTitle()->quickUserCan( 'create', $this->getContext()->getUser() )
 +                      && $this->getTitle()->quickUserCan( 'edit', $this->getContext()->getUser() )
 +              ) {
 +                      $text = wfMsgNoTrans( 'noarticletext' );
                } else {
 -                      $createErrors = $this->getTitle()->getUserPermissionsErrors( 'create', $this->getContext()->getUser() );
 -                      $editErrors = $this->getTitle()->getUserPermissionsErrors( 'edit', $this->getContext()->getUser() );
 -                      $errors = array_merge( $createErrors, $editErrors );
 -
 -                      if ( !count( $errors ) ) {
 -                              $text = wfMsgNoTrans( 'noarticletext' );
 -                      } else {
 -                              $text = wfMsgNoTrans( 'noarticletext-nopermission' );
 -                      }
 +                      $text = wfMsgNoTrans( 'noarticletext-nopermission' );
                }
                $text = "<div class='noarticletext'>\n$text\n</div>";
  
  
                $current = ( $oldid == $this->mPage->getLatest() );
                $language = $this->getContext()->getLanguage();
 -              $td = $language->timeanddate( $timestamp, true );
 -              $tddate = $language->date( $timestamp, true );
 -              $tdtime = $language->time( $timestamp, true );
 +              $user = $this->getContext()->getUser();
 +
 +              $td = $language->userTimeAndDate( $timestamp, $user );
 +              $tddate = $language->userDate( $timestamp, $user );
 +              $tdtime = $language->userTime( $timestamp, $user );
  
                # Show user links if allowed to see them. If hidden, then show them only if requested...
                $userlinks = Linker::revUserTools( $revision, !$unhide );
                                array( 'known', 'noclasses' )
                        );
  
 -              $cdel = Linker::getRevDeleteLink( $this->getContext()->getUser(), $revision, $this->getTitle() );
 +              $cdel = Linker::getRevDeleteLink( $user, $revision, $this->getTitle() );
                if ( $cdel !== '' ) {
                        $cdel .= ' ';
                }
  
                        $this->doDelete( $reason, $suppress );
  
 -                      if ( $request->getCheck( 'wpWatch' ) && $user->isLoggedIn() ) {
 -                              $this->doWatch();
 -                      } elseif ( $title->userIsWatching() ) {
 -                              $this->doUnwatch();
 +                      if ( $user->isLoggedIn() && $request->getCheck( 'wpWatch' ) != $user->isWatched( $title ) ) {
 +                              if ( $request->getCheck( 'wpWatch' ) ) {
 +                                      WatchAction::doWatch( $title, $user );
 +                              } else {
 +                                      WatchAction::doUnwatch( $title, $user );
 +                              }
                        }
  
                        return;
                        }
                }
  
 -              return $this->confirmDelete( $reason );
 +              $this->confirmDelete( $reason );
        }
  
        /**
                } else {
                        $suppress = '';
                }
 -              $checkWatch = $user->getBoolOption( 'watchdeletion' ) || $this->getTitle()->userIsWatching();
 +              $checkWatch = $user->getBoolOption( 'watchdeletion' ) || $user->isWatched( $this->getTitle() );
  
                $form = Xml::openElement( 'form', array( 'method' => 'post',
                        'action' => $this->getTitle()->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ) ) .
        public function doDelete( $reason, $suppress = false ) {
                $error = '';
                $outputPage = $this->getContext()->getOutput();
-               if ( $this->mPage->doDeleteArticle( $reason, $suppress, 0, true, $error ) ) {
+               $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error );
+               if ( $status->isGood() ) {
                        $deleted = $this->getTitle()->getPrefixedText();
  
                        $outputPage->setPageTitle( wfMessage( 'actioncomplete' ) );
                } else {
                        $outputPage->setPageTitle( wfMessage( 'cannotdelete-title', $this->getTitle()->getPrefixedText() ) );
                        if ( $error == '' ) {
+                               $errors = $status->getErrorsArray();
                                $outputPage->wrapWikiMsg( "<div class=\"error mw-error-cannotdelete\">\n$1\n</div>",
-                                       array( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) )
+                                       $errors[0]
                                );
                                $outputPage->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) );
  
        /**
         * Handle action=purge
         * @deprecated since 1.19
 +       * @return Action|bool|null false if the action is disabled, null if it is not recognised
         */
        public function purge() {
                return Action::factory( 'purge', $this )->show();
@@@ -1,31 -1,10 +1,31 @@@
  <?php
 +/**
 + * File deletion user interface.
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + * http://www.gnu.org/copyleft/gpl.html
 + *
 + * @file
 + * @author Rob Church <robchur@gmail.com>
 + * @ingroup Media
 + */
  
  /**
   * File deletion user interface
   *
   * @ingroup Media
 - * @author Rob Church <robchur@gmail.com>
   */
  class FileDeleteForm {
  
                                // file, otherwise go back to the description page
                                $wgOut->addReturnTo( $this->oldimage ? $this->title : Title::newMainPage() );
  
 -                              if ( $wgRequest->getCheck( 'wpWatch' ) && $wgUser->isLoggedIn() ) {
 -                                      WatchAction::doWatch( $this->title, $wgUser );
 -                              } elseif ( $this->title->userIsWatching() ) {
 -                                      WatchAction::doUnwatch( $this->title, $wgUser );
 +                              if ( $wgUser->isLoggedIn() && $wgRequest->getCheck( 'wpWatch' ) != $wgUser->isWatched( $this->title ) ) {
 +                                      if ( $wgRequest->getCheck( 'wpWatch' ) ) {
 +                                              WatchAction::doWatch( $this->title, $wgUser );
 +                                      } else {
 +                                              WatchAction::doUnwatch( $this->title, $wgUser );
 +                                      }
                                }
                        }
                        return;
                        try {
                                // delete the associated article first
                                $error = '';
-                               if ( $page->doDeleteArticleReal( $reason, $suppress, 0, false, $error, $user ) >= WikiPage::DELETE_SUCCESS ) {
+                               $deleteStatus = $page->doDeleteArticleReal( $reason, $suppress, 0, false, $error, $user );
+                               // doDeleteArticleReal() returns a non-fatal error status if the page
+                               // or revision is missing, so check for isOK() rather than isGood()
+                               if ( $deleteStatus->isOK() ) {
                                        $status = $file->delete( $reason, $suppress );
                                        if( $status->isOK() ) {
                                                $dbw->commit( __METHOD__ );
                        $suppress = '';
                }
  
 -              $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $this->title->userIsWatching();
 +              $checkWatch = $wgUser->getBoolOption( 'watchdeletion' ) || $wgUser->isWatched( $this->title );
                $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction(),
                        'id' => 'mw-img-deleteconfirm' ) ) .
                        Xml::openElement( 'fieldset' ) .
diff --combined includes/Title.php
@@@ -209,15 -209,7 +209,15 @@@ class Title 
         */
        public static function newFromID( $id, $flags = 0 ) {
                $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
 -              $row = $db->selectRow( 'page', '*', array( 'page_id' => $id ), __METHOD__ );
 +              $row = $db->selectRow(
 +                      'page',
 +                      array(
 +                              'page_namespace', 'page_title', 'page_id',
 +                              'page_len', 'page_is_redirect', 'page_latest',
 +                      ),
 +                      array( 'page_id' => $id ),
 +                      __METHOD__
 +              );
                if ( $row !== false ) {
                        $title = Title::newFromRow( $row );
                } else {
         */
        public function isConversionTable() {
                return $this->getNamespace() == NS_MEDIAWIKI &&
 -                      strpos( $this->getText(), 'Conversiontable' ) !== false;
 +                      strpos( $this->getText(), 'Conversiontable/' ) === 0;
        }
  
        /**
        /**
         * Is $wgUser watching this page?
         *
 +       * @deprecated in 1.20; use User::isWatched() instead.
         * @return Bool
         */
        public function userIsWatching() {
                                        $this->mRestrictions['edit'] = explode( ',', trim( $temp[0] ) );
                                        $this->mRestrictions['move'] = explode( ',', trim( $temp[0] ) );
                                } else {
 -                                      $this->mRestrictions[$temp[0]] = explode( ',', trim( $temp[1] ) );
 +                                      $restriction = trim( $temp[1] );
 +                                      if( $restriction != '' ) { //some old entries are empty
 +                                              $this->mRestrictions[$temp[0]] = explode( ',', $restriction );
 +                                      }
                                }
                        }
  
         *
         * - This is called from WikiPage::doEdit() and WikiPage::insertOn() to allow
         * loading of the new page_id. It's also called from
-        * WikiPage::doDeleteArticle()
+        * WikiPage::doDeleteArticleReal()
         *
         * @param $newid Int the new Article ID
         */
         * @return Array of String the URLs
         */
        public function getSquidURLs() {
 -              global $wgContLang;
 -
                $urls = array(
                        $this->getInternalURL(),
                        $this->getInternalURL( 'action=history' )
                );
  
 -              // purge variant urls as well
 -              if ( $wgContLang->hasVariants() ) {
 -                      $variants = $wgContLang->getVariants();
 +              $pageLang = $this->getPageLanguage();
 +              if ( $pageLang->hasVariants() ) {
 +                      $variants = $pageLang->getVariants();
                        foreach ( $variants as $vCode ) {
                                $urls[] = $this->getInternalURL( '', $vCode );
                        }
                $protected = $this->isProtected();
  
                // Do the actual move
 -              $err = $this->moveToInternal( $nt, $reason, $createRedirect );
 -              if ( is_array( $err ) ) {
 -                      # @todo FIXME: What about the File we have already moved?
 -                      $dbw->rollback( __METHOD__ );
 -                      return $err;
 -              }
 +              $this->moveToInternal( $nt, $reason, $createRedirect );
  
                // Refresh the sortkey for this row.  Be careful to avoid resetting
                // cl_timestamp, which may disturb time-based lists on some sites.
         * @param $reason String The reason for the move
         * @param $createRedirect Bool Whether to leave a redirect at the old title.  Ignored
         *   if the user doesn't have the suppressredirect right
 +       * @throws MWException
         */
        private function moveToInternal( &$nt, $reason = '', $createRedirect = true ) {
                global $wgUser, $wgContLang;
                $pageId = $this->getArticleID( $flags );
                if ( $pageId ) {
                        $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
 -                      $row = $db->selectRow( 'revision', '*',
 +                      $row = $db->selectRow( 'revision', Revision::selectFields(),
                                array( 'rev_page' => $pageId ),
                                __METHOD__,
                                array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 )
diff --combined includes/WikiPage.php
@@@ -34,30 -34,6 +34,6 @@@ abstract class Page {
   * @internal documentation reviewed 15 Mar 2010
   */
  class WikiPage extends Page {
-       // doDeleteArticleReal() return values. Values less than zero indicate fatal errors,
-       // values greater than zero indicate that there were problems not resulting in page
-       // not being deleted
-       /**
-        * Delete operation aborted by hook
-        */
-       const DELETE_HOOK_ABORTED = -1;
-       /**
-        * Deletion successful
-        */
-       const DELETE_SUCCESS = 0;
-       /**
-        * Page not found
-        */
-       const DELETE_NO_PAGE = 1;
-       /**
-        * No revisions found to delete
-        */
-       const DELETE_NO_REVISIONS = 2;
        // Constants for $mDataLoadedFrom and related
  
        /**
  
        /**
         * Clear the object
 +       * @return void
         */
        public function clear() {
                $this->mDataLoaded = false;
                $this->mDataLoadedFrom = self::DATA_NOT_LOADED;
  
 +              $this->clearCacheFields();
 +      }
 +
 +      /**
 +       * Clear the object cache fields
 +       * @return void
 +       */
 +      protected function clearCacheFields() {
                $this->mCounter = null;
                $this->mRedirectTarget = null; # Title object if set
                $this->mLastRevision = null; # Latest revision
                        $this->mTouched     = wfTimestamp( TS_MW, $data->page_touched );
                        $this->mIsRedirect  = intval( $data->page_is_redirect );
                        $this->mLatest      = intval( $data->page_latest );
 +                      // Bug 37225: $latest may no longer match the cached latest Revision object.
 +                      // Double-check the ID of any cached latest Revision object for consistency.
 +                      if ( $this->mLastRevision && $this->mLastRevision->getId() != $this->mLatest ) {
 +                              $this->mLastRevision = null;
 +                              $this->mTimestamp = '';
 +                      }
                } else {
                        $lc->addBadLinkObj( $this->mTitle );
  
                        $this->mTitle->loadFromRow( false );
 +
 +                      $this->clearCacheFields();
                }
  
                $this->mDataLoaded = true;
                }
  
                wfProfileOut( __METHOD__ );
 -              if ( $row ) {
 -                      return Revision::newFromRow( $row );
 -              } else {
 -                      return null;
 -              }
 +              return $row ? Revision::newFromRow( $row ) : null;
        }
  
        /**
                if ( !$this->mTimestamp ) {
                        $this->loadLastEdit();
                }
 -              
 +
                return wfTimestamp( TS_MW, $this->mTimestamp );
        }
  
         *  Compatibility note: this function previously returned a boolean value indicating success/failure
         */
        public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) {
 -              global $wgUser, $wgDBtransactions, $wgUseAutomaticEditSummaries;
 +              global $wgUser, $wgUseAutomaticEditSummaries;
  
                # Low-level sanity check
                if ( $this->mTitle->getText() === '' ) {
                                return $status;
                        }
  
 -                      # Make sure the revision is either completely inserted or not inserted at all
 -                      if ( !$wgDBtransactions ) {
 -                              $userAbort = ignore_user_abort( true );
 -                      }
 -
                        $revision = new Revision( array(
                                'page'       => $this->getId(),
                                'comment'    => $summary,
                                'user_text'  => $user->getName(),
                                'timestamp'  => $now
                        ) );
 +                      # Bug 37225: use accessor to get the text as Revision may trim it.
 +                      # After trimming, the text may be a duplicate of the current text.
 +                      $text = $revision->getText(); // sanity; EditPage should trim already
  
                        $changed = ( strcmp( $text, $oldtext ) != 0 );
  
                                        /* Belated edit conflict! Run away!! */
                                        $status->fatal( 'edit-conflict' );
  
 -                                      # Delete the invalid revision if the DB is not transactional
 -                                      if ( !$wgDBtransactions ) {
 -                                              $dbw->delete( 'revision', array( 'rev_id' => $revisionId ), __METHOD__ );
 -                                      }
 -
                                        $revisionId = 0;
                                        $dbw->rollback( __METHOD__ );
                                } else {
                                $revision->setId( $this->getLatest() );
                        }
  
 -                      if ( !$wgDBtransactions ) {
 -                              ignore_user_abort( $userAbort );
 -                      }
 -
                        // Now that ignore_user_abort is restored, we can respond to fatal errors
                        if ( !$status->isOK() ) {
                                wfProfileOut( __METHOD__ );
                        ) );
                        $revisionId = $revision->insertOn( $dbw );
  
 +                      # Bug 37225: use accessor to get the text as Revision may trim it
 +                      $text = $revision->getText(); // sanity; EditPage should trim already
 +
                        # Update the page record with revision data
                        $this->updateRevisionOn( $dbw, $revision, 0 );
  
                        $parserCache->save( $editInfo->output, $this, $editInfo->popts );
                }
  
 -              # Update the links tables
 -              $u = new LinksUpdate( $this->mTitle, $editInfo->output );
 -              $u->doUpdate();
 +              # Update the links tables and other secondary data
 +              $updates = $editInfo->output->getSecondaryDataUpdates( $this->mTitle );
 +              DataUpdate::runUpdates( $updates );
  
                wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
  
        }
  
        /**
-        * Same as doDeleteArticleReal(), but returns more detailed success/failure status
+        * Same as doDeleteArticleReal(), but returns a simple boolean. This is kept around for
+        * backwards compatibility, if you care about error reporting you should use
+        * doDeleteArticleReal() instead.
+        *
         * Deletes the article with database consistency, writes logs, purges caches
         *
         * @param $reason string delete reason for deletion log
        public function doDeleteArticle(
                $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
        ) {
-               return $this->doDeleteArticleReal( $reason, $suppress, $id, $commit, $error, $user )
-                       == WikiPage::DELETE_SUCCESS;
+               $status = $this->doDeleteArticleReal( $reason, $suppress, $id, $commit, $error, $user );
+               return $status->isGood();
        }
  
        /**
         * @param $commit boolean defaults to true, triggers transaction end
         * @param &$error Array of errors to append to
         * @param $user User The deleting user
-        * @return int: One of WikiPage::DELETE_* constants
+        * @return Status: Status object; if successful, $status->value is the log_id of the
+        *                 deletion log entry. If the page couldn't be deleted because it wasn't
+        *                 found, $status is a non-fatal 'cannotdelete' error
         */
        public function doDeleteArticleReal(
                $reason, $suppress = false, $id = 0, $commit = true, &$error = '', User $user = null
  
                wfDebug( __METHOD__ . "\n" );
  
+               $status = Status::newGood();
                if ( $this->mTitle->getDBkey() === '' ) {
-                       return WikiPage::DELETE_NO_PAGE;
+                       $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
+                       return $status;
                }
  
                $user = is_null( $user ) ? $wgUser : $user;
-               if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error ) ) ) {
-                       return WikiPage::DELETE_HOOK_ABORTED;
+               if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
+                       if ( $status->isOK() ) {
+                               // Hook aborted but didn't set a fatal status
+                               $status->fatal( 'delete-hook-aborted' );
+                       }
+                       return $status;
                }
  
                if ( $id == 0 ) {
                        $this->loadPageData( 'forupdate' );
                        $id = $this->getID();
                        if ( $id == 0 ) {
-                               return WikiPage::DELETE_NO_PAGE;
+                               $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
+                               return $status;
                        }
                }
  
  
                if ( !$ok ) {
                        $dbw->rollback( __METHOD__ );
-                       return WikiPage::DELETE_NO_REVISIONS;
+                       $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
+                       return $status;
                }
  
                $this->doDeleteUpdates( $id );
                }
  
                wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id ) );
-               return WikiPage::DELETE_SUCCESS;
+               $status->value = $logid;
+               return $status;
        }
  
        /**
         * Do some database updates after deletion
         *
 -       * @param $id Int: page_id value of the page being deleted
 +       * @param $id Int: page_id value of the page being deleted (B/C, currently unused)
         */
        public function doDeleteUpdates( $id ) {
 +              # update site status
                DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, - (int)$this->isCountable(), -1 ) );
  
 -              $dbw = wfGetDB( DB_MASTER );
 -
 -              # Delete restrictions for it
 -              $dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
 -
 -              # Fix category table counts
 -              $cats = array();
 -              $res = $dbw->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
 -
 -              foreach ( $res as $row ) {
 -                      $cats [] = $row->cl_to;
 -              }
 -
 -              $this->updateCategoryCounts( array(), $cats );
 -
 -              # If using cascading deletes, we can skip some explicit deletes
 -              if ( !$dbw->cascadingDeletes() ) {
 -                      $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
 -
 -                      # Delete outgoing links
 -                      $dbw->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
 -                      $dbw->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
 -              }
 -
 -              # If using cleanup triggers, we can skip some manual deletes
 -              if ( !$dbw->cleanupTriggers() ) {
 -                      # Clean up recentchanges entries...
 -                      $dbw->delete( 'recentchanges',
 -                              array( 'rc_type != ' . RC_LOG,
 -                                      'rc_namespace' => $this->mTitle->getNamespace(),
 -                                      'rc_title' => $this->mTitle->getDBkey() ),
 -                              __METHOD__ );
 -                      $dbw->delete( 'recentchanges',
 -                              array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
 -                              __METHOD__ );
 -              }
 +              # remove secondary indexes, etc
 +              $updates = $this->getDeletionUpdates( );
 +              DataUpdate::runUpdates( $updates );
  
                # Clear caches
 -              self::onArticleDelete( $this->mTitle );
 +              WikiPage::onArticleDelete( $this->mTitle );
  
                # Reset this object
                $this->clear();
                $this->mTitle->resetArticleID( 0 );
        }
  
 +      public function getDeletionUpdates() {
 +              $updates = array(
 +                      new LinksDeletionUpdate( $this ),
 +              );
 +
 +              //@todo: make a hook to add update objects
 +              //NOTE: deletion updates will be determined by the ContentHandler in the future
 +              return $updates;
 +      }
 +
        /**
         * Roll back the most recent consecutive set of edits to a page
         * from the same user; fails if there are no eligible edits to
         * roll back to, e.g. user is the sole contributor. This function
         * performs permissions checks on $user, then calls commitRollback()
         * to do the dirty work
 -       * 
 +       *
         * @todo: seperate the business/permission stuff out from backend code
         *
         * @param $fromP String: Name of the user whose edits to rollback.
  
                if ( count( $templates_diff ) > 0 ) {
                        # Whee, link updates time.
 +                      # Note: we are only interested in links here. We don't need to get other DataUpdate items from the parser output.
                        $u = new LinksUpdate( $this->mTitle, $parserOutput, false );
                        $u->doUpdate();
                }
        public function quickEdit( $text, $comment = '', $minor = 0 ) {
                wfDeprecated( __METHOD__, '1.18' );
                global $wgUser;
 -              return $this->doQuickEdit( $text, $wgUser, $comment, $minor );
 +              $this->doQuickEdit( $text, $wgUser, $comment, $minor );
        }
  
        /**
@@@ -56,13 -56,14 +56,14 @@@ class ApiDelete extends ApiBase 
                $user = $this->getUser();
  
                if ( $titleObj->getNamespace() == NS_FILE ) {
-                       $retval = self::deleteFile( $pageObj, $user, $params['token'], $params['oldimage'], $reason, false );
+                       $status = self::deleteFile( $pageObj, $user, $params['token'], $params['oldimage'], $reason, false );
                } else {
-                       $retval = self::delete( $pageObj, $user, $params['token'], $reason );
+                       $status = self::delete( $pageObj, $user, $params['token'], $reason );
                }
  
-               if ( count( $retval ) ) {
-                       $this->dieUsageMsg( reset( $retval ) ); // We don't care about multiple errors, just report one of them
+               if ( !$status->isGood() ) {
+                       $errors = $this->getErrorsArray();
+                       $this->dieUsageMsg( $errors[0] ); // We don't care about multiple errors, just report one of them
                }
  
                // Deprecated parameters
                }
                $this->setWatch( $watch, $titleObj, 'watchdeletion' );
  
-               $r = array( 'title' => $titleObj->getPrefixedText(), 'reason' => $reason );
+               $r = array(
+                       'title' => $titleObj->getPrefixedText(),
+                       'reason' => $reason,
+                       'logid' => $status->value
+               );
                $this->getResult()->addValue( null, $this->getModuleName(), $r );
        }
  
         * @param $user User doing the action
         * @param $token String: delete token (same as edit token)
         * @param $reason String: reason for the deletion. Autogenerated if NULL
-        * @return Title::getUserPermissionsErrors()-like array
+        * @return Status
         */
        public static function delete( Page $page, User $user, $token, &$reason = null ) {
                $title = $page->getTitle();
  
                $error = '';
                // Luckily, Article.php provides a reusable delete function that does the hard work for us
-               if ( $page->doDeleteArticle( $reason, false, 0, true, $error ) ) {
-                       return array();
-               } else {
-                       return array( array( 'cannotdelete', $title->getPrefixedText() ) );
-               }
+               return $page->doDeleteArticleReal( $reason, false, 0, true, $error );
        }
  
        /**
         * @param $oldimage
         * @param $reason
         * @param $suppress bool
-        * @return array|Title
+        * @return Status
         */
        public static function deleteFile( Page $page, User $user, $token, $oldimage, &$reason = null, $suppress = false ) {
                $title = $page->getTitle();
                if ( is_null( $reason ) ) { // Log and RC don't like null reasons
                        $reason = '';
                }
-               $status = FileDeleteForm::doDelete( $title, $file, $oldimage, $reason, $suppress );
-               if ( !$status->isGood() ) {
-                       return array( array( 'cannotdelete', $title->getPrefixedText() ) );
-               }
-               return array();
+               return FileDeleteForm::doDelete( $title, $file, $oldimage, $reason, $suppress );
        }
  
        public function mustBePosted() {
                );
        }
  
 +      public function getResultProperties() {
 +              return array(
 +                      '' => array(
 +                              'title' => 'string',
 +                              'reason' => 'string'
 +                      )
 +              );
 +      }
 +
        public function getDescription() {
                return 'Delete a page';
        }
@@@ -246,14 -246,6 +246,14 @@@ class MovePageForm extends UnlistedSpec
                // Byte limit (not string length limit) for wpReason and wpNewTitleMain
                // is enforced in the mediawiki.special.movePage module
  
 +              $immovableNamespaces = array();
 +
 +              foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $nsId ) {
 +                      if ( !MWNamespace::isMovable( $nsId ) ) {
 +                              $immovableNamespaces[] = $nsId;
 +                      }
 +              }
 +
                $out->addHTML(
                         Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalURL( 'action=submit' ), 'id' => 'movepage' ) ) .
                         Xml::openElement( 'fieldset' ) .
                                "</td>
                                <td class='mw-input'>" .
                                        Html::namespaceSelector(
 -                                              array( 'selected' => $newTitle->getNamespace() ),
 +                                              array(
 +                                                      'selected' => $newTitle->getNamespace(),
 +                                                      'exclude' => $immovableNamespaces
 +                                              ),
                                                array( 'name' => 'wpNewTitleNs', 'id' => 'wpNewTitleNs' )
                                        ) .
                                        Xml::input( 'wpNewTitleMain', 60, $wgContLang->recodeForEdit( $newTitle->getText() ), array(
                }
  
                $watchChecked = $user->isLoggedIn() && ($this->watch || $user->getBoolOption( 'watchmoves' )
 -                      || $this->oldTitle->userIsWatching());
 +                      || $user->isWatched( $this->oldTitle ) );
                # Don't allow watching if user is not logged in
                if( $user->isLoggedIn() ) {
                        $out->addHTML( "
  
                        $error = ''; // passed by ref
                        $page = WikiPage::factory( $nt );
-                       if ( !$page->doDeleteArticle( $reason, false, 0, true, $error, $user ) ) {
-                               $this->showForm( array( array( 'cannotdelete', wfEscapeWikiText( $nt->getPrefixedText() ) ) ) );
+                       $deleteStatus = $page->doDeleteArticleReal( $reason, false, 0, true, $error, $user );
+                       if ( !$deleteStatus->isGood() ) {
+                               $this->showForm( $deleteStatus->getErrorsArray() );
                                return;
                        }
                }
@@@ -191,7 -191,6 +191,7 @@@ $bookstoreList = array
   * Customisable syntax for wikitext and elsewhere.
   *
   * IDs must be valid identifiers, they cannot contain hyphens.
 + * CASE is 0 to match all case variants, 1 for case-sensitive
   *
   * Note to translators:
   *   Please include the English words as synonyms.  This allows people
@@@ -288,8 -287,7 +288,8 @@@ $magicWords = array
        'nse'                    => array( 0,    'NSE:'                   ),
        'localurl'               => array( 0,    'LOCALURL:'              ),
        'localurle'              => array( 0,    'LOCALURLE:'             ),
 -      'articlepath'            => array( 0,    'ARTICLEPATH'            ),
 +      'articlepath'            => array( 0,    'ARTICLEPATH'            ),
 +      'pageid'                 => array( 0,    'PAGEID'                 ),
        'server'                 => array( 0,    'SERVER'                 ),
        'servername'             => array( 0,    'SERVERNAME'             ),
        'scriptpath'             => array( 0,    'SCRIPTPATH'             ),
@@@ -637,7 -635,7 +637,7 @@@ XHTML id names
  'tog-hidepatrolled'           => 'Hide patrolled edits in recent changes',
  'tog-newpageshidepatrolled'   => 'Hide patrolled pages from new page list',
  'tog-extendwatchlist'         => 'Expand watchlist to show all changes, not just the most recent',
 -'tog-usenewrc'                => 'Use enhanced recent changes (requires JavaScript)',
 +'tog-usenewrc'                => 'Group changes by page in recent changes and watchlist (requires JavaScript)',
  'tog-numberheadings'          => 'Auto-number headings',
  'tog-showtoolbar'             => 'Show edit toolbar (requires JavaScript)',
  'tog-editondblclick'          => 'Edit pages on double click (requires JavaScript)',
  'index-category'                 => 'Indexed pages',
  'noindex-category'               => 'Noindexed pages',
  'broken-file-category'           => 'Pages with broken file links',
 +'categoryviewer-pagedlinks'      => '($1) ($2)',
  
  'linkprefix' => '/^(.*?)([a-zA-Z\\x80-\\xff]+)$/sD', # only translate this message to other languages if you have to change it
  
@@@ -1008,6 -1005,8 +1008,8 @@@ Please report this to an [[Special:List
  'cannotdelete'         => 'The page or file "$1" could not be deleted.
  It may have already been deleted by someone else.',
  'cannotdelete-title'   => 'Cannot delete page "$1"',
+ 'delete-hook-aborted'  => 'Deletion aborted by hook.
+ It gave no explanation.',
  'badtitle'             => 'Bad title',
  'badtitletext'         => 'The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title.
  It may contain one or more characters which cannot be used in titles.',
@@@ -1087,8 -1086,6 +1089,8 @@@ Do not forget to change your [[Special:
  Please choose a different name.',
  'loginerror'                 => 'Login error',
  'createaccounterror'         => 'Could not create account: $1',
 +'exception-nologin'          => 'Not logged in',
 +'exception-nologin-text'     => 'This page or action requires you to be logged in on this wiki.',
  'nocookiesnew'               => 'The user account was created, but you are not logged in.
  {{SITENAME}} uses cookies to log in users.
  You have cookies disabled.
@@@ -1666,7 -1663,6 +1668,7 @@@ Note that using the navigation links wi
  'mergehistory-comment'             => 'Merged [[:$1]] into [[:$2]]: $3',
  'mergehistory-same-destination'    => 'Source and destination pages cannot be the same',
  'mergehistory-reason'              => 'Reason:',
 +'mergehistory-revisionrow'         => '$1 ($2) $3 . . $4 $5 $6',
  
  # Merge log
  'mergelog'           => 'Merge log',
@@@ -1797,7 -1793,6 +1799,7 @@@ Note that their indexes of {{SITENAME}
  'prefs-beta'                    => 'Beta features',
  'prefs-datetime'                => 'Date and time',
  'prefs-labs'                    => 'Labs features',
 +'prefs-user-pages'              => 'User pages',
  'prefs-personal'                => 'User profile',
  'prefs-rc'                      => 'Recent changes',
  'prefs-watchlist'               => 'Watchlist',
@@@ -2068,8 -2063,7 +2070,8 @@@ Your e-mail address is not revealed whe
  'recentchanges'                     => 'Recent changes',
  'recentchanges-url'                 => 'Special:RecentChanges', # do not translate or duplicate this message to other languages
  'recentchanges-legend'              => 'Recent changes options',
 -'recentchangestext'                 => 'Track the most recent changes to the wiki on this page.',
 +'recentchanges-summary'             => 'Track the most recent changes to the wiki on this page.',
 +'recentchangestext'                 => '-', # do not translate or duplicate this message to other languages
  'recentchanges-feed-description'    => 'Track the most recent changes to the wiki in this feed.',
  'recentchanges-label-newpage'       => 'This edit created a new page',
  'recentchanges-label-minor'         => 'This is a minor edit',
@@@ -2291,9 -2285,8 +2293,9 @@@ If the problem persists, contact an [[S
  'backend-fail-writetemp'     => 'Could not write to temporary file.',
  'backend-fail-closetemp'     => 'Could not close temporary file.',
  'backend-fail-read'          => 'Could not read file $1.',
 -'backend-fail-create'        => 'Could not create file $1.',
 -'backend-fail-maxsize'       => 'Could not create file $1 because it is larger than {{PLURAL:$2|one byte|$2 bytes}}.',
 +'backend-fail-create'        => 'Could not write file $1.',
 +'backend-fail-maxsize'       => 'Could not write file $1 because it is larger than {{PLURAL:$2|one byte|$2 bytes}}.',
 +'backend-fail-usable'        => 'Could not write file $1 due to insufficient permissions or missing directories/containers.',
  'backend-fail-readonly'      => 'The storage backend "$1" is currently read-only. The reason given is: "\'\'$2\'\'"',
  'backend-fail-synced'        => 'The file "$1" is in an inconsistent state within the internal storage backends',
  'backend-fail-connect'       => 'Could not connect to storage backend "$1".',
  'lockmanager-fail-releaselock' => 'Could not release lock for "$1".',
  'lockmanager-fail-db-bucket'   => 'Could not contact enough lock databases in bucket $1.',
  'lockmanager-fail-db-release'  => 'Could not release locks on database $1.',
 +'lockmanager-fail-svr-acquire' => 'Could not acquire locks on server $1.',
  'lockmanager-fail-svr-release' => 'Could not release locks on server $1.',
  
  # ZipDirectoryReader
@@@ -2362,6 -2354,7 +2364,6 @@@ For optimal security, img_auth.php is d
  'http-curl-error'       => 'Error fetching URL: $1',
  'http-host-unreachable' => 'Could not reach URL.',
  'http-bad-status'       => 'There was a problem during the HTTP request: $1 $2',
 -'http-truncated-body'   => 'The request body was only partially received.',
  
  # Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>
  'upload-curl-error6'       => 'Could not reach URL',
@@@ -2662,15 -2655,14 +2664,15 @@@ Please note that other web sites may li
  'pubmedurl' => '//www.ncbi.nlm.nih.gov/pubmed/$1?dopt=Abstract', # do not translate or duplicate this message to other languages
  
  # Special:Log
 -'specialloguserlabel'  => 'Performer:',
 -'speciallogtitlelabel' => 'Target (title or user):',
 -'log'                  => 'Logs',
 -'all-logs-page'        => 'All public logs',
 -'alllogstext'          => 'Combined display of all available logs of {{SITENAME}}.
 +'specialloguserlabel'        => 'Performer:',
 +'speciallogtitlelabel'       => 'Target (title or user):',
 +'log'                        => 'Logs',
 +'all-logs-page'              => 'All public logs',
 +'alllogstext'                => 'Combined display of all available logs of {{SITENAME}}.
  You can narrow down the view by selecting a log type, the username (case-sensitive), or the affected page (also case-sensitive).',
 -'logempty'             => 'No matching items in log.',
 -'log-title-wildcard'   => 'Search titles starting with this text',
 +'logempty'                   => 'No matching items in log.',
 +'log-title-wildcard'         => 'Search titles starting with this text',
 +'showhideselectedlogentries' => 'Show/hide selected log entries',
  
  # Special:AllPages
  'allpages'                => 'All pages',
@@@ -3060,7 -3052,6 +3062,7 @@@ It may have already been undeleted.'
  $1',
  'undelete-show-file-confirm'   => 'Are you sure you want to view the deleted revision of the file "<nowiki>$1</nowiki>" from $2 at $3?',
  'undelete-show-file-submit'    => 'Yes',
 +'undelete-revisionrow'        => "$1 $2 $3 $4 . . $5 $6 $7",
  
  # Namespace form on various pages
  'namespace'                     => 'Namespace:',
@@@ -3198,8 -3189,8 +3200,8 @@@ See the [[Special:BlockList|block list]
  'expiringblock'                   => 'expires on $1 at $2',
  'anononlyblock'                   => 'anon. only',
  'noautoblockblock'                => 'autoblock disabled',
 -'createaccountblock'              => 'account creation blocked',
 -'emailblock'                      => 'e-mail blocked',
 +'createaccountblock'              => 'account creation disabled',
 +'emailblock'                      => 'e-mail disabled',
  'blocklist-nousertalk'            => 'cannot edit own talk page',
  'ipblocklist-empty'               => 'The block list is empty.',
  'ipblocklist-no-results'          => 'The requested IP address or username is not blocked.',
@@@ -3224,7 -3215,7 +3226,7 @@@ See the [[Special:BlockList|block list]
  'block-log-flags-anononly'        => 'anonymous users only',
  'block-log-flags-nocreate'        => 'account creation disabled',
  'block-log-flags-noautoblock'     => 'autoblock disabled',
 -'block-log-flags-noemail'         => 'e-mail blocked',
 +'block-log-flags-noemail'         => 'e-mail disabled',
  'block-log-flags-nousertalk'      => 'cannot edit own talk page',
  'block-log-flags-angry-autoblock' => 'enhanced autoblock enabled',
  'block-log-flags-hiddenname'      => 'username hidden',
@@@ -3696,7 -3687,6 +3698,7 @@@ This is probably caused by a link to a 
  'spambot_username'    => 'MediaWiki spam cleanup',
  'spam_reverting'      => 'Reverting to last revision not containing links to $1',
  'spam_blanking'       => 'All revisions contained links to $1, blanking',
 +'spam_deleting'       => 'All revisions contained links to $1, deleting',
  
  # Info page
  'pageinfo-title'            => 'Information for "$1"',
@@@ -4436,7 -4426,6 +4438,7 @@@ Please confirm that you really want to 
  'ellipsis'            => '...', # only translate this message to other languages if you have to change it
  'percent'             => '$1%', # only translate this message to other languages if you have to change it
  'parentheses'         => '($1)', # only translate this message to other languages if you have to change it
 +'brackets'            => '[$1]', # only translate this message to other languages if you have to change it
  
  # Multipage image navigation
  'imgmultipageprev' => '← previous page',
@@@ -8,7 -8,6 +8,7 @@@
   * @file
   *
   * @author *Surak*
 + * @author Abanima
   * @author Ahonc
   * @author Aleator
   * @author AlexSm
@@@ -74,7 -73,6 +74,7 @@@
   * @author Mihai
   * @author Mormegil
   * @author Mpradeep
 + * @author Murma174
   * @author Najami
   * @author Nemo bis
   * @author Niels
   * @author Sherbrooke
   * @author Shirayuki
   * @author Shushruth
 + * @author Siddhartha Ghai
   * @author Siebrand
   * @author Singularity
   * @author Sionnach
@@@ -139,7 -136,7 +139,7 @@@ $messages = array
  'tog-hidepatrolled' => 'Option in Recent changes tab of [[Special:Preferences]] (if [[mw:Manual:$wgUseRCPatrol|$wgUseRCPatrol]] is enabled). {{Gender}}',
  'tog-newpageshidepatrolled' => 'Toggle in [[Special:Preferences]], section "Recent changes" (if [[mw:Manual:$wgUseRCPatrol|$wgUseRCPatrol]] is enabled). {{Gender}}',
  'tog-extendwatchlist' => "[[Special:Preferences]], tab 'Watchlist'. Offers user to show all applicable changes in watchlist (by default only the last change to a page on the watchlist is shown). {{Gender}}",
 -'tog-usenewrc' => "[[Special:Preferences]], tab 'Recent changes'. Offers user to use alternative reprsentation of [[Special:RecentChanges]]. {{Gender}}",
 +'tog-usenewrc' => "[[Special:Preferences]], tab 'Recent changes'. Offers user to use alternative representation of [[Special:RecentChanges]] and watchlist. {{Gender}}",
  'tog-numberheadings' => "[[Special:Preferences]], tab 'Misc'. Offers numbered headings on content pages to user. {{Gender}}",
  'tog-showtoolbar' => "[[Special:Preferences]], tab 'Edit'. Offers user to show edit toolbar in page edit screen. {{Gender}}
  
@@@ -311,9 -308,6 +311,9 @@@ See http://test.wikipedia.org/wiki/Cate
  'index-category' => 'Name of the [[mw:Help:Tracking categories|tracking category]] where pages with the <nowiki>__INDEX__</nowiki> behaviour switch are listed. For description of this behaviour switch see [//www.mediawiki.org/wiki/Help:Magic_words#Behavior_switches mediawiki].',
  'noindex-category' => 'Name of the [[mw:Help:Tracking categories|tracking category]] where pages with the <nowiki>__NOINDEX__</nowiki> behaviour switch are listed. For description of this behaviour switch see [//www.mediawiki.org/wiki/Help:Magic_words#Behavior_switches mediawiki].',
  'broken-file-category' => 'Name of [[mw:Help:Tracking categories|tracking category]] where pages that embed files that do not exist ("broken images") are listed.',
 +'categoryviewer-pagedlinks' => 'The pagination links in category viewer. Parameters:
 +* $1 is the previous link,
 +* $2 is the next link',
  
  'linkprefix' => '{{optional}}',
  
  Possible alternatives to the word 'content' are 'subject matter' or 'wiki subject' or 'wiki purpose'.
  
  {{Identical|Content page}}",
 -'newwindow' => 'Below the edit form, next to "[[MediaWiki:Edithelp/{{SUBPAGENAME}}|Editing help]]".',
 +'newwindow' => 'Below the edit form, next to "{{msg-mw|Edithelp}}".',
  'cancel' => 'Message shown below the edit form, and if you click on it, you stop with editing the page and go back to the normal page view.
  
  {{Identical|Cancel}}',
@@@ -415,7 -409,7 +415,7 @@@ Also used as title of [[Special:Search]
  'edit' => 'The text of the tab going to the edit form. When the page is protected, you will see "[[MediaWiki:Viewsource/{{SUBPAGENAME}}|{{int:viewsource}}]]". Should be in the infinitive mood.
  
  {{Identical|Edit}}',
 -'create' => 'The text on the tab for to the edit form on unexisting pages.
 +'create' => 'The text on the tab of the edit form on unexisting pages starts editing them.
  
  {{Identical|Create}}',
  'editthispage' => 'This is the "edit" link as used in the skins Classic/Standard, Cologne Blue and Nostalgia. See {{msg|create-this-page}} for when the page does not exist.',
@@@ -665,6 -659,7 +665,7 @@@ HTML markup cannot be used
  $1 is a filename, I think.',
  'cannotdelete-title' => 'Title of error page when the user cannot delete a page
  * $1 is the page name',
+ 'delete-hook-aborted' => 'Error message shown when an extension hook prevents a page deletion, but does not provide an error message.',
  'badtitle' => 'The page title when a user requested a page with invalid page name. The content will be {{msg-mw|badtitletext}}.',
  'badtitletext' => 'The message shown when a user requested a page with invalid page name. The page title will be {{msg-mw|badtitle}}.',
  'perfcached' => 'Like {{msg-mw|perfcachedts}} but used when we do not know how long ago page was cached (unlikely to happen). Parameters:
  'invalidtitle-unknownnamespace' => 'Displayed when an invalid title was encountered (generally in a list) and the namespace number is unknown.
  * $1 is the namespace number
  * $2 is the part of the title after the namespace (e.g. SomeName for the page User:SomeName)',
 +'exception-nologin' => 'Generic page title used on error page when a user is not logged in. Message used by the UserNotLoggedIn exception.',
 +'exception-nologin-text' => 'Generic reason displayed on error page when a user is not logged in. Message used by the UserNotLoggedIn exception.',
  
  # Login and logout pages
  'logouttext' => 'Log out message',
  'nologin' => 'A message shown in the log in form. $1 is a link to the account creation form, and the text of it is "[[MediaWiki:Nologinlink/{{SUBPAGENAME}}|{{int:nologinlink}}]]".',
  'nologinlink' => 'Text of the link to the account creation form. Before that link, the message [[MediaWiki:Nologin/{{SUBPAGENAME}}]] appears.
  {{Identical|Create an account}}',
 -'createaccount' => 'The title of Special:CreateAccount, where users can register a new account. Used on Special:SpecialPages, and also on the submit button in the form where you register a new account.
 +'createaccount' => 'The title of Special:CreateAccount, where users can register a new account. Used on Special:SpecialPages and on the submit button in the form where you register a new account.
 +
 +It is also used on the top of the page for logged out users, where it appears next to {{msg-mw|login}}, so consider making them similar.
  {{Identical|Create account}}',
  'gotaccount' => 'A message shown in the account creation form. $1 is a link to the log in form, and the text of it is "[[MediaWiki:Gotaccountlink/{{SUBPAGENAME}}|{{int:gotaccountlink}}]]".',
  'gotaccountlink' => 'Text of the link to the log in form. Before that link, the message [[MediaWiki:Gotaccount/{{SUBPAGENAME}}]] appears.
@@@ -803,7 -794,7 +804,7 @@@ Parameters
  *Parameter $4 is a URL to the wiki',
  'login-throttled' => 'Error message shown at [[Special:UserLogin]] after 5 wrong passwords. The hardcoded waiting time is 300 seconds.',
  'login-abort-generic' => 'The generic unsuccessful login message is used unless otherwise specified by hook writers',
 -'loginlanguagelabel' => 'Used on [[Special:UserLogin]] if $wgLoginLanguageSelector is true.
 +'loginlanguagelabel' => 'Used on [[Special:UserLogin]] if $wgLoginLanguageSelector is true. $1 is a pipe-separated list built from the names that appear in the message {{msg-mw|Loginlanguagelinks}}.
  {{Identical|Language}}',
  
  # E-mail sending
@@@ -1125,7 -1116,6 +1126,7 @@@ Used in History and [[Special:Contribut
  'rev-deleted-user-contribs' => 'Part of revision deletion.',
  'rev-deleted-text-unhide' => 'This message is very similar to {{msg-mw|rev-suppressed-unhide-diff}}. Parameters:
  * $1 is a HTML link to the diff',
 +'rev-deleted-text-view' => 'I believe this is an error message which appears if a user tries to view a past revision of a page, where the revision has been hidden from view, although later revisions of the page still exist.',
  'rev-suppressed-unhide-diff' => 'This message is very similar to {{msg-mw|rev-deleted-unhide-diff}} and to {{msg-mw|rev-suppressed-text-unhide}}. Parameters:
  * $1 is a HTML link to the diff',
  'rev-delundel' => 'Link in page history for oversight (see also {{msg-mw|rev-showdeleted}})',
@@@ -1250,13 -1240,6 +1251,13 @@@ Parameters
  *Parameter $3 is a log comment for the merge',
  'mergehistory-same-destination' => 'Error message shown on [[Special:MergeHistory]] when the user entered the same page title to both source and destination',
  'mergehistory-reason' => '{{Identical|Reason}}',
 +'mergehistory-revisionrow' => 'A revision row in the merge history page. Parameters:
 +* $1 is a radio button to indicate a merge point,
 +* $2 is a link to the last revision of a page ({{msg-mw|last}}),
 +* $3 is a page link,
 +* $4 is a user link,
 +* $5 is a revision size,
 +* $6 is a revision comment',
  
  # Merge log
  'mergelog' => 'This is the name of a log of merge actions done on [[Special:MergeHistory]]. This special page and this log is not enabled by default.',
@@@ -1279,7 -1262,7 +1280,7 @@@ Please note that the parameters in a lo
  See also {{msg-mw|difference}}.',
  'lineno' => 'Message used when comparing different versions of a page (diff). $1 is a line number.',
  'compareselectedversions' => 'Used as button in history pages.',
 -'showhideselectedversions' => 'Text of the button which brings up the [[mw:RevisionDelete|RevisionDelete]] menu.',
 +'showhideselectedversions' => 'Text of the button which brings up the [[mw:RevisionDelete|RevisionDelete]] menu on history pages.',
  'editundo' => 'Undo link when viewing diffs
  {{Identical|Undo}}
  
@@@ -1410,7 -1393,6 +1411,7 @@@ This is a search result (and I guess se
  'prefs-beta' => "Header of a subsection at [[Special:Preferences]], tab ''{{int:prefs-editing}}'', listing features that are in beta but mostly suitable for general use",
  'prefs-datetime' => '{{Identical|Date}}',
  'prefs-labs' => "Header of a subsection at [[Special:Preferences]], tab ''{{int:prefs-editing}}'', listing features that are experimental",
 +'prefs-user-pages' => "Header of a subsection at [[Special:Preferences]], tab ''{{int:prefs-misc}}'', listing features that are related to user pages",
  'prefs-personal' => 'Title of a tab in [[Special:Preferences]].',
  'prefs-rc' => 'Used in user preferences.
  
@@@ -1789,7 -1771,7 +1790,7 @@@ This action allows editing of all of th
  
  {{Identical|Recent changes}}',
  'recentchanges-legend' => 'Legend of the fieldset of [[Special:RecentChanges]]',
 -'recentchangestext' => 'Text in recent changes',
 +'recentchanges-summary' => 'Summary of [[Special:RecentChanges]].',
  'recentchanges-label-newpage' => 'Tooltip for {{msg-mw|newpageletter}}',
  'recentchanges-label-minor' => 'Tooltip for {{msg-mw|newpageletter}}',
  'recentchanges-label-bot' => 'Tooltip for {{msg-mw|boteditletter}}',
@@@ -1984,11 -1966,7 +1985,11 @@@ Extensions making use of it
  'backend-fail-batchsize' => 'Error message when the limit of operations to be done at once in the file backend was reached.
  Parameters:
  * $1 is the number of operations attempted at once in this case.
 -* $2 is the maximum number of operations that can be attempted at once.',
 +* $2 is the maximum number of operations that can be attempted at once.
 +
 +A "[[:wikipedia:Front and back ends|backend]]" is a system or component that ordinary users don\'t interact with directly and don\'t need to know about, and that is responsible for a distinct task or service - for example, a storage back-end is a generic system for storing data which other applications can use. Possible alternatives for back-end are "system" or "service", or (depending on context and language) even leave it untranslated.',
 +'backend-fail-usable' => 'Parameters:
 +* $1 is the file name, including the path, formatted for the storage backend used',
  
  # File journal errors
  'filejournal-fail-dbconnect' => 'Parameters:
@@@ -2055,6 -2033,7 +2056,6 @@@ Siebrand think this has to do with allo
  
  If \'scheme\' is difficult to translate, then you could use \'prefix\' instead.',
  'http-bad-status' => '$1 is an HTTP error code (e.g. 404), $2 is the HTTP error message (e.g. File Not Found)',
 -'http-truncated-body' => 'This is a standard HTTP error message. → Seems the connection closed prematurely. The HTTP response contained a content-length greater than the received body.',
  
  'license' => 'This appears in the upload form for the license drop-down. The header in the file description page is now at {{msg-mw|License-header}}.',
  'nolicense' => '{{Identical|None selected}}',
@@@ -2365,7 -2344,7 +2366,7 @@@ $1 is a page title"
  'nopagetitle' => 'Used as title of [[Special:MovePage]], when the oldtitle does not exist.
  
  The text is {{msg-mw|nopagetext}}.',
 -'nopagetext' => 'Used as text of [[Special:MovePage]], when the oldtitle does not exist.
 +'nopagetext' => 'Used as text on special pages like [[Special:MovePage]] (when the oldtitle does not exist) or [[Special:PermaLink]].
  
  The title is {{msg-mw|nopagetitle}}.',
  'pager-newer-n' => "This is part of the navigation message on the top and bottom of Special pages which are lists of things in date order, e.g. the User's contributions page. It is passed as the second argument of {{msg-mw|Viewprevnext}}. $1 is the number of items shown per page.",
  'booksources-go' => 'Name of button in [[Special:BookSources]]
  
  {{Identical|Go}}',
 -'booksources-invalid-isbn' => 'This message is displayed after an invalid ISBN is entered on Special:Booksources.',
 +'booksources-invalid-isbn' => 'This message is displayed after an invalid ISBN is entered on [[Special:Booksources]].',
  
  # Special:Log
  'specialloguserlabel' => 'Used in [[Special:Log]] as a label for an input field with which the log can be filtered for entries describing actions \'\'performed\'\' by the specified user.  "Carried out" and "done" are possible alternatives for "performed".',
  'alllogstext' => 'Header of [[Special:Log]]',
  'log-title-wildcard' => '* Appears in: [[Special:Log]]
  * Description: A check box to enable prefix search option',
 +'showhideselectedlogentries' => 'Text of the button which brings up the [[mw:RevisionDelete|RevisionDelete]] menu on [[Special:Log]].',
  
  # Special:AllPages
  'allpages' => 'First part of the navigation bar for the special page [[Special:AllPages]] and [[Special:PrefixIndex]]. The other parts are {{msg-mw|Prevpage}} and {{msg-mw|Nextpage}}.
@@@ -2488,7 -2466,7 +2489,7 @@@ You can apparently use 'URL' instead o
  'activeusers-noresult' => 'identical with {{msg-mw|listusers-noresult}}',
  
  # Special:Log/newusers
 -'newuserlogpage' => 'Part of the "Newuserlog" extension. It is both the title of [[Special:Log/newusers]] and the link you can see in the recent changes.',
 +'newuserlogpage' => 'Part of the "Newuserlog" extension. It is both the title of [[Special:Log/newusers]] and the link you can see in [[Special:RecentChanges]].',
  'newuserlogpagetext' => 'Part of the "Newuserlog" extension. It is the description you can see on [[Special:Log/newusers]].',
  
  # Special:ListGroupRights
@@@ -2600,7 -2578,7 +2601,7 @@@ This is a button text used in [[Special
  Possible alternatives to the word 'content' are 'subject matter' or 'wiki subject' or 'wiki purpose'.
  
  {{Identical|Content page}}",
 -'watchlist-details' => 'Message on Special page: My watchlist. This is paired with the message [[Mediawiki:Nowatchlist]] which appears instead of Watchlist-details when $1 is 0.',
 +'watchlist-details' => 'Message on [[Special:Watchlist]]. This is paired with the message {{msg-mw|Nowatchlist}} which appears instead of Watchlist-details when $1 is 0.',
  'wlheader-showupdated' => 'This message shows up near top of users watchlist page.',
  'wlnote' => 'Used on [[Special:Watchlist]] when the maximum number of days is specified.
  Similar to {{msg-mw|rcnote}} which is used on [[Special:RecentChanges]].
  'unwatching' => 'Text displayed when clicked on the unwatch tab: [[MediaWiki:Unwatch/{{SUBPAGENAME}}|{{int:unwatch}}]]. It means the wiki is removing that page from your watchlist.',
  'watcherrortext' => 'When a user clicked the watch/unwatch tab and the action did not succeed, this message is displayed. See also {{msg|addedwatchtext}}. and {{msg|addedwatchtext}}. This message is used raw and should not contain wikitext.',
  
 +'enotif_reset' => "This should be translated as \"Mark all pages '''as''' visited\".",
  'enotif_newpagetext' => 'Part of text of a notification e-mail sent when a watched page has been created. See [[File:Screenshot_MediaWiki_e-mail_notifier.PNG|150px|right]]',
  'changed' => 'Possible value for $CHANGEDORCREATED in {{msg|enotif_subject}} and {{msg|enotif_body}}.',
  'created' => 'Possible value for $CHANGEDORCREATED in {{msg|enotif_subject}} and {{msg|enotif_body}}.',
@@@ -2750,8 -2727,8 +2751,8 @@@ This message was something like "unloc
  {{Identical|Infinite}}",
  'restriction-type' => 'Used on [[Special:ProtectedPages]]. The text next to a drop-down box. See [[mw:Manual:Administrators|MediaWiki Manual]] for more information on protection.',
  'restriction-level' => 'Used on [[Special:ProtectedPages]] and [[Special:ProtectedTitles]]. The text next to a drop-down box. See the [//www.mediawiki.org/wiki/Project:Protected_titles help page on Mediawiki] and on [http://meta.wikimedia.org/wiki/Protect Meta] for more information.',
 -'minimum-size' => 'Used in [[Special:Protectedpages]] as a pair of radio buttons, with [[MediaWiki:Maximum-size]]. There is an input box to specify the minimum bites of the projected pages listed.',
 -'maximum-size' => 'Used in [[Special:Protectedpages]] as a pair of radio buttons, with [[MediaWiki:Minimum-size]]. There is an input box to specify the maximum bites of the projected pages listed.',
 +'minimum-size' => 'Used in [[Special:Protectedpages]] as a pair of radio buttons, with {{msg-mw|Maximum-size}}. There is an input box to specify the minimum bites of the projected pages listed.',
 +'maximum-size' => 'Used in [[Special:Protectedpages]] as a pair of radio buttons, with {{msg-mw|Minimum-size}}. There is an input box to specify the maximum bites of the projected pages listed.',
  'pagesize' => 'Used on [[Special:ProtectedPages]]. See the help page on [http://meta.wikimedia.org/wiki/Protect Meta] for more information on protection.',
  
  # Restrictions (nouns)
  
  {{identical|Are you sure you want to view the deleted revision of the file...}}',
  'undelete-show-file-submit' => '{{Identical|Yes}}',
 +'undelete-revisionrow' => "A revision row in the undelete page. Parameters:
 +* $1 is a checkBox to indicate whether to restore this specific revision
 +* $2 is a link to the revision
 +* $3 is a link to the last revision of a page ({{msg-mw|last}})
 +* $4 is a link to the page
 +* $5 is a link to the revision's user
 +* $6 is the revision size
 +* $7 is the revision comment",
  
  # Namespace form on various pages
  'namespace' => 'This message is located at [[Special:Contributions]].',
@@@ -3080,7 -3049,6 +3081,7 @@@ See also {{msg-mw|Movepagetext-noredire
  'movetalk' => 'The text of the checkbox to watch the associated talk page to the page you are moving. This only appears when the talk page is not empty.',
  'move-subpages' => 'The text of an option on the special page [[Special:MovePage|MovePage]]. If this option is ticked, any subpages will be moved with the main page to a new title.',
  'move-talk-subpages' => 'The text of an option on the special page [[Special:MovePage|MovePage]]. If this option is ticked, any talk subpages will be moved with the talk page to a new title.',
 +'movepage-max-pages' => 'PROBABLY (A GUESS): when moving a page, you can select an option of moving its subpages, but there is a maximum that can be moved automatically.',
  'movelogpage' => 'Title of [[Special:Log/move]]. Used as heading on that page, and in the dropdown menu on log pages.',
  'movelogpagetext' => "Text on the special page 'Move log'.",
  'movesubpage' => "This is a section header on [[Special:MovePage]], below is a list of subpages.
@@@ -3091,7 -3059,6 +3092,7 @@@ Parameters
  
  {{Identical|Reason}}',
  'revertmove' => '{{Identical|Revert}}',
 +'delete_and_move' => 'Button text on the move page when the target page already exists.',
  'delete_and_move_text' => 'Used when moving a page, but the destination page already exists and needs deletion. This message is to confirm that you really want to delete the page. See also {{msg|delete and move confirm}}.',
  'delete_and_move_confirm' => 'Used when moving a page, but the destination page already exists and needs deletion. This message is for a checkbox to confirm that you really want to delete the page. See also {{msg|delete and move text}}.',
  'delete_and_move_reason' => 'Shown as reason in content language in the deletion log. Parameter:
@@@ -3201,7 -3168,7 +3202,7 @@@ See also
  # Tooltip help for the actions
  'tooltip-pt-userpage' => 'Tooltip shown when hovering the mouse over the link to your own User page in the upper-side personal toolbox.',
  'tooltip-pt-mytalk' => 'Tooltip shown when hovering over the "my talk" link in your personal toolbox (upper right side).',
 -'tooltip-pt-preferences' => 'Tooltip shown when hovering over the "my preferences" ([[MediaWiki:Mypreferences]]) link in your personal toolbox (upper right side).
 +'tooltip-pt-preferences' => 'Tooltip shown when hovering over the {{msg-mw|Mypreferences}} link in your personal toolbox (upper right side).
  
  {{Identical|My preferences}}',
  'tooltip-pt-watchlist' => 'Tooltip shown when hovering over the "my watchlist" link in your personal toolbox (upper right side).',
@@@ -3229,8 -3196,8 +3230,8 @@@ Possible alternatives to the word 'cont
  'tooltip-ca-watch' => '{{Identical|Add this page to your watchlist}}',
  'tooltip-ca-unwatch' => 'Tooltip shown when hovering over the {{msg|unwatch}} tab.',
  'tooltip-search' => 'The tooltip when hovering over the search menu.',
 -'tooltip-search-go' => 'This is the text of the tooltip displayed when hovering the mouse over the “[[MediaWiki:Go|Go]]” button next to the search box.',
 -'tooltip-search-fulltext' => 'This is the text of the tooltip displayed when hovering the mouse over the “[[MediaWiki:Search|Search]]” button under the search box.',
 +'tooltip-search-go' => 'This is the text of the tooltip displayed when hovering the mouse over the “{{msg-mw|Go}}” button next to the search box.',
 +'tooltip-search-fulltext' => 'This is the text of the tooltip displayed when hovering the mouse over the “{{msg-mw|Search}}” button under the search box.',
  'tooltip-p-logo' => 'Tool tip shown when hovering the mouse over the logo that links to [[Main Page]].
  {{Identical|Visit the main page}}',
  'tooltip-n-mainpage' => 'Tool tip shown when hovering the mouse over the link to [[{{MediaWiki:Mainpage}}]].
@@@ -3258,7 -3225,7 +3259,7 @@@ No GENDER-Support for performance reaso
  'tooltip-ca-nstab-template' => 'Tooltip shown when hovering over the {{msg|nstab-template}} tab.',
  'tooltip-ca-nstab-help' => 'Tootip shown when hovering over the {{msg|nstab-help}} tab in the Help namespace.',
  'tooltip-ca-nstab-category' => 'Tooltip shown when hovering over the {{msg|nstab-category}} tab.',
 -'tooltip-minoredit' => 'Tooltip shown when hovering over the "[[MediaWiki:Minoredit/{{SUBPAGENAME}}|{{int:minoredit}}]]" link below the edit form.',
 +'tooltip-minoredit' => 'Tooltip shown when hovering over the "{{msg-mw|Minoredit}}" link below the edit form.',
  'tooltip-save' => "This is the text that appears when you hover the mouse over the 'Save page' button on the edit page",
  'tooltip-preview' => 'Tooltip shown when hovering over the "Show preview" button.
  
@@@ -3363,12 -3330,7 +3364,12 @@@ See also {{msg-mw|Anonuser}} and {{msg-
  'nocredits' => 'This message is shown when viewing the credits of a page (example: {{fullurl:Main Page|action=credits}}) but when there are no credits available. Note that the credits action is disabled by default (currently enabled on translatewiki.net).',
  
  # Spam protection
 -'spam_reverting' => '{{Identical|Revert}}',
 +'spam_reverting' => 'Edit summary for spam cleanup script. Used when a page is reverted because all later revisions contained a particular link. Parameters:
 +* $1 is a spammed domain name.',
 +'spam_blanking' => 'Edit summary for spam cleanup script. Used when a page is blanked (made to have no content, but still exist) because the script could not find an appropriate revision to set the page to. Parameters:
 +* $1 is a spammed domain name.',
 +'spam_deleting' => 'Edit summary for spam cleanup script. Used when a page is deleted because all revisions contained a particular link. Parameters:
 +* $1 is a spammed domain name.',
  
  # Info page
  'pageinfo-title' => 'Page title for action=info.
@@@ -3514,7 -3476,7 +3515,7 @@@ Part of variable $1 in {{msg-mw|Ago}
  *{{msg-mw|Days}}',
  
  # Bad image list
 -'bad_image_list' => 'This is only message appears to guide administrators to add links with right format. This will not appear anywhere else in Mediawiki.',
 +'bad_image_list' => 'This message only appears to guide administrators to add links with the right format. This will not appear anywhere else in MediaWiki.',
  
  /*
  Short names for language variants used for language conversion links.
@@@ -4060,7 -4022,6 +4061,7 @@@ CW is an abbreviation for clockwise.'
  'exif-contrast-2' => '{{Identical|Hard}}',
  
  'exif-saturation-0' => '{{Identical|Normal}}',
 +'exif-saturation-2' => 'Color saturation in picture EXIF data',
  
  'exif-sharpness-0' => '{{Identical|Normal}}',
  'exif-sharpness-1' => '{{Identical|Soft}}',
@@@ -4301,14 -4262,14 +4302,14 @@@ Bitrate (of a file, typically) in yotta
  'livepreview-loading' => '{{Identical|Loading}}',
  
  # Watchlist editor
 -'watchlistedit-numitems' => 'Message on Special page: Edit watchlist. This is paired with the message [[Mediawiki:Watchlistedit-noitems]] which appears instead of Watchlistedit-numitems when $1 is 0.',
 -'watchlistedit-noitems' => "Message on [[Special:Watchlist/edit]], which only appears when a user's watchlist is empty.",
 +'watchlistedit-numitems' => 'Message on [[Special:EditWatchlist]]. This is paired with the message {{Msg-mw|Watchlistedit-noitems}} which appears instead of Watchlistedit-numitems when $1 is 0.',
 +'watchlistedit-noitems' => "Message on [[Special:EditWatchlist]], which only appears when a user's watchlist is empty.",
  'watchlistedit-normal-title' => 'Title of [[Special:Watchlist/edit|special page]].',
  'watchlistedit-normal-legend' => 'Heading of dialogue box on [[Special:Watchlist/edit]]',
  'watchlistedit-normal-explain' => 'An introduction/explanation about the [[Special:Watchlist/edit|normal edit watchlist function]].
  Hint: the text "Remove Titles" is in {{msg-mw|watchlistedit-normal-submit}}',
  'watchlistedit-normal-submit' => 'Text of submit button on [[Special:Watchlist/edit]].',
 -'watchlistedit-normal-done' => 'Message on Special page: Edit watchlist after pages are removed from the watchlist.',
 +'watchlistedit-normal-done' => 'Message on [[Special:EditWatchlist]] after pages are removed from the watchlist.',
  'watchlistedit-raw-title' => 'Title of [[Special:Watchlist/raw|Special page]].
  
  {{Identical|Edit raw watchlist}}',
  'watchlistedit-raw-titles' => 'Text above edit box containing items being watched on [[Special:Watchlist/raw]].',
  'watchlistedit-raw-submit' => 'Text of submit button on [[Special:Watchlist/raw]].',
  'watchlistedit-raw-done' => 'A message which appears after the raw watchlist has been updated using [[Special:Watchlist/raw]].',
 -'watchlistedit-raw-added' => 'Message on special page: Edit raw watchlist. The message appears after at least 1 message is added to the raw watchlist.',
 -'watchlistedit-raw-removed' => 'Message on special page: Edit raw watchlist. The message appears after at least 1 message is deleted from the raw watchlist.',
 +'watchlistedit-raw-added' => 'Message on [[Special:EditWatchlist/raw]]. The message appears after at least 1 message is added to the raw watchlist.',
 +'watchlistedit-raw-removed' => 'Message on [[Special:EditWatchlist/raw]]. The message appears after at least 1 message is deleted from the raw watchlist.',
  
  # Watchlist editing tools
  'watchlisttools-view' => '[[Special:Watchlist]]: Navigation link under the title. See also {{msg|watchlisttools-edit}} and {{msg|watchlisttools-raw}}.',
@@@ -4565,7 -4526,7 +4566,7 @@@ It appears that the word 'valid' descri
  'tags-hitcount-header' => 'Caption of a column in [[Special:Tags]]. For more information on tags see [//www.mediawiki.org/wiki/Manual:Tags Mediawiki].',
  'tags-edit' => '{{Identical|Edit}}
  Used on [[Special:Tags]]. Verb. Used as display text on a link to create/edit a description.',
 -'tags-hitcount' => 'Shown in the “Tagged changes” column in [[Special:Tags]]. For more information on tags see [//www.mediawiki.org/wiki/Manual:Tags Mediawiki].
 +'tags-hitcount' => 'Shown in the "{{msg-mw|Tags-hitcount-header}}" column in [[Special:Tags]]. For more information on tags see [//www.mediawiki.org/wiki/Manual:Tags Mediawiki].
  
  * <code>$1</code> is the number of changes marked with the tag',
  
@@@ -157,7 -157,6 +157,7 @@@ $wgMessageStructure = array
                'index-category',
                'noindex-category',
                'broken-file-category',
 +              'categoryviewer-pagedlinks',
        ),
        'mainpage' => array(
                'linkprefix',
                'badarticleerror',
                'cannotdelete',
                'cannotdelete-title',
+               'delete-hook-aborted',
                'badtitle',
                'badtitletext',
                'perfcached',
                'filereadonlyerror',
                'invalidtitle-knownnamespace',
                'invalidtitle-unknownnamespace',
 +              'exception-nologin',
 +              'exception-nologin-text',
        ),
        'virus' => array(
                'virus-badscanner',
                'mergehistory-autocomment',
                'mergehistory-comment',
                'mergehistory-same-destination',
 -              'mergehistory-reason'
 +              'mergehistory-reason',
 +              'mergehistory-revisionrow'
        ),
        'mergelog' => array(
                'mergelog',
                'prefs-beta',
                'prefs-datetime',
                'prefs-labs',
 +              'prefs-user-pages',
                'prefs-personal',
                'prefs-rc',
                'prefs-watchlist',
                'recentchanges',
                'recentchanges-url',
                'recentchanges-legend',
 +              'recentchanges-summary',
                'recentchangestext',
                'recentchanges-feed-description',
                'recentchanges-label-newpage',
                'backend-fail-connect',
                'backend-fail-internal',
                'backend-fail-contenttype',
 -              'backend-fail-batchsize'
 +              'backend-fail-batchsize',
 +              'backend-fail-usable'
        ),
  
        'filejournal-errors' => array(
                'lockmanager-fail-deletelock',
                'lockmanager-fail-acquirelock',
                'lockmanager-fail-openlock',
 +              'lockmanager-fail-acquirelock',
                'lockmanager-fail-releaselock',
                'lockmanager-fail-db-bucket',
                'lockmanager-fail-db-release',
                'http-curl-error',
                'http-host-unreachable',
                'http-bad-status',
 -              'http-truncated-body',
        ),
  
        'upload-curl-errors' => array(
                'alllogstext',
                'logempty',
                'log-title-wildcard',
 +              'showhideselectedlogentries',
        ),
        'allpages' => array(
                'allpages',
                'undelete-error-long',
                'undelete-show-file-confirm',
                'undelete-show-file-submit',
 +              'undelete-revisionrow',
        ),
        'nsform' => array(
                'namespace',
                'spambot_username',
                'spam_reverting',
                'spam_blanking',
 +              'spam_deleting',
        ),
        'info' => array(
                'pageinfo-title',
                'ellipsis',
                'percent',
                'parentheses',
 +              'brackets',
        ),
        'imgmulti' => array(
                'imgmultipageprev',