Merge "AJAXify watchlist editor"
authorCatrope <roan.kattouw@gmail.com>
Wed, 1 Aug 2012 00:24:46 +0000 (00:24 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 1 Aug 2012 00:24:46 +0000 (00:24 +0000)
1  2 
includes/api/ApiWatch.php
includes/specials/SpecialEditWatchlist.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc
resources/Resources.php

@@@ -4,7 -4,7 +4,7 @@@
   *
   * Created on Jan 4, 2008
   *
 - * Copyright © 2008 Yuri Astrakhan <Firstname><Lastname>@gmail.com,
 + * Copyright © 2008 Yuri Astrakhan "<Firstname><Lastname>@gmail.com",
   *
   * 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
@@@ -40,14 -40,27 +40,27 @@@ class ApiWatch extends ApiBase 
                if ( !$user->isLoggedIn() ) {
                        $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
                }
                $params = $this->extractRequestParams();
-               $title = Title::newFromText( $params['title'] );
-               if ( !$title || $title->getNamespace() < 0 ) {
-                       $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+               // titles can handle basic request of 1 title,
+               // but title is still supported for backward compatability
+               if ( isset( $params['title'] ) ) {
+                       $title = Title::newFromText( $params['title'] );
+                       if ( !$title || $title->getNamespace() < 0 ) {
+                               $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+                       }
+                       $res = $this->watchTitle( $title, $user, $params);
+               } else {
+                       $pageSet = new ApiPageSet( $this );
+                       $pageSet->execute();
+                       $res = array();
+                       foreach ( $pageSet->getTitles() as $title ) {
+                               $r = $this->watchTitle( $title, $user, $params);
+                               $res[] = $r;
+                       }
                }
+               $this->getResult()->addValue( null, $this->getModuleName(), $res );
+       }
+       private function watchTitle( $title, $user, $params ) {
                $res = array( 'title' => $title->getPrefixedText() );
  
                if ( $params['unwatch'] ) {
@@@ -62,7 -75,7 +75,7 @@@
                if ( !$success ) {
                        $this->dieUsageMsg( 'hookaborted' );
                }
-               $this->getResult()->addValue( null, $this->getModuleName(), $res );
+               return $res;
        }
  
        public function mustBePosted() {
                return array(
                        'title' => array(
                                ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => true
+                       ),
+                       'titles' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_ISMULTI => true
                        ),
                        'unwatch' => false,
 -                      'token' => null,
 +                      'token' => array(
 +                              ApiBase::PARAM_TYPE => 'string',
 +                              ApiBase::PARAM_REQUIRED => true
 +                      ),
                );
        }
  
@@@ -43,6 -43,8 +43,8 @@@ class SpecialEditWatchlist extends Unli
        const EDIT_RAW = 2;
        const EDIT_NORMAL = 3;
  
+       protected $offset = 0;
+       protected $limit = 0;
        protected $successMessage;
  
        protected $toc;
@@@ -92,6 -94,7 +94,7 @@@
                        }
                }
                $mode = self::getMode( $this->getRequest(), $mode );
+               list( $this->limit, $this->offset ) = $this->getRequest()->getLimitOffset( 50, 'wllimit' );
  
                switch( $mode ) {
                        case self::EDIT_CLEAR:
                        case self::EDIT_NORMAL:
                        default:
                                $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) );
+                               $out->addModules( 'mediawiki.special.editWatchlist' );
                                $form = $this->getNormalForm();
                                if( $form->show() ){
                                        $out->addHTML( $this->successMessage );
         * @return array
         */
        private function extractTitles( $list ) {
 -              $titles = array();
                $list = explode( "\n", trim( $list ) );
                if( !is_array( $list ) ) {
                        return array();
                }
 +              $titles = array();
                foreach( $list as $text ) {
                        $text = trim( $text );
                        if( strlen( $text ) > 0 ) {
                                $title = Title::newFromText( $text );
                                if( $title instanceof Title && $title->isWatchable() ) {
 -                                      $titles[] = $title->getPrefixedText();
 +                                      $titles[] = $title;
                                }
                        }
                }
 -              return array_unique( $titles );
 +
 +              GenderCache::singleton()->doTitlesArray( $titles );
 +
 +              $list = array();
 +              foreach( $titles as $title ) {
 +                      $list[] = $title->getPrefixedText();
 +              }
 +              return array_unique( $list );
        }
  
        public function submitRaw( $data ){
                        __METHOD__
                );
                if( $res->numRows() > 0 ) {
 +                      $titles = array();
                        foreach ( $res as $row ) {
                                $title = Title::makeTitleSafe( $row->wl_namespace, $row->wl_title );
                                if ( $this->checkTitle( $title, $row->wl_namespace, $row->wl_title )
                                        && !$title->isTalkPage()
                                ) {
 -                                      $list[] = $title->getPrefixedText();
 +                                      $titles[] = $title;
                                }
                        }
                        $res->free();
 +
 +                      GenderCache::singleton()->doTitlesArray( $titles );
 +
 +                      foreach( $titles as $title ) {
 +                              $list[] = $title->getPrefixedText();
 +                      }
                }
                $this->cleanupWatchlist();
                return $list;
        }
  
        /**
-        * Get a list of titles on a user's watchlist, excluding talk pages,
-        * and return as a two-dimensional array with namespace and title.
-        *
-        * @return array
-        */
-       private function getWatchlistInfo() {
-               $titles = array();
+       * select from DB  watchlist items watched by the current user
+       * @return q query result of watchlist items watched by the current user
+       */
+       private function selectWatchListInfo( ) {
+               $options = array(
+                       'ORDER BY' => array( 'wl_namespace', 'wl_title' ),
+                       'LIMIT' => intval( $this->limit ),
+                       'OFFSET' => intval( $this->offset )
+               );
                $dbr = wfGetDB( DB_MASTER );
+               //query only non talk namespaces.
+               $nonTalkNamespaces = MWNamespace::getContentNamespaces();
                $res = $dbr->select(
                        array( 'watchlist' ),
                        array( 'wl_namespace',  'wl_title' ),
-                       array( 'wl_user' => $this->getUser()->getId() ),
+                       array( 'wl_user' => $this->getUser()->getId(), 'wl_namespace' => $nonTalkNamespaces  ),
                        __METHOD__,
-                       array( 'ORDER BY' => array( 'wl_namespace', 'wl_title' ) )
+                       $options
                );
  
+               return $res;
+       }
+       /**
+        * Get a list of titles on a user's watchlist, excluding talk pages,
+        * and return as a two-dimensional array with namespace and title.
+        *
+        * @param $watchedItems rows of watched items
+        * @return array
+        */
+       private function getWatchlistInfo( $watchedItems ) {
+               $titles = array();
                $lb = new LinkBatch();
-               foreach ( $res as $row ) {
+               foreach ( $watchedItems as $row ) {
                        $lb->add( $row->wl_namespace, $row->wl_title );
-                       if ( !MWNamespace::isTalk( $row->wl_namespace ) ) {
-                               $titles[$row->wl_namespace][$row->wl_title] = 1;
-                       }
+                       $titles[$row->wl_namespace][$row->wl_title] = 1;
                }
  
                $lb->execute();
  
                $fields = array();
                $count = 0;
-               foreach( $this->getWatchlistInfo() as $namespace => $pages ){
+               $watchedItems = $this->selectWatchListInfo();
+               $rowNum = $watchedItems->numRows();
+               foreach ( $this->getWatchlistInfo( $watchedItems ) as $namespace => $pages ) {
                        if ( $namespace >= 0 ) {
                                $fields['TitlesNs'.$namespace] = array(
                                        'class' => 'EditWatchlistCheckboxSeriesField',
                                );
                        }
  
-                       foreach( array_keys( $pages ) as $dbkey ){
+                       foreach ( array_keys( $pages ) as $dbkey ) {
                                $title = Title::makeTitleSafe( $namespace, $dbkey );
                                if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
                                        $text = $this->buildRemoveLine( $title );
                $form = new EditWatchlistNormalHTMLForm( $fields, $this->getContext() );
                $form->setTitle( $this->getTitle() );
                $form->setSubmitTextMsg( 'watchlistedit-normal-submit' );
+               $form->setSubmitID( 'watchlistedit-submit' );
                # Used message keys: 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit'
                $form->setSubmitTooltip('watchlistedit-normal-submit');
                $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' );
-               $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() );
+               $paging = '<p>' . $this->getLanguage()->viewPrevNext( $this->getTitle(), $this->offset,
+                               $this->limit,  array(), ( $rowNum < $this->limit ) ) . '</p>';
+               $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() . $paging );
                $form->setSubmitCallback( array( $this, 'submitNormal' ) );
                return $form;
        }
  
                wfRunHooks( 'WatchlistEditorBuildRemoveLine', array( &$tools, $title, $title->isRedirect(), $this->getSkin() ) );
  
-               return $link . " (" . $this->getLanguage()->pipeList( $tools ) . ")";
+               return '<span class="watchlist-item">' . $link . '</span>' . " (" . $this->getLanguage()->pipeList( $tools ) . ")";
        }
  
        /**
@@@ -200,166 -200,161 +200,166 @@@ $bookstoreList = array
   * This array can be modified at runtime with the LanguageGetMagic hook
   */
  $magicWords = array(
 -#   ID                                 CASE  SYNONYMS
 -      'redirect'               => array( 0,    '#REDIRECT'              ),
 -      'notoc'                  => array( 0,    '__NOTOC__'              ),
 -      'nogallery'              => array( 0,    '__NOGALLERY__'          ),
 -      'forcetoc'               => array( 0,    '__FORCETOC__'           ),
 -      'toc'                    => array( 0,    '__TOC__'                ),
 -      'noeditsection'          => array( 0,    '__NOEDITSECTION__'      ),
 -      'noheader'               => array( 0,    '__NOHEADER__'           ),
 -      'currentmonth'           => array( 1,    'CURRENTMONTH', 'CURRENTMONTH2' ),
 -      'currentmonth1'          => array( 1,    'CURRENTMONTH1'          ),
 -      'currentmonthname'       => array( 1,    'CURRENTMONTHNAME'       ),
 -      'currentmonthnamegen'    => array( 1,    'CURRENTMONTHNAMEGEN'    ),
 -      'currentmonthabbrev'     => array( 1,    'CURRENTMONTHABBREV'     ),
 -      'currentday'             => array( 1,    'CURRENTDAY'             ),
 -      'currentday2'            => array( 1,    'CURRENTDAY2'            ),
 -      'currentdayname'         => array( 1,    'CURRENTDAYNAME'         ),
 -      'currentyear'            => array( 1,    'CURRENTYEAR'            ),
 -      'currenttime'            => array( 1,    'CURRENTTIME'            ),
 -      'currenthour'            => array( 1,    'CURRENTHOUR'            ),
 -      'localmonth'             => array( 1,    'LOCALMONTH', 'LOCALMONTH2' ),
 -      'localmonth1'            => array( 1,    'LOCALMONTH1'             ),
 -      'localmonthname'         => array( 1,    'LOCALMONTHNAME'         ),
 -      'localmonthnamegen'      => array( 1,    'LOCALMONTHNAMEGEN'      ),
 -      'localmonthabbrev'       => array( 1,    'LOCALMONTHABBREV'       ),
 -      'localday'               => array( 1,    'LOCALDAY'               ),
 -      'localday2'              => array( 1,    'LOCALDAY2'              ),
 -      'localdayname'           => array( 1,    'LOCALDAYNAME'           ),
 -      'localyear'              => array( 1,    'LOCALYEAR'              ),
 -      'localtime'              => array( 1,    'LOCALTIME'              ),
 -      'localhour'              => array( 1,    'LOCALHOUR'              ),
 -      'numberofpages'          => array( 1,    'NUMBEROFPAGES'          ),
 -      'numberofarticles'       => array( 1,    'NUMBEROFARTICLES'       ),
 -      'numberoffiles'          => array( 1,    'NUMBEROFFILES'          ),
 -      'numberofusers'          => array( 1,    'NUMBEROFUSERS'          ),
 -      'numberofactiveusers'    => array( 1,    'NUMBEROFACTIVEUSERS'    ),
 -      'numberofedits'          => array( 1,    'NUMBEROFEDITS'          ),
 -      'numberofviews'          => array( 1,    'NUMBEROFVIEWS'          ),
 -      'pagename'               => array( 1,    'PAGENAME'               ),
 -      'pagenamee'              => array( 1,    'PAGENAMEE'              ),
 -      'namespace'              => array( 1,    'NAMESPACE'              ),
 -      'namespacee'             => array( 1,    'NAMESPACEE'             ),
 -      'namespacenumber'        => array( 1,    'NAMESPACENUMBER'        ),
 -      'talkspace'              => array( 1,    'TALKSPACE'              ),
 -      'talkspacee'             => array( 1,    'TALKSPACEE'              ),
 -      'subjectspace'           => array( 1,    'SUBJECTSPACE', 'ARTICLESPACE' ),
 -      'subjectspacee'          => array( 1,    'SUBJECTSPACEE', 'ARTICLESPACEE' ),
 -      'fullpagename'           => array( 1,    'FULLPAGENAME'           ),
 -      'fullpagenamee'          => array( 1,    'FULLPAGENAMEE'          ),
 -      'subpagename'            => array( 1,    'SUBPAGENAME'            ),
 -      'subpagenamee'           => array( 1,    'SUBPAGENAMEE'           ),
 -      'basepagename'           => array( 1,    'BASEPAGENAME'           ),
 -      'basepagenamee'          => array( 1,    'BASEPAGENAMEE'          ),
 -      'talkpagename'           => array( 1,    'TALKPAGENAME'           ),
 -      'talkpagenamee'          => array( 1,    'TALKPAGENAMEE'          ),
 -      'subjectpagename'        => array( 1,    'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
 -      'subjectpagenamee'       => array( 1,    'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
 -      'msg'                    => array( 0,    'MSG:'                   ),
 -      'subst'                  => array( 0,    'SUBST:'                 ),
 -      'safesubst'              => array( 0,    'SAFESUBST:'             ),
 -      'msgnw'                  => array( 0,    'MSGNW:'                 ),
 -      'img_thumbnail'          => array( 1,    'thumbnail', 'thumb'     ),
 -      'img_manualthumb'        => array( 1,    'thumbnail=$1', 'thumb=$1' ),
 -      'img_right'              => array( 1,    'right'                  ),
 -      'img_left'               => array( 1,    'left'                   ),
 -      'img_none'               => array( 1,    'none'                   ),
 -      'img_width'              => array( 1,    '$1px'                   ),
 -      'img_center'             => array( 1,    'center', 'centre'       ),
 -      'img_framed'             => array( 1,    'framed', 'enframed', 'frame' ),
 -      'img_frameless'          => array( 1,    'frameless'              ),
 -      'img_page'               => array( 1,    'page=$1', 'page $1'     ),
 -      'img_upright'            => array( 1,    'upright', 'upright=$1', 'upright $1'  ),
 -      'img_border'             => array( 1,    'border'                 ),
 -      'img_baseline'           => array( 1,    'baseline'               ),
 -      'img_sub'                => array( 1,    'sub'                    ),
 -      'img_super'              => array( 1,    'super', 'sup'           ),
 -      'img_top'                => array( 1,    'top'                    ),
 -      'img_text_top'           => array( 1,    'text-top'               ),
 -      'img_middle'             => array( 1,    'middle'                 ),
 -      'img_bottom'             => array( 1,    'bottom'                 ),
 -      'img_text_bottom'        => array( 1,    'text-bottom'            ),
 -      'img_link'               => array( 1,    'link=$1'                ),
 -      'img_alt'                => array( 1,    'alt=$1'                 ),
 -      'int'                    => array( 0,    'INT:'                   ),
 -      'sitename'               => array( 1,    'SITENAME'               ),
 -      'ns'                     => array( 0,    'NS:'                    ),
 -      'nse'                    => array( 0,    'NSE:'                   ),
 -      'localurl'               => array( 0,    'LOCALURL:'              ),
 -      'localurle'              => array( 0,    'LOCALURLE:'             ),
 -      'articlepath'            => array( 0,    'ARTICLEPATH'            ),
 -      'server'                 => array( 0,    'SERVER'                 ),
 -      'servername'             => array( 0,    'SERVERNAME'             ),
 -      'scriptpath'             => array( 0,    'SCRIPTPATH'             ),
 -      'stylepath'              => array( 0,    'STYLEPATH'              ),
 -      'grammar'                => array( 0,    'GRAMMAR:'               ),
 -      'gender'                 => array( 0,    'GENDER:'                ),
 -      'notitleconvert'         => array( 0,    '__NOTITLECONVERT__', '__NOTC__' ),
 -      'nocontentconvert'       => array( 0,    '__NOCONTENTCONVERT__', '__NOCC__' ),
 -      'currentweek'            => array( 1,    'CURRENTWEEK'            ),
 -      'currentdow'             => array( 1,    'CURRENTDOW'             ),
 -      'localweek'              => array( 1,    'LOCALWEEK'              ),
 -      'localdow'               => array( 1,    'LOCALDOW'               ),
 -      'revisionid'             => array( 1,    'REVISIONID'             ),
 -      'revisionday'            => array( 1,    'REVISIONDAY'            ),
 -      'revisionday2'           => array( 1,    'REVISIONDAY2'           ),
 -      'revisionmonth'          => array( 1,    'REVISIONMONTH'          ),
 -      'revisionmonth1'         => array( 1,    'REVISIONMONTH1'         ),
 -      'revisionyear'           => array( 1,    'REVISIONYEAR'           ),
 -      'revisiontimestamp'      => array( 1,    'REVISIONTIMESTAMP'      ),
 -      'revisionuser'           => array( 1,    'REVISIONUSER'           ),
 -      'plural'                 => array( 0,    'PLURAL:'                ),
 -      'fullurl'                => array( 0,    'FULLURL:'               ),
 -      'fullurle'               => array( 0,    'FULLURLE:'              ),
 -      'canonicalurl'           => array( 0,    'CANONICALURL:'          ),
 -      'canonicalurle'          => array( 0,    'CANONICALURLE:'         ),
 -      'lcfirst'                => array( 0,    'LCFIRST:'               ),
 -      'ucfirst'                => array( 0,    'UCFIRST:'               ),
 -      'lc'                     => array( 0,    'LC:'                    ),
 -      'uc'                     => array( 0,    'UC:'                    ),
 -      'raw'                    => array( 0,    'RAW:'                   ),
 -      'displaytitle'           => array( 1,    'DISPLAYTITLE'           ),
 -      'rawsuffix'              => array( 1,    'R'                      ),
 -      'newsectionlink'         => array( 1,    '__NEWSECTIONLINK__'     ),
 -      'nonewsectionlink'       => array( 1,    '__NONEWSECTIONLINK__'   ),
 -      'currentversion'         => array( 1,    'CURRENTVERSION'         ),
 -      'urlencode'              => array( 0,    'URLENCODE:'             ),
 -      'anchorencode'           => array( 0,    'ANCHORENCODE'           ),
 -      'currenttimestamp'       => array( 1,    'CURRENTTIMESTAMP'       ),
 -      'localtimestamp'         => array( 1,    'LOCALTIMESTAMP'         ),
 -      'directionmark'          => array( 1,    'DIRECTIONMARK', 'DIRMARK' ),
 -      'language'               => array( 0,    '#LANGUAGE:'             ),
 -      'contentlanguage'        => array( 1,    'CONTENTLANGUAGE', 'CONTENTLANG' ),
 -      'pagesinnamespace'       => array( 1,    'PAGESINNAMESPACE:', 'PAGESINNS:' ),
 -      'numberofadmins'         => array( 1,    'NUMBEROFADMINS'         ),
 -      'formatnum'              => array( 0,    'FORMATNUM'              ),
 -      'padleft'                => array( 0,    'PADLEFT'                ),
 -      'padright'               => array( 0,    'PADRIGHT'               ),
 -      'special'                => array( 0,    'special',               ),
 -      'speciale'               => array( 0,    'speciale',              ),
 -      'defaultsort'            => array( 1,    'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ),
 -      'filepath'               => array( 0,    'FILEPATH:'              ),
 -      'tag'                    => array( 0,    'tag'                    ),
 -      'hiddencat'              => array( 1,    '__HIDDENCAT__'          ),
 -      'pagesincategory'        => array( 1,    'PAGESINCATEGORY', 'PAGESINCAT' ),
 -      'pagesize'               => array( 1,    'PAGESIZE'               ),
 -      'index'                  => array( 1,    '__INDEX__'              ),
 -      'noindex'                => array( 1,    '__NOINDEX__'            ),
 -      'numberingroup'          => array( 1,    'NUMBERINGROUP', 'NUMINGROUP' ),
 -      'staticredirect'         => array( 1,    '__STATICREDIRECT__'     ),
 -      'protectionlevel'        => array( 1,    'PROTECTIONLEVEL'        ),
 -      'formatdate'             => array( 0,    'formatdate', 'dateformat' ),
 -      'url_path'               => array( 0,    'PATH' ),
 -      'url_wiki'               => array( 0,    'WIKI' ),
 -      'url_query'              => array( 0,    'QUERY' ),
 -      'defaultsort_noerror'    => array( 0,    'noerror' ),
 -      'defaultsort_noreplace'  => array( 0,    'noreplace' ),
 +#   ID                                  CASE  SYNONYMS
 +      'redirect'                => array( 0,    '#REDIRECT' ),
 +      'notoc'                   => array( 0,    '__NOTOC__' ),
 +      'nogallery'               => array( 0,    '__NOGALLERY__' ),
 +      'forcetoc'                => array( 0,    '__FORCETOC__' ),
 +      'toc'                     => array( 0,    '__TOC__' ),
 +      'noeditsection'           => array( 0,    '__NOEDITSECTION__' ),
 +      'noheader'                => array( 0,    '__NOHEADER__' ),
 +      'currentmonth'            => array( 1,    'CURRENTMONTH', 'CURRENTMONTH2' ),
 +      'currentmonth1'           => array( 1,    'CURRENTMONTH1' ),
 +      'currentmonthname'        => array( 1,    'CURRENTMONTHNAME' ),
 +      'currentmonthnamegen'     => array( 1,    'CURRENTMONTHNAMEGEN' ),
 +      'currentmonthabbrev'      => array( 1,    'CURRENTMONTHABBREV' ),
 +      'currentday'              => array( 1,    'CURRENTDAY' ),
 +      'currentday2'             => array( 1,    'CURRENTDAY2' ),
 +      'currentdayname'          => array( 1,    'CURRENTDAYNAME' ),
 +      'currentyear'             => array( 1,    'CURRENTYEAR' ),
 +      'currenttime'             => array( 1,    'CURRENTTIME' ),
 +      'currenthour'             => array( 1,    'CURRENTHOUR' ),
 +      'localmonth'              => array( 1,    'LOCALMONTH', 'LOCALMONTH2' ),
 +      'localmonth1'             => array( 1,    'LOCALMONTH1' ),
 +      'localmonthname'          => array( 1,    'LOCALMONTHNAME' ),
 +      'localmonthnamegen'       => array( 1,    'LOCALMONTHNAMEGEN' ),
 +      'localmonthabbrev'        => array( 1,    'LOCALMONTHABBREV' ),
 +      'localday'                => array( 1,    'LOCALDAY' ),
 +      'localday2'               => array( 1,    'LOCALDAY2' ),
 +      'localdayname'            => array( 1,    'LOCALDAYNAME' ),
 +      'localyear'               => array( 1,    'LOCALYEAR' ),
 +      'localtime'               => array( 1,    'LOCALTIME' ),
 +      'localhour'               => array( 1,    'LOCALHOUR' ),
 +      'numberofpages'           => array( 1,    'NUMBEROFPAGES' ),
 +      'numberofarticles'        => array( 1,    'NUMBEROFARTICLES' ),
 +      'numberoffiles'           => array( 1,    'NUMBEROFFILES' ),
 +      'numberofusers'           => array( 1,    'NUMBEROFUSERS' ),
 +      'numberofactiveusers'     => array( 1,    'NUMBEROFACTIVEUSERS' ),
 +      'numberofedits'           => array( 1,    'NUMBEROFEDITS' ),
 +      'numberofviews'           => array( 1,    'NUMBEROFVIEWS' ),
 +      'pagename'                => array( 1,    'PAGENAME' ),
 +      'pagenamee'               => array( 1,    'PAGENAMEE' ),
 +      'namespace'               => array( 1,    'NAMESPACE' ),
 +      'namespacee'              => array( 1,    'NAMESPACEE' ),
 +      'namespacenumber'         => array( 1,    'NAMESPACENUMBER' ),
 +      'talkspace'               => array( 1,    'TALKSPACE' ),
 +      'talkspacee'              => array( 1,    'TALKSPACEE' ),
 +      'subjectspace'            => array( 1,    'SUBJECTSPACE', 'ARTICLESPACE' ),
 +      'subjectspacee'           => array( 1,    'SUBJECTSPACEE', 'ARTICLESPACEE' ),
 +      'fullpagename'            => array( 1,    'FULLPAGENAME' ),
 +      'fullpagenamee'           => array( 1,    'FULLPAGENAMEE' ),
 +      'subpagename'             => array( 1,    'SUBPAGENAME' ),
 +      'subpagenamee'            => array( 1,    'SUBPAGENAMEE' ),
 +      'basepagename'            => array( 1,    'BASEPAGENAME' ),
 +      'basepagenamee'           => array( 1,    'BASEPAGENAMEE' ),
 +      'talkpagename'            => array( 1,    'TALKPAGENAME' ),
 +      'talkpagenamee'           => array( 1,    'TALKPAGENAMEE' ),
 +      'subjectpagename'         => array( 1,    'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
 +      'subjectpagenamee'        => array( 1,    'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
 +      'msg'                     => array( 0,    'MSG:' ),
 +      'subst'                   => array( 0,    'SUBST:' ),
 +      'safesubst'               => array( 0,    'SAFESUBST:' ),
 +      'msgnw'                   => array( 0,    'MSGNW:' ),
 +      'img_thumbnail'           => array( 1,    'thumbnail', 'thumb' ),
 +      'img_manualthumb'         => array( 1,    'thumbnail=$1', 'thumb=$1' ),
 +      'img_right'               => array( 1,    'right' ),
 +      'img_left'                => array( 1,    'left' ),
 +      'img_none'                => array( 1,    'none' ),
 +      'img_width'               => array( 1,    '$1px' ),
 +      'img_center'              => array( 1,    'center', 'centre' ),
 +      'img_framed'              => array( 1,    'framed', 'enframed', 'frame' ),
 +      'img_frameless'           => array( 1,    'frameless' ),
 +      'img_page'                => array( 1,    'page=$1', 'page $1' ),
 +      'img_upright'             => array( 1,    'upright', 'upright=$1', 'upright $1' ),
 +      'img_border'              => array( 1,    'border' ),
 +      'img_baseline'            => array( 1,    'baseline' ),
 +      'img_sub'                 => array( 1,    'sub' ),
 +      'img_super'               => array( 1,    'super', 'sup' ),
 +      'img_top'                 => array( 1,    'top' ),
 +      'img_text_top'            => array( 1,    'text-top' ),
 +      'img_middle'              => array( 1,    'middle' ),
 +      'img_bottom'              => array( 1,    'bottom' ),
 +      'img_text_bottom'         => array( 1,    'text-bottom' ),
 +      'img_link'                => array( 1,    'link=$1' ),
 +      'img_alt'                 => array( 1,    'alt=$1' ),
 +      'int'                     => array( 0,    'INT:' ),
 +      'sitename'                => array( 1,    'SITENAME' ),
 +      'ns'                      => array( 0,    'NS:' ),
 +      'nse'                     => array( 0,    'NSE:' ),
 +      'localurl'                => array( 0,    'LOCALURL:' ),
 +      'localurle'               => array( 0,    'LOCALURLE:' ),
 +      'articlepath'             => array( 0,    'ARTICLEPATH' ),
 +      'pageid'                  => array( 0,    'PAGEID' ),
 +      'server'                  => array( 0,    'SERVER' ),
 +      'servername'              => array( 0,    'SERVERNAME' ),
 +      'scriptpath'              => array( 0,    'SCRIPTPATH' ),
 +      'stylepath'               => array( 0,    'STYLEPATH' ),
 +      'grammar'                 => array( 0,    'GRAMMAR:' ),
 +      'gender'                  => array( 0,    'GENDER:' ),
 +      'notitleconvert'          => array( 0,    '__NOTITLECONVERT__', '__NOTC__' ),
 +      'nocontentconvert'        => array( 0,    '__NOCONTENTCONVERT__', '__NOCC__' ),
 +      'currentweek'             => array( 1,    'CURRENTWEEK' ),
 +      'currentdow'              => array( 1,    'CURRENTDOW' ),
 +      'localweek'               => array( 1,    'LOCALWEEK' ),
 +      'localdow'                => array( 1,    'LOCALDOW' ),
 +      'revisionid'              => array( 1,    'REVISIONID' ),
 +      'revisionday'             => array( 1,    'REVISIONDAY' ),
 +      'revisionday2'            => array( 1,    'REVISIONDAY2' ),
 +      'revisionmonth'           => array( 1,    'REVISIONMONTH' ),
 +      'revisionmonth1'          => array( 1,    'REVISIONMONTH1' ),
 +      'revisionyear'            => array( 1,    'REVISIONYEAR' ),
 +      'revisiontimestamp'       => array( 1,    'REVISIONTIMESTAMP' ),
 +      'revisionuser'            => array( 1,    'REVISIONUSER' ),
 +      'plural'                  => array( 0,    'PLURAL:' ),
 +      'fullurl'                 => array( 0,    'FULLURL:' ),
 +      'fullurle'                => array( 0,    'FULLURLE:' ),
 +      'canonicalurl'            => array( 0,    'CANONICALURL:' ),
 +      'canonicalurle'           => array( 0,    'CANONICALURLE:' ),
 +      'lcfirst'                 => array( 0,    'LCFIRST:' ),
 +      'ucfirst'                 => array( 0,    'UCFIRST:' ),
 +      'lc'                      => array( 0,    'LC:' ),
 +      'uc'                      => array( 0,    'UC:' ),
 +      'raw'                     => array( 0,    'RAW:' ),
 +      'displaytitle'            => array( 1,    'DISPLAYTITLE' ),
 +      'rawsuffix'               => array( 1,    'R' ),
 +      'newsectionlink'          => array( 1,    '__NEWSECTIONLINK__' ),
 +      'nonewsectionlink'        => array( 1,    '__NONEWSECTIONLINK__' ),
 +      'currentversion'          => array( 1,    'CURRENTVERSION' ),
 +      'urlencode'               => array( 0,    'URLENCODE:' ),
 +      'anchorencode'            => array( 0,    'ANCHORENCODE' ),
 +      'currenttimestamp'        => array( 1,    'CURRENTTIMESTAMP' ),
 +      'localtimestamp'          => array( 1,    'LOCALTIMESTAMP' ),
 +      'directionmark'           => array( 1,    'DIRECTIONMARK', 'DIRMARK' ),
 +      'language'                => array( 0,    '#LANGUAGE:' ),
 +      'contentlanguage'         => array( 1,    'CONTENTLANGUAGE', 'CONTENTLANG' ),
 +      'pagesinnamespace'        => array( 1,    'PAGESINNAMESPACE:', 'PAGESINNS:' ),
 +      'numberofadmins'          => array( 1,    'NUMBEROFADMINS' ),
 +      'formatnum'               => array( 0,    'FORMATNUM' ),
 +      'padleft'                 => array( 0,    'PADLEFT' ),
 +      'padright'                => array( 0,    'PADRIGHT' ),
 +      'special'                 => array( 0,    'special' ),
 +      'speciale'                => array( 0,    'speciale' ),
 +      'defaultsort'             => array( 1,    'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ),
 +      'filepath'                => array( 0,    'FILEPATH:' ),
 +      'tag'                     => array( 0,    'tag' ),
 +      'hiddencat'               => array( 1,    '__HIDDENCAT__' ),
 +      'pagesincategory'         => array( 1,    'PAGESINCATEGORY', 'PAGESINCAT' ),
 +      'pagesize'                => array( 1,    'PAGESIZE' ),
 +      'index'                   => array( 1,    '__INDEX__' ),
 +      'noindex'                 => array( 1,    '__NOINDEX__' ),
 +      'numberingroup'           => array( 1,    'NUMBERINGROUP', 'NUMINGROUP' ),
 +      'staticredirect'          => array( 1,    '__STATICREDIRECT__' ),
 +      'protectionlevel'         => array( 1,    'PROTECTIONLEVEL' ),
 +      'formatdate'              => array( 0,    'formatdate', 'dateformat' ),
 +      'url_path'                => array( 0,    'PATH' ),
 +      'url_wiki'                => array( 0,    'WIKI' ),
 +      'url_query'               => array( 0,    'QUERY' ),
 +      'defaultsort_noerror'     => array( 0,    'noerror' ),
 +      'defaultsort_noreplace'   => array( 0,    'noreplace' ),
 +      'pagesincategory_all'     => array( 0,    'all' ),
 +      'pagesincategory_pages'   => array( 0,    'pages' ),
 +      'pagesincategory_subcats' => array( 0,    'subcats' ),
 +      'pagesincategory_files'   => array( 0,    'files' ),
  );
  
  /**
@@@ -641,7 -636,7 +641,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)',
  'tog-editsectiononrightclick' => 'Enable section editing by right clicking on section titles (requires JavaScript)',
  'tog-showtoc'                 => 'Show table of contents (for pages with more than 3 headings)',
  'tog-rememberpassword'        => 'Remember my login on this browser (for a maximum of $1 {{PLURAL:$1|day|days}})',
 -'tog-watchcreations'          => 'Add pages I create to my watchlist',
 -'tog-watchdefault'            => 'Add pages I edit to my watchlist',
 -'tog-watchmoves'              => 'Add pages I move to my watchlist',
 -'tog-watchdeletion'           => 'Add pages I delete to my watchlist',
 +'tog-watchcreations'          => 'Add pages I create and files I upload to my watchlist',
 +'tog-watchdefault'            => 'Add pages and files I edit to my watchlist',
 +'tog-watchmoves'              => 'Add pages and files I move to my watchlist',
 +'tog-watchdeletion'           => 'Add pages and files I delete to my watchlist',
  'tog-minordefault'            => 'Mark all edits minor by default',
  'tog-previewontop'            => 'Show preview before edit box',
  'tog-previewonfirst'          => 'Show preview on first edit',
  'tog-nocache'                 => 'Disable browser page caching',
 -'tog-enotifwatchlistpages'    => 'E-mail me when a page on my watchlist is changed',
 +'tog-enotifwatchlistpages'    => 'E-mail me when a page or file on my watchlist is changed',
  'tog-enotifusertalkpages'     => 'E-mail me when my user talk page is changed',
 -'tog-enotifminoredits'        => 'E-mail me also for minor edits of pages',
 +'tog-enotifminoredits'        => 'E-mail me also for minor edits of pages and files',
  'tog-enotifrevealaddr'        => 'Reveal my e-mail address in notification e-mails',
  'tog-shownumberswatching'     => 'Show the number of watching users',
  'tog-oldsig'                  => 'Existing signature:',
  'index-category'                 => 'Indexed pages',
  'noindex-category'               => 'Noindexed pages',
  'broken-file-category'           => 'Pages with broken file links',
 -'categoryviewer-pagedlinks'      => '($1) ($2)',
 +'categoryviewer-pagedlinks'      => '($1) ($2)', # only translate this message to other languages if you have to change it
  
  'linkprefix' => '/^(.*?)([a-zA-Z\\x80-\\xff]+)$/sD', # only translate this message to other languages if you have to change it
  
@@@ -968,90 -963,86 +968,90 @@@ This might also indicate a bug in the s
  A list of valid special pages can be found at [[Special:SpecialPages|{{int:specialpages}}]].',
  
  # General errors
 -'error'                => 'Error',
 -'databaseerror'        => 'Database error',
 -'dberrortext'          => 'A database query syntax error has occurred.
 +'error'                         => 'Error',
 +'databaseerror'                 => 'Database error',
 +'dberrortext'                   => 'A database query syntax error has occurred.
  This may indicate a bug in the software.
  The last attempted database query was:
  <blockquote><tt>$1</tt></blockquote>
  from within function "<tt>$2</tt>".
  Database returned error "<tt>$3: $4</tt>".',
 -'dberrortextcl'        => 'A database query syntax error has occurred.
 +'dberrortextcl'                 => 'A database query syntax error has occurred.
  The last attempted database query was:
  "$1"
  from within function "$2".
  Database returned error "$3: $4"',
 -'laggedslavemode'      => "'''Warning:''' Page may not contain recent updates.",
 -'readonly'             => 'Database locked',
 -'enterlockreason'      => 'Enter a reason for the lock, including an estimate of when the lock will be released',
 -'readonlytext'         => 'The database is currently locked to new entries and other modifications, probably for routine database maintenance, after which it will be back to normal.
 +'laggedslavemode'               => "'''Warning:''' Page may not contain recent updates.",
 +'readonly'                      => 'Database locked',
 +'enterlockreason'               => 'Enter a reason for the lock, including an estimate of when the lock will be released',
 +'readonlytext'                  => 'The database is currently locked to new entries and other modifications, probably for routine database maintenance, after which it will be back to normal.
  
  The administrator who locked it offered this explanation: $1',
 -'missing-article'      => 'The database did not find the text of a page that it should have found, named "$1" $2.
 +'missing-article'               => 'The database did not find the text of a page that it should have found, named "$1" $2.
  
  This is usually caused by following an outdated diff or history link to a page that has been deleted.
  
  If this is not the case, you may have found a bug in the software.
  Please report this to an [[Special:ListUsers/sysop|administrator]], making note of the URL.',
 -'missingarticle-rev'   => '(revision#: $1)',
 -'missingarticle-diff'  => '(Diff: $1, $2)',
 -'readonly_lag'         => 'The database has been automatically locked while the slave database servers catch up to the master',
 -'internalerror'        => 'Internal error',
 -'internalerror_info'   => 'Internal error: $1',
 -'fileappenderrorread'  => 'Could not read "$1" during append.',
 -'fileappenderror'      => 'Could not append "$1" to "$2".',
 -'filecopyerror'        => 'Could not copy file "$1" to "$2".',
 -'filerenameerror'      => 'Could not rename file "$1" to "$2".',
 -'filedeleteerror'      => 'Could not delete file "$1".',
 -'directorycreateerror' => 'Could not create directory "$1".',
 -'filenotfound'         => 'Could not find file "$1".',
 -'fileexistserror'      => 'Unable to write to file "$1": File exists.',
 -'unexpected'           => 'Unexpected value: "$1"="$2".',
 -'formerror'            => 'Error: Could not submit form.',
 -'badarticleerror'      => 'This action cannot be performed on this page.',
 -'cannotdelete'         => 'The page or file "$1" could not be deleted.
 +'missingarticle-rev'            => '(revision#: $1)',
 +'missingarticle-diff'           => '(Diff: $1, $2)',
 +'readonly_lag'                  => 'The database has been automatically locked while the slave database servers catch up to the master',
 +'internalerror'                 => 'Internal error',
 +'internalerror_info'            => 'Internal error: $1',
 +'fileappenderrorread'           => 'Could not read "$1" during append.',
 +'fileappenderror'               => 'Could not append "$1" to "$2".',
 +'filecopyerror'                 => 'Could not copy file "$1" to "$2".',
 +'filerenameerror'               => 'Could not rename file "$1" to "$2".',
 +'filedeleteerror'               => 'Could not delete file "$1".',
 +'directorycreateerror'          => 'Could not create directory "$1".',
 +'filenotfound'                  => 'Could not find file "$1".',
 +'fileexistserror'               => 'Unable to write to file "$1": File exists.',
 +'unexpected'                    => 'Unexpected value: "$1"="$2".',
 +'formerror'                     => 'Error: Could not submit form.',
 +'badarticleerror'               => 'This action cannot be performed on this page.',
 +'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"',
 -'badtitle'             => 'Bad title',
 -'badtitletext'         => 'The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title.
 +'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.',
 -'perfcached'           => 'The following data is cached and may not be up to date. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.',
 -'perfcachedts'         => 'The following data is cached, and was last updated $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.',
 -'querypage-no-updates' => 'Updates for this page are currently disabled.
 +'perfcached'                    => 'The following data is cached and may not be up to date. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.',
 +'perfcachedts'                  => 'The following data is cached, and was last updated $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.',
 +'querypage-no-updates'          => 'Updates for this page are currently disabled.
  Data here will not presently be refreshed.',
 -'wrong_wfQuery_params' => 'Incorrect parameters to wfQuery()<br />
 +'wrong_wfQuery_params'          => 'Incorrect parameters to wfQuery()<br />
  Function: $1<br />
  Query: $2',
 -'viewsource'           => 'View source',
 -'viewsource-title'     => 'View source for $1',
 -'actionthrottled'      => 'Action throttled',
 -'actionthrottledtext'  => 'As an anti-spam measure, you are limited from performing this action too many times in a short space of time, and you have exceeded this limit.
 +'viewsource'                    => 'View source',
 +'viewsource-title'              => 'View source for $1',
 +'actionthrottled'               => 'Action throttled',
 +'actionthrottledtext'           => 'As an anti-spam measure, you are limited from performing this action too many times in a short space of time, and you have exceeded this limit.
  Please try again in a few minutes.',
 -'protectedpagetext'    => 'This page has been protected to prevent editing.',
 -'viewsourcetext'       => 'You can view and copy the source of this page:',
 -'viewyourtext'         => "You can view and copy the source of '''your edits''' to this page:",
 -'protectedinterface'   => 'This page provides interface text for the software, and is protected to prevent abuse.',
 -'editinginterface'     => "'''Warning:''' You are editing a page which is used to provide interface text for the software.
 +'protectedpagetext'             => 'This page has been protected to prevent editing.',
 +'viewsourcetext'                => 'You can view and copy the source of this page:',
 +'viewyourtext'                  => "You can view and copy the source of '''your edits''' to this page:",
 +'protectedinterface'            => 'This page provides interface text for the software, and is protected to prevent abuse.',
 +'editinginterface'              => "'''Warning:''' You are editing a page which is used to provide interface text for the software.
  Changes to this page will affect the appearance of the user interface for other users.
  For translations, please consider using [//translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net], the MediaWiki localisation project.",
 -'sqlhidden'            => '(SQL query hidden)',
 -'cascadeprotected'     => 'This page has been protected from editing, because it is included in the following {{PLURAL:$1|page, which is|pages, which are}} protected with the "cascading" option turned on:
 +'sqlhidden'                     => '(SQL query hidden)',
 +'cascadeprotected'              => 'This page has been protected from editing, because it is included in the following {{PLURAL:$1|page, which is|pages, which are}} protected with the "cascading" option turned on:
  $2',
 -'namespaceprotected'   => "You do not have permission to edit pages in the '''$1''' namespace.",
 -'customcssprotected'   => "You do not have permission to edit this CSS page, because it contains another user's personal settings.",
 -'customjsprotected'    => "You do not have permission to edit this JavaScript page, because it contains another user's personal settings.",
 -'ns-specialprotected'  => 'Special pages cannot be edited.',
 -'titleprotected'       => 'This title has been protected from creation by [[User:$1|$1]].
 +'namespaceprotected'            => "You do not have permission to edit pages in the '''$1''' namespace.",
 +'customcssprotected'            => "You do not have permission to edit this CSS page, because it contains another user's personal settings.",
 +'customjsprotected'             => "You do not have permission to edit this JavaScript page, because it contains another user's personal settings.",
 +'ns-specialprotected'           => 'Special pages cannot be edited.',
 +'titleprotected'                => 'This title has been protected from creation by [[User:$1|$1]].
  The reason given is "\'\'$2\'\'".',
 -'filereadonlyerror'    => 'Unable to modify the file "$1" because the file repository "$2" is in read-only mode.
 +'filereadonlyerror'             => 'Unable to modify the file "$1" because the file repository "$2" is in read-only mode.
  
  The administrator who locked it offered this explanation: "$3".',
  'invalidtitle-knownnamespace'   => 'Invalid title with namespace "$2" and text "$3"',
  'invalidtitle-unknownnamespace' => 'Invalid title with unknown namespace number $1 and text "$2"',
 +'exception-nologin'             => 'Not logged in',
 +'exception-nologin-text'        => 'This page or action requires you to be logged in on this wiki.',
  
  # Virus scanner
  'virus-badscanner'     => "Bad configuration: Unknown virus scanner: ''$1''",
@@@ -1386,7 -1377,7 +1386,7 @@@ Custom .css and .js pages use a lowerca
  'note'                             => "'''Note:'''",
  'previewnote'                      => "'''Remember that this is only a preview.'''
  Your changes have not yet been saved!",
 -'continue-editing'                 => "Continue editing",
 +'continue-editing'                 => 'Continue editing',
  'previewconflict'                  => 'This preview reflects the text in the upper text editing area as it will appear if you choose to save.',
  'session_fail_preview'             => "'''Sorry! We could not process your edit due to a loss of session data.'''
  Please try again.
@@@ -1672,7 -1663,7 +1672,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',
 +'mergehistory-revisionrow'         => '$1 ($2) $3 . . $4 $5 $6', # only translate this message to other languages if you have to change it
  
  # Merge log
  'mergelog'           => 'Merge log',
@@@ -1989,7 -1980,6 +1989,7 @@@ Your e-mail address is not revealed whe
  'right-writeapi'              => 'Use of the write API',
  'right-delete'                => 'Delete pages',
  'right-bigdelete'             => 'Delete pages with large histories',
 +'right-deletelogentry'        => 'Delete and undelete specific log entries',
  'right-deleterevision'        => 'Delete and undelete specific revisions of pages',
  'right-deletedhistory'        => 'View deleted history entries, without their associated text',
  'right-deletedtext'           => 'View deleted text and changes between deleted revisions',
@@@ -2300,15 -2290,14 +2300,15 @@@ If the problem persists, contact an [[S
  'backend-fail-read'          => 'Could not read file $1.',
  '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".',
  'backend-fail-internal'      => 'An unknown error occurred in storage backend "$1".',
  'backend-fail-contenttype'   => 'Could not determine the content type of the file to store at "$1".',
  'backend-fail-batchsize'     => 'Storage backend given a batch of $1 file {{PLURAL:$1|operation|operations}}; the limit is $2 {{PLURAL:$2|operation|operations}}.',
 +'backend-fail-usable'        => 'Could not write file $1 due to insufficient permissions or missing directories/containers.',
  
 +# File journal errors
  'filejournal-fail-dbconnect' => 'Could not connect to the journal database for storage backend "$1".',
  'filejournal-fail-dbquery'   => 'Could not update the journal database for storage backend "$1".',
  
@@@ -2702,8 -2691,8 +2702,8 @@@ It may contain one or more characters w
  
  # SpecialCachedPage
  'cachedspecial-viewing-cached-ttl' => 'You are viewing a cached version of this page, which can be up to $1 old.',
 -'cachedspecial-viewing-cached-ts' => 'You are viewing a cached version of this page, which might not be completely actual.',
 -'cachedspecial-refresh-now' => 'View latest.',
 +'cachedspecial-viewing-cached-ts'  => 'You are viewing a cached version of this page, which might not be completely actual.',
 +'cachedspecial-refresh-now'        => 'View latest.',
  
  # Special:Categories
  'categories'                    => 'Categories',
@@@ -3068,7 -3057,7 +3068,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",
 +'undelete-revisionrow'         => '$1 $2 ($3) $4 . . $5 $6 $7', # only translate this message to other languages if you have to change it
  
  # Namespace form on various pages
  'namespace'                     => 'Namespace:',
@@@ -3206,8 -3195,8 +3206,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.',
@@@ -3232,7 -3221,7 +3232,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',
@@@ -4538,6 -4527,7 +4538,7 @@@ Try normal preview.'
  To remove a title, check the box next to it, and click "{{int:Watchlistedit-normal-submit}}".
  You can also [[Special:EditWatchlist/raw|edit the raw list]].',
  'watchlistedit-normal-submit'  => 'Remove titles',
+ 'watchlistedit-normal-submitting'  => 'Removing titles...',
  'watchlistedit-normal-done'    => '{{PLURAL:$1|1 title was|$1 titles were}} removed from your watchlist:',
  'watchlistedit-raw-title'      => 'Edit raw watchlist',
  'watchlistedit-raw-legend'     => 'Edit raw watchlist',
@@@ -4624,44 -4614,44 +4625,44 @@@ You can also [[Special:EditWatchlist|us
  'duplicate-defaultsort' => '\'\'\'Warning:\'\'\' Default sort key "$2" overrides earlier default sort key "$1".',
  
  # Special:Version
 -'version'                       => 'Version',
 -'version-summary'               => '', # do not translate or duplicate this message to other languages
 -'version-extensions'            => 'Installed extensions',
 -'version-specialpages'          => 'Special pages',
 -'version-parserhooks'           => 'Parser hooks',
 -'version-variables'             => 'Variables',
 -'version-antispam'              => 'Spam prevention',
 -'version-skins'                 => 'Skins',
 -'version-api'                   => 'API', # only translate this message to other languages if you have to change it
 -'version-other'                 => 'Other',
 -'version-mediahandlers'         => 'Media handlers',
 -'version-hooks'                 => 'Hooks',
 -'version-extension-functions'   => 'Extension functions',
 -'version-parser-extensiontags'  => 'Parser extension tags',
 -'version-parser-function-hooks' => 'Parser function hooks',
 -'version-hook-name'             => 'Hook name',
 -'version-hook-subscribedby'     => 'Subscribed by',
 -'version-version'               => '(Version $1)',
 -'version-svn-revision'          => '(r$2)', # only translate this message to other languages if you have to change it
 -'version-license'               => 'License',
 -'version-poweredby-credits'     => "This wiki is powered by '''[//www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
 -'version-poweredby-others'      => 'others',
 -'version-license-info'          => 'MediaWiki 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.
 +'version'                               => 'Version',
 +'version-summary'                       => '', # do not translate or duplicate this message to other languages
 +'version-extensions'                    => 'Installed extensions',
 +'version-specialpages'                  => 'Special pages',
 +'version-parserhooks'                   => 'Parser hooks',
 +'version-variables'                     => 'Variables',
 +'version-antispam'                      => 'Spam prevention',
 +'version-skins'                         => 'Skins',
 +'version-api'                           => 'API', # only translate this message to other languages if you have to change it
 +'version-other'                         => 'Other',
 +'version-mediahandlers'                 => 'Media handlers',
 +'version-hooks'                         => 'Hooks',
 +'version-extension-functions'           => 'Extension functions',
 +'version-parser-extensiontags'          => 'Parser extension tags',
 +'version-parser-function-hooks'         => 'Parser function hooks',
 +'version-hook-name'                     => 'Hook name',
 +'version-hook-subscribedby'             => 'Subscribed by',
 +'version-version'                       => '(Version $1)',
 +'version-svn-revision'                  => '(r$2)', # only translate this message to other languages if you have to change it
 +'version-license'                       => 'License',
 +'version-poweredby-credits'             => "This wiki is powered by '''[//www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
 +'version-poweredby-others'              => '[{{SERVER}}{{SCRIPTPATH}}/CREDITS others]',
 +'version-license-info'                  => 'MediaWiki 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.
  
  MediaWiki 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 [{{SERVER}}{{SCRIPTPATH}}/COPYING 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 or [//www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].',
 -'version-software'              => 'Installed software',
 -'version-software-product'      => 'Product',
 -'version-software-version'      => 'Version',
 -'version-entrypoints'           => 'Entry point URLs',
 +'version-software'                      => 'Installed software',
 +'version-software-product'              => 'Product',
 +'version-software-version'              => 'Version',
 +'version-entrypoints'                   => 'Entry point URLs',
  'version-entrypoints-header-entrypoint' => 'Entry point',
 -'version-entrypoints-header-url' => 'URL',
 -'version-entrypoints-articlepath' => '[https://www.mediawiki.org/wiki/Manual:$wgArticlePath Article path]',
 -'version-entrypoints-scriptpath' => '[https://www.mediawiki.org/wiki/Manual:$wgScriptPath Script path]',
 -'version-entrypoints-index-php' => '[https://www.mediawiki.org/wiki/Manual:index.php index.php]',
 -'version-entrypoints-api-php'   => '[https://www.mediawiki.org/wiki/Manual:api.php api.php]',
 -'version-entrypoints-load-php'  => '[https://www.mediawiki.org/wiki/Manual:load.php load.php]',
 +'version-entrypoints-header-url'        => 'URL',
 +'version-entrypoints-articlepath'       => '[https://www.mediawiki.org/wiki/Manual:$wgArticlePath Article path]', # only translate this message to other languages if you have to change it
 +'version-entrypoints-scriptpath'        => '[https://www.mediawiki.org/wiki/Manual:$wgScriptPath Script path]', # only translate this message to other languages if you have to change it
 +'version-entrypoints-index-php'         => '[https://www.mediawiki.org/wiki/Manual:index.php index.php]', # do not translate or duplicate this message to other languages
 +'version-entrypoints-api-php'           => '[https://www.mediawiki.org/wiki/Manual:api.php api.php]', # do not translate or duplicate this message to other languages
 +'version-entrypoints-load-php'          => '[https://www.mediawiki.org/wiki/Manual:load.php load.php]', # do not translate or duplicate this message to other languages
  
  # Special:FilePath
  'filepath'         => 'File path',
@@@ -4849,8 -4839,6 +4850,8 @@@ Otherwise, you can use the easy form be
  'api-error-empty-file'                    => 'The file you submitted was empty.',
  'api-error-emptypage'                     => 'Creating new, empty pages is not allowed.',
  'api-error-fetchfileerror'                => 'Internal error: Something went wrong while fetching the file.',
 +'api-error-fileexists-forbidden'          => 'A file with name "$1" already exists, and cannot be overwritten.',
 +'api-error-fileexists-shared-forbidden'   => 'A file with name "$1" already exists in the shared file repository, and cannot be overwritten.',
  'api-error-file-too-large'                => 'The file you submitted was too large.',
  'api-error-filename-tooshort'             => 'The filename is too short.',
  'api-error-filetype-banned'               => 'This type of file is banned.',
@@@ -12,7 -12,6 +12,7 @@@
   * @author Ahonc
   * @author Aleator
   * @author AlexSm
 + * @author Amahoney
   * @author Amire80
   * @author AnakngAraw
   * @author Ans
@@@ -75,7 -74,6 +75,7 @@@
   * @author Mihai
   * @author Mormegil
   * @author Mpradeep
 + * @author Murma174
   * @author Najami
   * @author Nemo bis
   * @author Niels
@@@ -140,7 -138,7 +140,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}}
  
@@@ -170,7 -168,7 +170,7 @@@ Is only shown if {{msg-mw|tog-enotifuse
  'tog-fancysig' => 'In user preferences under the signature box.  {{Gender}}',
  'tog-externaleditor' => "[[Special:Preferences]], tab 'Edit'. Offers user to use an external editor by default. {{Gender}}",
  'tog-externaldiff' => "[[Special:Preferences]], tab 'Edit'. Offers user to use an external diff program by default. {{Gender}}",
 -'tog-showjumplinks' => 'Toggle option used in [[Special:Preferences]]. The "jump to" part should be the same with {{msg-mw|jumpto}} (or you can use <nowiki>{{int:jumpto}}</nowiki>). Thess links are shown in some of the older skins as "jump to: navigation, search" but they are hidden by default (you can enable them with this option). {{Gender}}',
 +'tog-showjumplinks' => 'Toggle option used in [[Special:Preferences]]. The "jump to" part should be the same with {{msg-mw|jumpto}} (or you can use <nowiki>{{int:jumpto}}</nowiki>). These links are shown in some of the older skins as "jump to: navigation, search" but they are hidden by default (you can enable them with this option). {{Gender}}',
  'tog-uselivepreview' => 'Toggle option used in [[Special:Preferences]]. Live preview is an experimental feature (unavailable by default) to use edit preview without loading the page again. {{Gender}}',
  'tog-forceeditsummary' => "Toggle option used in [[Special:Preferences]] to force an edit ''{{msg-mw|summary}}''. {{Gender}}",
  'tog-watchlisthideown' => "[[Special:Preferences]], tab 'Watchlist'. Offers user to hide own edits from watchlist. {{Gender}}",
@@@ -666,7 -664,6 +666,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',
@@@ -745,7 -740,6 +745,7 @@@ It is also used on the top of the page 
  'gotaccountlink' => 'Text of the link to the log in form. Before that link, the message [[MediaWiki:Gotaccount/{{SUBPAGENAME}}]] appears.
  
  {{Identical|Log in}}',
 +'userlogin-resetlink' => 'Used on the login page.',
  'createaccountmail' => 'Button text for creating a new account and sending the new password to the specified e-mail address directly, as used on [[Special:UserLogin/signup]] if creating accounts by e-mail is allowed.',
  'createaccountreason' => '{{Identical|Reason}}',
  'createaccounterror' => 'Parameters:
@@@ -838,10 -832,7 +838,10 @@@ Used on [[Special:ResetPass]]'
  {{Identical|Reset password}}',
  'passwordreset-text' => 'Text on [[Special:PasswordReset]]',
  'passwordreset-legend' => '{{Identical|Reset password}}',
 -'passwordreset-pretext' => 'Parameters:
 +'passwordreset-pretext' => 'These instructions are shown on the password reset dialogue, which can, in principle, take the user\'s email address as well as, or instead of, their username. This text displays above one or more fields, at least one of which needs to be completed, and the message does not know which routes are available, so it needs to refer to some vague noun rather than specifically "username". 
 +"One of the pieces of data" means "an info"/"a datum" (probably to be translatea with a singular noun in your language if available).
 +
 +Parameters:
  * $1 is the number of password reset routes. This is never 1, but always two or more. Thus, the first plural option is empty in English.',
  'passwordreset-username' => '{{Identical|Username}}',
  'passwordreset-domain' => 'A domain like used in Domain Name System (DNS) or more specifically like a domain component in the Lightweight Directory Access Protocol (LDAP)',
@@@ -1025,7 -1016,7 +1025,7 @@@ This text will be shown below upload fo
  'sectioneditnotsupported-title' => 'Page title of special page, which presumably appears when someone tries to edit a section, and section editing is disabled. Explanation of section editing on [http://meta.wikimedia.org/wiki/Help:Section_editing#Section_editing meta].',
  'sectioneditnotsupported-text' => 'I think this is the text of an error message, which presumably appears when someone tries to edit a section, and section editing is disabled. Explanation of section editing on [http://meta.wikimedia.org/wiki/Help:Section_editing#Section_editing meta].',
  'permissionserrorstext-withaction' => '* $1 is the number of reasons that were found why the action cannot be performed.
 -* $2 is one of the action-* messages (for example {{msg|action-edit}}).
 +* $2 is one of the action-* messages (for example {{msg|action-edit}}) or other such messages tagged with {{tl|doc-action}} in their documentation.
  
  Please report at [[Support]] if you are unable to properly translate this message. Also see [[bugzilla:14246]]',
  'recreate-moveddeleted-warn' => 'Warning shown when creating a page which has already been deleted. See for example [[Test]].',
@@@ -1059,16 -1050,11 +1059,16 @@@ When templates are expanded, there is 
  * <tt>$2</tt> is the value of the max depth limit',
  'parser-unstrip-loop-warning' => 'This error is shown when a parser extension tag such as &lt;pre> includes a reference to itself in its own output.
  The reference must be to the exact same invocation of the tag at the same location in the source, merely writing &lt;pre>&lt;pre>&lt;/pre>&lt;/pre> will not do it.
 -This is usually impossible and unlikely to happen by accident, so translation is not essential.',
 +This is usually impossible and unlikely to happen by accident, so translation is not essential.
 +"Unstrip" refers to the internal function of the parser, called \'unstrip\', which recursively puts the output of parser functions in the place of the parser function call and which would enter an infinite loop in the situation above. See also:
 +*{{msg-mw|Parser-unstrip-recursion-limit}}',
  'parser-unstrip-recursion-limit' => 'This message is shown when the recursion limit for nested parser extension tags is exceeded.
  This warning may be encountered due to input text like &lt;ref>&lt;ref>&lt;ref>...&lt;/ref>&lt;/ref>&lt;/ref>.
  
 -* <tt>$1</tt> is the depth limit',
 +* <tt>$1</tt> is the depth limit
 +
 +"Unstrip" refers to the internal function of the parser, called \'unstrip\', which recursively puts the output of parser functions in the place of the parser function call and which would enter an infinite loop in the situation above. See also:
 +*{{msg-mw|Parser-unstrip-loop-warning}}',
  
  # "Undo" feature
  'undo-success' => 'Text on special page to confirm edit revert. You arrive on this page by clicking on the "undo" link on a revision history special page.
@@@ -1133,12 -1119,9 +1133,12 @@@ Used in History and [[Special:Contribut
  * '''$4''' - time.",
  
  # Revision deletion
 +'rev-deleted-comment' => 'Apparently this can also be about the reason of a log action, not only an edit summary. See also:
 +*{{msg-mw|revdelete-hide-comment}}',
  '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}})',
@@@ -1667,15 -1650,6 +1667,15 @@@ If someone with this right (bots by def
  'right-writeapi' => '{{doc-right|writeapi}}',
  'right-delete' => '{{doc-right|delete}}',
  'right-bigdelete' => '{{doc-right|bigdelete}}',
 +'right-deletelogentry' => '{{doc-right|deletelogentry}}
 +This user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.
 +It can be given to the group {{msg|group-sysop|pl=yes}}, although this right is disabled by default.
 +
 +See also
 +* {{msg|right-suppressionlog|pl=yes}}
 +* {{msg|right-hideuser|pl=yes}}
 +* {{msg|right-suppressrevision|pl=yes}}
 +* {{msg|right-deleterevision|pl=yes}}',
  'right-deleterevision' => '{{doc-right|deleterevision}}
  This user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.
  It can be given to the group {{msg|group-sysop|pl=yes}}, although this right is disabled by default.
  See also
  * {{msg|right-suppressionlog|pl=yes}}
  * {{msg|right-hideuser|pl=yes}}
 -* {{msg|right-suppressrevision|pl=yes}}',
 +* {{msg|right-suppressrevision|pl=yes}}
 +* {{msg|right-deletelogentry|pl=yes}}',
  'right-deletedhistory' => '{{doc-right|deletedhistory}}',
  'right-deletedtext' => '{{doc-right|deletedtext}}',
  'right-browsearchive' => '{{doc-right|browsearchive}}',
@@@ -1696,7 -1669,6 +1696,7 @@@ It can be given to the group {{msg|grou
  See also
  * {{msg|right-suppressionlog|pl=yes}}
  * {{msg|right-hideuser|pl=yes}}
 +* {{msg|right-deletelogentry|pl=yes}}
  * {{msg|right-deleterevision|pl=yes}}',
  'right-suppressionlog' => '{{doc-right|suppressionlog}}
  This user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.
@@@ -1705,7 -1677,6 +1705,7 @@@ It can be given to the group {{msg|grou
  See also
  * {{msg|right-suppressrevision|pl=yes}}
  * {{msg|right-hideuser|pl=yes}}
 +* {{msg|right-deletelogentry|pl=yes}}
  * {{msg|right-deleterevision|pl=yes}}',
  'right-block' => '{{doc-right|block}}',
  'right-blockemail' => '{{doc-right|blockemail}}',
@@@ -1716,7 -1687,6 +1716,7 @@@ It can be given to the group {{msg|grou
  See also
  * {{msg|right-suppressionlog|pl=yes}}
  * {{msg|right-suppressrevision|pl=yes}}
 +* {{msg|right-deletelogentry|pl=yes}}
  * {{msg|right-deleterevision|pl=yes}}',
  'right-ipblock-exempt' => '{{doc-right|ipblock-exempt}}
  This user automatically bypasses IP blocks, auto-blocks and range blocks - so I presume - but I am uncertain',
@@@ -1832,10 -1802,10 +1832,10 @@@ Similar to {{msg-mw|wlnote}} which is u
   Example: "\'\'{{int:rcnote/en|50|7||24 January 2008|14:48}}\'\'"',
  'rcnotefrom' => 'This message is displayed at [[Special:RecentChanges]] when viewing recentchanges from some specific time. The corrosponding message is {{msg-mw|Rclistfrom}} (without split of date and time, [[bugzilla:19104|Bug 19104]]).
  
 -Parameter $1 is the maximum number of changes that are displayed.
 -Parameter $2 is a date and time.
 -Parameter $3 is a date.
 -Parameter $4 is a time.',
 +Parameter $1 is the maximum number of changes that are displayed.
 +* Parameter $2 is a date and time. (alternative to $3 and $4)
 +* Parameter $3 is a date. (alternative to $1)
 +* Parameter $4 is a time. (alternative to $1)',
  'rclistfrom' => 'Used on [[Special:RecentChanges]]. Parameter $1 is a link to the revision of a specific date and time. The date and the time are the link description (without split of date and time, [[bugzilla:19104|Bug 19104]]). The corrosponding message is {{msg-mw|Rcnotefrom}}.',
  'rcshowhideminor' => "Option text in [[Special:RecentChanges]]. Parameters:
  * $1 is the 'show/hide' command, with the text taken from either {{msg-mw|show}} or {{msg-mw|hide}}.",
@@@ -3389,12 -3359,7 +3389,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.
@@@ -4335,6 -4300,7 +4335,7 @@@ Bitrate (of a file, typically) in yotta
  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:EditWatchlist]] after pages are removed from the watchlist.',
+ 'watchlistedit-normal-submitting' => 'Text of submit button on [[Special:Watchlist/edit]] when submiting an AJAX request',
  'watchlistedit-raw-title' => 'Title of [[Special:Watchlist/raw|Special page]].
  
  {{Identical|Edit raw watchlist}}',
@@@ -4745,8 -4711,6 +4746,8 @@@ $4 is the gender of the target user.'
  'api-error-empty-file' => 'API error message that can be used for client side localisation of API errors.',
  'api-error-emptypage' => 'API error message that can be used for client side localisation of API errors.',
  'api-error-fetchfileerror' => 'API error message that can be used for client side localisation of API errors.',
 +'api-error-fileexists-forbidden' => 'API error message that can be used for client side localisation of API errors.',
 +'api-error-fileexists-shared-forbidden' => 'API error message that can be used for client side localisation of API errors.',
  'api-error-file-too-large' => 'API error message that can be used for client side localisation of API errors.',
  'api-error-filename-tooshort' => 'API error message that can be used for client side localisation of API errors.',
  'api-error-filetype-banned' => 'API error message that can be used for client side localisation of API errors.',
@@@ -387,7 -387,6 +387,7 @@@ $wgMessageStructure = array
                'badarticleerror',
                'cannotdelete',
                'cannotdelete-title',
 +              'delete-hook-aborted',
                'badtitle',
                'badtitletext',
                'perfcached',
                'filereadonlyerror',
                'invalidtitle-knownnamespace',
                'invalidtitle-unknownnamespace',
 +              'exception-nologin',
 +              'exception-nologin-text',
        ),
        'virus' => array(
                'virus-badscanner',
                'right-writeapi',
                'right-delete',
                'right-bigdelete',
 +              'right-deletelogentry',
                'right-deleterevision',
                'right-deletedhistory',
                'right-deletedtext',
                'lockmanager-fail-releaselock',
                'lockmanager-fail-db-bucket',
                'lockmanager-fail-db-release',
 +              'lockmanager-fail-svr-acquire',
                'lockmanager-fail-svr-release'
        ),
  
                'watchlistedit-normal-legend',
                'watchlistedit-normal-explain',
                'watchlistedit-normal-submit',
+               'watchlistedit-normal-submiting',
                'watchlistedit-normal-done',
                'watchlistedit-raw-title',
                'watchlistedit-raw-legend',
                'api-error-empty-file',
                'api-error-emptypage',
                'api-error-fetchfileerror',
 +              'api-error-fileexists-forbidden',
 +              'api-error-fileexists-shared-forbidden',
                'api-error-file-too-large',
                'api-error-filename-tooshort',
                'api-error-filetype-banned',
diff --combined resources/Resources.php
@@@ -106,10 -106,6 +106,10 @@@ return array
                'scripts' => 'resources/jquery/jquery.autoEllipsis.js',
                'dependencies' => 'jquery.highlightText',
        ),
 +      'jquery.badge' => array(
 +              'scripts' => 'resources/jquery/jquery.badge.js',
 +              'styles' => 'resources/jquery/jquery.badge.css',
 +      ),
        'jquery.byteLength' => array(
                'scripts' => 'resources/jquery/jquery.byteLength.js',
        ),
                        'fa' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-fa.js',
                        'fi' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-fi.js',
                        'fo' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-fo.js',
 -                      'fr-ch' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-fr-CH.js',
                        'fr' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-fr.js',
                        'gl' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-gl.js',
                        'he' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-he.js',
                        'jquery.textSelection',
                        'jquery.byteLimit',
                ),
 +              'position' => 'top',
        ),
        'mediawiki.action.history' => array(
                'scripts' => 'resources/mediawiki.action/mediawiki.action.history.js',
        'mediawiki.action.view.rightClickEdit' => array(
                'scripts' => 'resources/mediawiki.action/mediawiki.action.view.rightClickEdit.js',
        ),
 +      // Alias for backwards compatibility
 +      'mediawiki.action.watch.ajax' => array(
 +              'dependencies' => 'mediawiki.page.watch.ajax'
 +      ),
  
        /* MediaWiki Language */
  
                        'mk' => 'resources/mediawiki.language/languages/mk.js',
                        'mo' => 'resources/mediawiki.language/languages/mo.js',
                        'mt' => 'resources/mediawiki.language/languages/mt.js',
 -                      'nl' => 'resources/mediawiki.language/languages/nl.js',
                        'nso' => 'resources/mediawiki.language/languages/nso.js',
                        'os' => 'resources/mediawiki.language/languages/os.js',
                        'pl' => 'resources/mediawiki.language/languages/pl.js',
 -                      'pt' => 'resources/mediawiki.language/languages/pt.js',
 -                      'pt-br' => 'resources/mediawiki.language/languages/pt-br.js',
                        'ro' => 'resources/mediawiki.language/languages/ro.js',
                        'ru' => 'resources/mediawiki.language/languages/ru.js',
                        'se' => 'resources/mediawiki.language/languages/se.js',
                'styles' => 'resources/mediawiki.special/mediawiki.special.changeslist.css',
                'dependencies' => array( 'jquery.makeCollapsible' ),
        ),
+       'mediawiki.special.editWatchlist' => array(
+               'scripts' => 'resources/mediawiki.special/mediawiki.special.editWatchlist.js',
+               'dependencies' => array(
+                       'mediawiki.api',
+                       'user.tokens'
+               ),
+               'messages' => array( 'watchlistedit-normal-submit', 'watchlistedit-normal-submiting' )
+       ),
        'mediawiki.special.movePage' => array(
                'scripts' => 'resources/mediawiki.special/mediawiki.special.movePage.js',
                'dependencies' => 'jquery.byteLimit',