Merge "MagicWordFactory to replace MagicWord static members/methods"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 31 Jul 2018 05:34:30 +0000 (05:34 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 31 Jul 2018 05:34:30 +0000 (05:34 +0000)
52 files changed:
RELEASE-NOTES-1.32
docs/hooks.txt
includes/Storage/RevisionRecord.php
includes/api/ApiExpandTemplates.php
includes/api/ApiFeedContributions.php
includes/api/ApiPatrol.php
includes/api/ApiQueryAllDeletedRevisions.php
includes/api/ApiQueryAllRevisions.php
includes/api/ApiQueryContributors.php
includes/api/ApiQueryDeletedRevisions.php
includes/api/ApiQueryFilearchive.php
includes/api/ApiQueryRecentChanges.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQueryRevisionsBase.php
includes/api/ApiQueryUserContribs.php
includes/api/ApiQueryWatchlist.php
includes/api/ApiRevisionDelete.php
includes/api/ApiSetNotificationTimestamp.php
includes/api/ApiTag.php
includes/api/i18n/en.json
includes/api/i18n/qqq.json
includes/api/i18n/zh-hant.json
includes/deferred/LinksUpdate.php
includes/installer/i18n/fa.json
includes/installer/i18n/gl.json
includes/parser/LinkHolderArray.php
languages/i18n/ar.json
languages/i18n/be-tarask.json
languages/i18n/bg.json
languages/i18n/bqi.json
languages/i18n/ca.json
languages/i18n/ckb.json
languages/i18n/el.json
languages/i18n/eu.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/gl.json
languages/i18n/gu.json
languages/i18n/it.json
languages/i18n/ka.json
languages/i18n/ko.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/qqq.json
languages/i18n/sd.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/te.json
languages/i18n/ur.json
languages/i18n/zh-hans.json
tests/phpunit/includes/api/query/ApiQueryRevisionsTest.php

index c5e9a67..baa520c 100644 (file)
@@ -66,6 +66,8 @@ production.
   remove or otherwise alter the elements to be output in the page <head>.
 * (T28934) The 'HistoryPageToolLinks' hook allows extensions to append
   additional links to the subtitle of a history page.
+* The 'GetLinkColours' hook now receives an additional $title parameter,
+  the Title object of the page being parsed, on which the links will be shown.
 
 === External library changes in 1.32 ===
 * …
@@ -110,12 +112,32 @@ production.
 * 'missingparam' errors will now use the prefixed parameter name in the code
   and error text, e.g. "noxxfoo" and "The 'xxfoo' parameter must be set" rather
   than "nofoo" and "The 'foo' parameter must be set".
+* action=query&prop=revisions now takes a 'rvslots' parameter to indicate the
+  multi-content revision slots for which content should be returned. It also
+  has a new rvprop, 'roles', to indicate which roles have slots. A deprecation
+  warning will be issued if rvprop=content or rvprop=contentmodel are used
+  without rvslots.
+* The rvcontentformat parameter to action=query&prop=revisions has been
+  deprecated. Clients should be prepared to deal with the default format for
+  relevant models.
+* Use of the deprecated parameters rvexpandtemplates, rvgeneratexml, rvparse,
+  rvdiffto, rvdifftotext, rvdifftotextpst, rvcontentformat, or the deprecated
+  rvprop=parsetree is forbidden with the new 'rvslots' parameter.
+* action=query&prop=deletedrevisions, action=query&list=allrevisions, and
+  action=query&list=alldeletedrevisions are changed similarly to
+  &prop=revisions (see the three previous items).
 
 === Action API internal changes in 1.32 ===
 * Added 'ApiParseMakeOutputPage' hook.
 * Parameter names may no longer contain '{' or '}', as these are now used for
   templated parameters.
 * (T194950) Added 'ApiMaxLagInfo' hook.
+* Added 'ApiParseMakeOutputPage' hook.
+* The following methods now take a RevisionRecord rather than a Revision. No
+  external callers are known.
+  * ApiFeedContributions::feedItemAuthor()
+  * ApiFeedContributions::feedItemDesc()
+  * ApiQueryRevisionsBase::extractRevisionInfo()
 
 === Languages updated in 1.32 ===
 MediaWiki supports over 350 languages. Many localisations are updated regularly.
index 251bea6..219c51f 100644 (file)
@@ -1730,6 +1730,7 @@ $query: query options passed to Title::getInternalURL()
 $linkcolour_ids: array of prefixed DB keys of the pages linked to,
   indexed by page_id.
 &$colours: (output) array of CSS classes, indexed by prefixed DB keys
+$title: Title object of the page being parsed, on which the links will be shown
 
 'GetLocalURL': Modify local URLs as output into page links. Note that if you are
 working with internal urls (non-interwiki) then it may be preferable to work
index 7d1b477..17c56ea 100644 (file)
@@ -453,7 +453,7 @@ abstract class RevisionRecord {
         *
         * @return bool
         */
-       protected function audienceCan( $field, $audience, User $user = null ) {
+       public function audienceCan( $field, $audience, User $user = null ) {
                if ( $audience == self::FOR_PUBLIC && $this->isDeleted( $field ) ) {
                        return false;
                } elseif ( $audience == self::FOR_THIS_USER ) {
index fe49b25..562bcdf 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * API module that functions as a shortcut to the wikitext preprocessor. Expands
  * any templates in a provided string, and returns the result of this expansion
@@ -48,7 +50,7 @@ class ApiExpandTemplates extends ApiBase {
 
                if ( $params['prop'] === null ) {
                        $this->addDeprecation(
-                               'apiwarn-deprecation-expandtemplates-prop', 'action=expandtemplates&!prop'
+                               [ 'apiwarn-deprecation-missingparam', 'prop' ], 'action=expandtemplates&!prop'
                        );
                        $prop = [];
                } else {
@@ -63,12 +65,12 @@ class ApiExpandTemplates extends ApiBase {
                // Get title and revision ID for parser
                $revid = $params['revid'];
                if ( $revid !== null ) {
-                       $rev = Revision::newFromId( $revid );
+                       $rev = MediaWikiServices::getInstance()->getRevisionStore()->getRevisionById( $revid );
                        if ( !$rev ) {
                                $this->dieWithError( [ 'apierror-nosuchrevid', $revid ] );
                        }
                        $pTitleObj = $titleObj;
-                       $titleObj = $rev->getTitle();
+                       $titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
                        if ( $titleProvided ) {
                                if ( !$titleObj->equals( $pTitleObj ) ) {
                                        $this->addWarning( [ 'apierror-revwrongpage', $rev->getId(),
index 61a9035..92d504e 100644 (file)
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionAccessException;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\RevisionStore;
+
 /**
  * @ingroup API
  */
 class ApiFeedContributions extends ApiBase {
 
+       /** @var RevisionStore */
+       private $revisionStore;
+
        /**
         * This module uses a custom feed wrapper printer.
         *
@@ -35,6 +43,8 @@ class ApiFeedContributions extends ApiBase {
        }
 
        public function execute() {
+               $this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+
                $params = $this->extractRequestParams();
 
                $config = $this->getConfig();
@@ -130,7 +140,7 @@ class ApiFeedContributions extends ApiBase {
                if ( $title && $title->userCan( 'read', $this->getUser() ) ) {
                        $date = $row->rev_timestamp;
                        $comments = $title->getTalkPage()->getFullURL();
-                       $revision = Revision::newFromRow( $row );
+                       $revision = $this->revisionStore->newRevisionFromRow( $row );
 
                        return new FeedItem(
                                $title->getPrefixedText(),
@@ -146,21 +156,28 @@ class ApiFeedContributions extends ApiBase {
        }
 
        /**
-        * @param Revision $revision
+        * @since 1.32, takes a RevisionRecord instead of a Revision
+        * @param RevisionRecord $revision
         * @return string
         */
-       protected function feedItemAuthor( $revision ) {
-               return $revision->getUserText();
+       protected function feedItemAuthor( RevisionRecord $revision ) {
+               $user = $revision->getUser();
+               return $user ? $user->getName() : '';
        }
 
        /**
-        * @param Revision $revision
+        * @since 1.32, takes a RevisionRecord instead of a Revision
+        * @param RevisionRecord $revision
         * @return string
         */
-       protected function feedItemDesc( $revision ) {
+       protected function feedItemDesc( RevisionRecord $revision ) {
                if ( $revision ) {
                        $msg = wfMessage( 'colon-separator' )->inContentLanguage()->text();
-                       $content = $revision->getContent();
+                       try {
+                               $content = $revision->getContent( 'main' );
+                       } catch ( RevisionAccessException $e ) {
+                               $content = null;
+                       }
 
                        if ( $content instanceof TextContent ) {
                                // only textual content has a "source view".
@@ -173,8 +190,10 @@ class ApiFeedContributions extends ApiBase {
                                $html = '';
                        }
 
-                       return '<p>' . htmlspecialchars( $revision->getUserText() ) . $msg .
-                               htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
+                       $comment = $revision->getComment();
+
+                       return '<p>' . htmlspecialchars( $this->feedItemAuthor( $revision ) ) . $msg .
+                               htmlspecialchars( FeedItem::stripComment( $comment ? $comment->text : '' ) ) .
                                "</p>\n<hr />\n<div>" . $html . '</div>';
                }
 
index a20aca4..2b65f95 100644 (file)
@@ -22,6 +22,8 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Allows user to patrol pages
  * @ingroup API
@@ -41,11 +43,12 @@ class ApiPatrol extends ApiBase {
                                $this->dieWithError( [ 'apierror-nosuchrcid', $params['rcid'] ] );
                        }
                } else {
-                       $rev = Revision::newFromId( $params['revid'] );
+                       $store = MediaWikiServices::getInstance()->getRevisionStore();
+                       $rev = $store->getRevisionById( $params['revid'] );
                        if ( !$rev ) {
                                $this->dieWithError( [ 'apierror-nosuchrevid', $params['revid'] ] );
                        }
-                       $rc = $rev->getRecentChange();
+                       $rc = $store->getRecentChange( $rev );
                        if ( !$rc ) {
                                $this->dieWithError( [ 'apierror-notpatrollable', $params['revid'] ] );
                        }
index 87f99dd..50afc7d 100644 (file)
@@ -23,6 +23,9 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * Query module to enumerate all deleted revisions.
  *
@@ -45,6 +48,7 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
                $user = $this->getUser();
                $db = $this->getDB();
                $params = $this->extractRequestParams( false );
+               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
 
                $result = $this->getResult();
 
@@ -103,7 +107,7 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
 
                if ( $resultPageSet === null ) {
                        $this->parseParameters( $params );
-                       $arQuery = Revision::getArchiveQueryInfo();
+                       $arQuery = $revisionStore->getArchiveQueryInfo();
                        $this->addTables( $arQuery['tables'] );
                        $this->addJoinConds( $arQuery['joins'] );
                        $this->addFields( $arQuery['fields'] );
@@ -235,9 +239,9 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
                        // (shouldn't be able to get here without 'deletedhistory', but
                        // check it again just in case)
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
-                               $bitmask = Revision::DELETED_USER;
+                               $bitmask = RevisionRecord::DELETED_USER;
                        } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                               $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+                               $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
                        }
@@ -343,13 +347,13 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
                                        $generated[] = $row->ar_rev_id;
                                }
                        } else {
-                               $revision = Revision::newFromArchiveRow( $row );
+                               $revision = $revisionStore->newRevisionFromArchiveRow( $row );
                                $rev = $this->extractRevisionInfo( $revision, $row );
 
                                if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
                                        $index = $nextIndex++;
                                        $pageMap[$row->ar_namespace][$row->ar_title] = $index;
-                                       $title = $revision->getTitle();
+                                       $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
                                        $a = [
                                                'pageid' => $title->getArticleID(),
                                                'revisions' => [ $rev ],
index a0e71a5..833e2e4 100644 (file)
@@ -20,6 +20,9 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * Query module to enumerate all revisions.
  *
@@ -39,6 +42,7 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
        protected function run( ApiPageSet $resultPageSet = null ) {
                $db = $this->getDB();
                $params = $this->extractRequestParams( false );
+               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
 
                $result = $this->getResult();
 
@@ -63,7 +67,7 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
 
                if ( $resultPageSet === null ) {
                        $this->parseParameters( $params );
-                       $revQuery = Revision::getQueryInfo(
+                       $revQuery = $revisionStore->getQueryInfo(
                                $this->fetchContent ? [ 'page', 'text' ] : [ 'page' ]
                        );
                        $this->addTables( $revQuery['tables'] );
@@ -120,9 +124,9 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
                if ( $params['user'] !== null || $params['excludeuser'] !== null ) {
                        // Paranoia: avoid brute force searches (T19342)
                        if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) {
-                               $bitmask = Revision::DELETED_USER;
+                               $bitmask = RevisionRecord::DELETED_USER;
                        } elseif ( !$this->getUser()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                               $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+                               $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
                        }
@@ -185,13 +189,13 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
                                        $generated[] = $row->rev_id;
                                }
                        } else {
-                               $revision = Revision::newFromRow( $row );
+                               $revision = $revisionStore->newRevisionFromRow( $row );
                                $rev = $this->extractRevisionInfo( $revision, $row );
 
                                if ( !isset( $pageMap[$row->rev_page] ) ) {
                                        $index = $nextIndex++;
                                        $pageMap[$row->rev_page] = $index;
-                                       $title = $revision->getTitle();
+                                       $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
                                        $a = [
                                                'pageid' => $title->getArticleID(),
                                                'revisions' => [ $rev ],
index 6848fcb..e39afac 100644 (file)
@@ -23,6 +23,9 @@
  * @since 1.23
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * A query module to show contributors to a page
  *
@@ -75,7 +78,7 @@ class ApiQueryContributors extends ApiQueryBase {
                }
 
                $result = $this->getResult();
-               $revQuery = Revision::getQueryInfo();
+               $revQuery = MediaWikiServices::getInstance()->getRevisionStore()->getQueryInfo();
 
                // For MIGRATION_NEW, target indexes on the revision_actor_temp table.
                // Otherwise, revision is fine because it'll have to check all revision rows anyway.
@@ -94,7 +97,7 @@ class ApiQueryContributors extends ApiQueryBase {
                ] );
                $this->addWhereFld( $pageField, $pages );
                $this->addWhere( ActorMigration::newMigration()->isAnon( $revQuery['fields']['rev_user'] ) );
-               $this->addWhere( $db->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' );
+               $this->addWhere( $db->bitAnd( 'rev_deleted', RevisionRecord::DELETED_USER ) . ' = 0' );
                $this->addOption( 'GROUP BY', $pageField );
                $res = $this->select( __METHOD__ );
                foreach ( $res as $row ) {
@@ -126,7 +129,7 @@ class ApiQueryContributors extends ApiQueryBase {
                ] );
                $this->addWhereFld( $pageField, $pages );
                $this->addWhere( ActorMigration::newMigration()->isNotAnon( $revQuery['fields']['rev_user'] ) );
-               $this->addWhere( $db->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' );
+               $this->addWhere( $db->bitAnd( 'rev_deleted', RevisionRecord::DELETED_USER ) . ' = 0' );
                $this->addOption( 'GROUP BY', [ $pageField, $idField ] );
                $this->addOption( 'LIMIT', $params['limit'] + 1 );
 
index 1a1e8f7..c3af71b 100644 (file)
@@ -23,6 +23,9 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * Query module to enumerate deleted revisions for pages.
  *
@@ -55,12 +58,13 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
                $params = $this->extractRequestParams( false );
 
                $db = $this->getDB();
+               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
 
                $this->requireMaxOneParameter( $params, 'user', 'excludeuser' );
 
                if ( $resultPageSet === null ) {
                        $this->parseParameters( $params );
-                       $arQuery = Revision::getArchiveQueryInfo();
+                       $arQuery = $revisionStore->getArchiveQueryInfo();
                        $this->addTables( $arQuery['tables'] );
                        $this->addFields( $arQuery['fields'] );
                        $this->addJoinConds( $arQuery['joins'] );
@@ -132,9 +136,9 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
                        // (shouldn't be able to get here without 'deletedhistory', but
                        // check it again just in case)
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
-                               $bitmask = Revision::DELETED_USER;
+                               $bitmask = RevisionRecord::DELETED_USER;
                        } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                               $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+                               $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
                        }
@@ -234,7 +238,7 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
 
                                $fit = $this->addPageSubItem(
                                        $pageMap[$row->ar_namespace][$row->ar_title],
-                                       $this->extractRevisionInfo( Revision::newFromArchiveRow( $row ), $row ),
+                                       $this->extractRevisionInfo( $revisionStore->newRevisionFromArchiveRow( $row ), $row ),
                                        'rev'
                                );
                                if ( !$fit ) {
index ebffb15..a6a3251 100644 (file)
@@ -24,6 +24,8 @@
  * @file
  */
 
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * Query module to enumerate all deleted files.
  *
@@ -153,7 +155,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
                        self::addTitleInfo( $file, $title );
 
                        if ( $fld_description &&
-                               Revision::userCanBitfield( $row->fa_deleted, File::DELETED_COMMENT, $user )
+                               RevisionRecord::userCanBitfield( $row->fa_deleted, File::DELETED_COMMENT, $user )
                        ) {
                                $file['description'] = $commentStore->getComment( 'fa_description', $row )->text;
                                if ( isset( $prop['parseddescription'] ) ) {
@@ -162,7 +164,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
                                }
                        }
                        if ( $fld_user &&
-                               Revision::userCanBitfield( $row->fa_deleted, File::DELETED_USER, $user )
+                               RevisionRecord::userCanBitfield( $row->fa_deleted, File::DELETED_USER, $user )
                        ) {
                                $file['userid'] = (int)$row->fa_user;
                                $file['user'] = $row->fa_user_text;
index f870d45..a5be58b 100644 (file)
@@ -20,6 +20,8 @@
  * @file
  */
 
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * A query action to enumerate the recent changes that were done to the wiki.
  * Various filters are supported.
@@ -365,9 +367,9 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                // Paranoia: avoid brute force searches (T19342)
                if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) {
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
-                               $bitmask = Revision::DELETED_USER;
+                               $bitmask = RevisionRecord::DELETED_USER;
                        } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                               $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+                               $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
                        }
@@ -507,11 +509,11 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
 
                /* Add user data and 'anon' flag, if user is anonymous. */
                if ( $this->fld_user || $this->fld_userid ) {
-                       if ( $row->rc_deleted & Revision::DELETED_USER ) {
+                       if ( $row->rc_deleted & RevisionRecord::DELETED_USER ) {
                                $vals['userhidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( Revision::userCanBitfield( $row->rc_deleted, Revision::DELETED_USER, $user ) ) {
+                       if ( RevisionRecord::userCanBitfield( $row->rc_deleted, RevisionRecord::DELETED_USER, $user ) ) {
                                if ( $this->fld_user ) {
                                        $vals['user'] = $row->rc_user_text;
                                }
@@ -546,11 +548,13 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
 
                /* Add edit summary / log summary. */
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                       if ( $row->rc_deleted & Revision::DELETED_COMMENT ) {
+                       if ( $row->rc_deleted & RevisionRecord::DELETED_COMMENT ) {
                                $vals['commenthidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( Revision::userCanBitfield( $row->rc_deleted, Revision::DELETED_COMMENT, $user ) ) {
+                       if ( RevisionRecord::userCanBitfield(
+                               $row->rc_deleted, RevisionRecord::DELETED_COMMENT, $user
+                       ) ) {
                                $comment = $this->commentStore->getComment( 'rc_comment', $row )->text;
                                if ( $this->fld_comment ) {
                                        $vals['comment'] = $comment;
@@ -597,11 +601,13 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                }
 
                if ( $this->fld_sha1 && $row->rev_sha1 !== null ) {
-                       if ( $row->rev_deleted & Revision::DELETED_TEXT ) {
+                       if ( $row->rev_deleted & RevisionRecord::DELETED_TEXT ) {
                                $vals['sha1hidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( Revision::userCanBitfield( $row->rev_deleted, Revision::DELETED_TEXT, $user ) ) {
+                       if ( RevisionRecord::userCanBitfield(
+                               $row->rev_deleted, RevisionRecord::DELETED_TEXT, $user
+                       ) ) {
                                if ( $row->rev_sha1 !== '' ) {
                                        $vals['sha1'] = Wikimedia\base_convert( $row->rev_sha1, 36, 16, 40 );
                                } else {
@@ -623,7 +629,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                        }
                }
 
-               if ( $anyHidden && ( $row->rc_deleted & Revision::DELETED_RESTRICTED ) ) {
+               if ( $anyHidden && ( $row->rc_deleted & RevisionRecord::DELETED_RESTRICTED ) ) {
                        $vals['suppressed'] = true;
                }
 
index 5858bc7..5e7b864 100644 (file)
@@ -20,6 +20,9 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * A query action to enumerate revisions of a given page, or show top revisions
  * of multiple pages. Various pieces of information may be shown - flags,
@@ -81,6 +84,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
 
        protected function run( ApiPageSet $resultPageSet = null ) {
                $params = $this->extractRequestParams( false );
+               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
 
                // If any of those parameters are used, work in 'enumeration' mode.
                // Enum mode can only be used when exactly one page is provided.
@@ -139,7 +143,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                        if ( $this->fld_user ) {
                                $opts[] = 'user';
                        }
-                       $revQuery = Revision::getQueryInfo( $opts );
+                       $revQuery = $revisionStore->getQueryInfo( $opts );
                        $this->addTables( $revQuery['tables'] );
                        $this->addFields( $revQuery['fields'] );
                        $this->addJoinConds( $revQuery['joins'] );
@@ -301,9 +305,9 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                        if ( $params['user'] !== null || $params['excludeuser'] !== null ) {
                                // Paranoia: avoid brute force searches (T19342)
                                if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) {
-                                       $bitmask = Revision::DELETED_USER;
+                                       $bitmask = RevisionRecord::DELETED_USER;
                                } elseif ( !$this->getUser()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                                       $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+                                       $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
                                } else {
                                        $bitmask = 0;
                                }
@@ -382,14 +386,15 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                        if ( $resultPageSet !== null ) {
                                $generated[] = $row->rev_id;
                        } else {
-                               $revision = new Revision( $row );
+                               $revision = $revisionStore->newRevisionFromRow( $row );
                                $rev = $this->extractRevisionInfo( $revision, $row );
 
                                if ( $this->token !== null ) {
-                                       $title = $revision->getTitle();
+                                       $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
+                                       $revisionCompat = new Revision( $revision );
                                        $tokenFunctions = $this->getTokenFunctions();
                                        foreach ( $this->token as $t ) {
-                                               $val = call_user_func( $tokenFunctions[$t], $title->getArticleID(), $title, $revision );
+                                               $val = call_user_func( $tokenFunctions[$t], $title->getArticleID(), $title, $revisionCompat );
                                                if ( $val === false ) {
                                                        $this->addWarning( [ 'apiwarn-tokennotallowed', $t ] );
                                                } else {
index 87c6f9d..600c89e 100644 (file)
  * @file
  */
 
+use MediaWiki\Storage\RevisionAccessException;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\SlotRecord;
+use MediaWiki\MediaWikiServices;
+
 /**
  * A base class for functions common to producing a list of revisions.
  *
  */
 abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
 
+       /**
+        * @name Constants for internal use. Don't use externally.
+        * @{
+        */
+
+       // Bits to indicate the results of the revdel permission check on a revision,
+       // see self::checkRevDel()
+       const IS_DELETED = 1; // Whether the field is revision-deleted
+       const CANNOT_VIEW = 2; // Whether the user cannot view the field due to revdel
+
+       /**@}*/
+
        protected $limit, $diffto, $difftotext, $difftotextpst, $expandTemplates, $generateXML,
-               $section, $parseContent, $fetchContent, $contentFormat, $setParsedLimit = true;
+               $section, $parseContent, $fetchContent, $contentFormat, $setParsedLimit = true,
+               $slotRoles = null, $needSlots;
 
        protected $fld_ids = false, $fld_flags = false, $fld_timestamp = false,
-               $fld_size = false, $fld_sha1 = false, $fld_comment = false,
-               $fld_parsedcomment = false, $fld_user = false, $fld_userid = false,
-               $fld_content = false, $fld_tags = false, $fld_contentmodel = false, $fld_parsetree = false;
+               $fld_size = false, $fld_slotsize = false, $fld_sha1 = false, $fld_slotsha1 = false,
+               $fld_comment = false, $fld_parsedcomment = false, $fld_user = false, $fld_userid = false,
+               $fld_content = false, $fld_tags = false, $fld_contentmodel = false, $fld_roles = false,
+               $fld_parsetree = false;
 
        public function execute() {
                $this->run();
@@ -55,6 +74,55 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
         * @param array $params
         */
        protected function parseParameters( $params ) {
+               $prop = array_flip( $params['prop'] );
+
+               $this->fld_ids = isset( $prop['ids'] );
+               $this->fld_flags = isset( $prop['flags'] );
+               $this->fld_timestamp = isset( $prop['timestamp'] );
+               $this->fld_comment = isset( $prop['comment'] );
+               $this->fld_parsedcomment = isset( $prop['parsedcomment'] );
+               $this->fld_size = isset( $prop['size'] );
+               $this->fld_slotsize = isset( $prop['slotsize'] );
+               $this->fld_sha1 = isset( $prop['sha1'] );
+               $this->fld_slotsha1 = isset( $prop['slotsha1'] );
+               $this->fld_content = isset( $prop['content'] );
+               $this->fld_contentmodel = isset( $prop['contentmodel'] );
+               $this->fld_userid = isset( $prop['userid'] );
+               $this->fld_user = isset( $prop['user'] );
+               $this->fld_tags = isset( $prop['tags'] );
+               $this->fld_roles = isset( $prop['roles'] );
+               $this->fld_parsetree = isset( $prop['parsetree'] );
+
+               $this->slotRoles = $params['slots'];
+
+               if ( $this->slotRoles !== null ) {
+                       if ( $this->fld_parsetree ) {
+                               $this->dieWithError( [
+                                       'apierror-invalidparammix-cannotusewith',
+                                       $this->encodeParamName( 'prop=parsetree' ),
+                                       $this->encodeParamName( 'slots' ),
+                               ], 'invalidparammix' );
+                       }
+                       foreach ( [
+                               'expandtemplates', 'generatexml', 'parse', 'diffto', 'difftotext', 'difftotextpst',
+                               'contentformat'
+                       ] as $p ) {
+                               if ( $params[$p] !== null && $params[$p] !== false ) {
+                                       $this->dieWithError( [
+                                               'apierror-invalidparammix-cannotusewith',
+                                               $this->encodeParamName( $p ),
+                                               $this->encodeParamName( 'slots' ),
+                                       ], 'invalidparammix' );
+                               }
+                       }
+               }
+
+               if ( !empty( $params['contentformat'] ) ) {
+                       $this->contentFormat = $params['contentformat'];
+               }
+
+               $this->limit = $params['limit'];
+
                if ( !is_null( $params['difftotext'] ) ) {
                        $this->difftotext = $params['difftotext'];
                        $this->difftotextpst = $params['difftotextpst'];
@@ -72,11 +140,13 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        // DifferenceEngine returns a rather ambiguous empty
                        // string if that's not the case
                        if ( $params['diffto'] != 0 ) {
-                               $difftoRev = Revision::newFromId( $params['diffto'] );
+                               $difftoRev = MediaWikiServices::getInstance()->getRevisionStore()
+                                       ->getRevisionById( $params['diffto'] );
                                if ( !$difftoRev ) {
                                        $this->dieWithError( [ 'apierror-nosuchrevid', $params['diffto'] ] );
                                }
-                               if ( !$difftoRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
+                               $revDel = $this->checkRevDel( $difftoRev, RevisionRecord::DELETED_TEXT );
+                               if ( $revDel & self::CANNOT_VIEW ) {
                                        $this->addWarning( [ 'apiwarn-difftohidden', $difftoRev->getId() ] );
                                        $params['diffto'] = null;
                                }
@@ -84,39 +154,6 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        $this->diffto = $params['diffto'];
                }
 
-               $prop = array_flip( $params['prop'] );
-
-               $this->fld_ids = isset( $prop['ids'] );
-               $this->fld_flags = isset( $prop['flags'] );
-               $this->fld_timestamp = isset( $prop['timestamp'] );
-               $this->fld_comment = isset( $prop['comment'] );
-               $this->fld_parsedcomment = isset( $prop['parsedcomment'] );
-               $this->fld_size = isset( $prop['size'] );
-               $this->fld_sha1 = isset( $prop['sha1'] );
-               $this->fld_content = isset( $prop['content'] );
-               $this->fld_contentmodel = isset( $prop['contentmodel'] );
-               $this->fld_userid = isset( $prop['userid'] );
-               $this->fld_user = isset( $prop['user'] );
-               $this->fld_tags = isset( $prop['tags'] );
-               $this->fld_parsetree = isset( $prop['parsetree'] );
-
-               if ( $this->fld_parsetree ) {
-                       $encParam = $this->encodeParamName( 'prop' );
-                       $name = $this->getModuleName();
-                       $parent = $this->getParent();
-                       $parentParam = $parent->encodeParamName( $parent->getModuleManager()->getModuleGroup( $name ) );
-                       $this->addDeprecation(
-                               [ 'apiwarn-deprecation-parameter', "{$encParam}=parsetree" ],
-                               "action=query&{$parentParam}={$name}&{$encParam}=parsetree"
-                       );
-               }
-
-               if ( !empty( $params['contentformat'] ) ) {
-                       $this->contentFormat = $params['contentformat'];
-               }
-
-               $this->limit = $params['limit'];
-
                $this->fetchContent = $this->fld_content || !is_null( $this->diffto )
                        || !is_null( $this->difftotext ) || $this->fld_parsetree;
 
@@ -152,18 +189,46 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        $this->limit = 10;
                }
                $this->validateLimit( 'limit', $this->limit, 1, $userMax, $botMax );
+
+               $this->needSlots = $this->fetchContent || $this->fld_contentmodel ||
+                       $this->fld_slotsize || $this->fld_slotsha1;
+               if ( $this->needSlots && $this->slotRoles === null ) {
+                       $encParam = $this->encodeParamName( 'slots' );
+                       $name = $this->getModuleName();
+                       $parent = $this->getParent();
+                       $parentParam = $parent->encodeParamName( $parent->getModuleManager()->getModuleGroup( $name ) );
+                       $this->addDeprecation(
+                               [ 'apiwarn-deprecation-missingparam', $encParam ],
+                               "action=query&{$parentParam}={$name}&!{$encParam}"
+                       );
+               }
        }
 
        /**
-        * Extract information from the Revision
+        * Test revision deletion status
+        * @param RevisionRecord $revision Revision to check
+        * @param int $field One of the RevisionRecord::DELETED_* constants
+        * @return int Revision deletion status flags. Bitwise OR of
+        *  self::IS_DELETED and self::CANNOT_VIEW, as appropriate.
+        */
+       private function checkRevDel( RevisionRecord $revision, $field ) {
+               $ret = $revision->isDeleted( $field ) ? self::IS_DELETED : 0;
+               if ( $ret ) {
+                       $canSee = $revision->audienceCan( $field, RevisionRecord::FOR_THIS_USER, $this->getUser() );
+                       $ret = $ret | ( $canSee ? 0 : self::CANNOT_VIEW );
+               }
+               return $ret;
+       }
+
+       /**
+        * Extract information from the RevisionRecord
         *
-        * @param Revision $revision
+        * @since 1.32, takes a RevisionRecord instead of a Revision
+        * @param RevisionRecord $revision Revision
         * @param object $row Should have a field 'ts_tags' if $this->fld_tags is set
         * @return array
         */
-       protected function extractRevisionInfo( Revision $revision, $row ) {
-               $title = $revision->getTitle();
-               $user = $this->getUser();
+       protected function extractRevisionInfo( RevisionRecord $revision, $row ) {
                $vals = [];
                $anyHidden = false;
 
@@ -179,15 +244,17 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                }
 
                if ( $this->fld_user || $this->fld_userid ) {
-                       if ( $revision->isDeleted( Revision::DELETED_USER ) ) {
+                       $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_USER );
+                       if ( ( $revDel & self::IS_DELETED ) ) {
                                $vals['userhidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( $revision->userCan( Revision::DELETED_USER, $user ) ) {
+                       if ( !( $revDel & self::CANNOT_VIEW ) ) {
+                               $u = $revision->getUser( RevisionRecord::RAW );
                                if ( $this->fld_user ) {
-                                       $vals['user'] = $revision->getUserText( Revision::RAW );
+                                       $vals['user'] = $u->getName();
                                }
-                               $userid = $revision->getUser( Revision::RAW );
+                               $userid = $u->getId();
                                if ( !$userid ) {
                                        $vals['anon'] = true;
                                }
@@ -203,45 +270,115 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                }
 
                if ( $this->fld_size ) {
-                       if ( !is_null( $revision->getSize() ) ) {
+                       try {
                                $vals['size'] = intval( $revision->getSize() );
-                       } else {
+                       } catch ( RevisionAccessException $e ) {
+                               // Back compat: If there's no size, return 0.
+                               // @todo: Gergő says to mention T198099 as a "todo" here.
                                $vals['size'] = 0;
                        }
                }
 
                if ( $this->fld_sha1 ) {
-                       if ( $revision->isDeleted( Revision::DELETED_TEXT ) ) {
+                       $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_TEXT );
+                       if ( ( $revDel & self::IS_DELETED ) ) {
                                $vals['sha1hidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( $revision->userCan( Revision::DELETED_TEXT, $user ) ) {
-                               if ( $revision->getSha1() != '' ) {
+                       if ( !( $revDel & self::CANNOT_VIEW ) ) {
+                               try {
                                        $vals['sha1'] = Wikimedia\base_convert( $revision->getSha1(), 36, 16, 40 );
-                               } else {
+                               } catch ( RevisionAccessException $e ) {
+                                       // Back compat: If there's no sha1, return emtpy string.
+                                       // @todo: Gergő says to mention T198099 as a "todo" here.
                                        $vals['sha1'] = '';
                                }
                        }
                }
 
-               if ( $this->fld_contentmodel ) {
-                       $vals['contentmodel'] = $revision->getContentModel();
+               if ( $this->fld_roles ) {
+                       $vals['roles'] = $revision->getSlotRoles();
+               }
+
+               if ( $this->needSlots ) {
+                       $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_TEXT );
+                       if ( ( $this->fld_slotsha1 || $this->fetchContent ) && ( $revDel & self::IS_DELETED ) ) {
+                               $anyHidden = true;
+                       }
+                       if ( $this->slotRoles === null ) {
+                               try {
+                                       $slot = $revision->getSlot( 'main', RevisionRecord::RAW );
+                               } catch ( RevisionAccessException $e ) {
+                                       // Back compat: If there's no slot, there's no content, so set 'textmissing'
+                                       // @todo: Gergő says to mention T198099 as a "todo" here.
+                                       $vals['textmissing'] = true;
+                                       $slot = null;
+                               }
+
+                               if ( $slot ) {
+                                       $content = null;
+                                       $vals += $this->extractSlotInfo( $slot, $revDel, $content );
+                                       if ( !empty( $vals['nosuchsection'] ) ) {
+                                               $this->dieWithError(
+                                                       [
+                                                               'apierror-nosuchsection-what',
+                                                               wfEscapeWikiText( $this->section ),
+                                                               $this->msg( 'revid', $revision->getId() )
+                                                       ],
+                                                       'nosuchsection'
+                                               );
+                                       }
+                                       if ( $content ) {
+                                               $vals += $this->extractDeprecatedContent( $content, $revision );
+                                       }
+                               }
+                       } else {
+                               $roles = array_intersect( $this->slotRoles, $revision->getSlotRoles() );
+                               $vals['slots'] = [
+                                       ApiResult::META_KVP_MERGE => true,
+                               ];
+                               foreach ( $roles as $role ) {
+                                       try {
+                                               $slot = $revision->getSlot( $role, RevisionRecord::RAW );
+                                       } catch ( RevisionAccessException $e ) {
+                                               // Don't error out here so the client can still process other slots/revisions.
+                                               // @todo: Gergő says to mention T198099 as a "todo" here.
+                                               $vals['slots'][$role]['missing'] = true;
+                                               continue;
+                                       }
+                                       $content = null;
+                                       $vals['slots'][$role] = $this->extractSlotInfo( $slot, $revDel, $content );
+                                       // @todo Move this into extractSlotInfo() (and remove its $content parameter)
+                                       // when extractDeprecatedContent() is no more.
+                                       if ( $content ) {
+                                               $vals['slots'][$role]['contentmodel'] = $content->getModel();
+                                               $vals['slots'][$role]['contentformat'] = $content->getDefaultFormat();
+                                               ApiResult::setContentValue( $vals['slots'][$role], 'content', $content->serialize() );
+                                       }
+                               }
+                               ApiResult::setArrayType( $vals['slots'], 'kvp', 'role' );
+                               ApiResult::setIndexedTagName( $vals['slots'], 'slot' );
+                       }
                }
 
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                       if ( $revision->isDeleted( Revision::DELETED_COMMENT ) ) {
+                       $revDel = $this->checkRevDel( $revision, RevisionRecord::DELETED_COMMENT );
+                       if ( ( $revDel & self::IS_DELETED ) ) {
                                $vals['commenthidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( $revision->userCan( Revision::DELETED_COMMENT, $user ) ) {
-                               $comment = $revision->getComment( Revision::RAW );
+                       if ( !( $revDel & self::CANNOT_VIEW ) ) {
+                               $comment = $revision->getComment( RevisionRecord::RAW );
+                               $comment = $comment ? $comment->text : '';
 
                                if ( $this->fld_comment ) {
                                        $vals['comment'] = $comment;
                                }
 
                                if ( $this->fld_parsedcomment ) {
-                                       $vals['parsedcomment'] = Linker::formatComment( $comment, $title );
+                                       $vals['parsedcomment'] = Linker::formatComment(
+                                               $comment, Title::newFromLinkTarget( $revision->getPageAsLinkTarget() )
+                                       );
                                }
                        }
                }
@@ -256,69 +393,119 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        }
                }
 
-               $content = null;
-               global $wgParser;
-               if ( $this->fetchContent ) {
-                       $content = $revision->getContent( Revision::FOR_THIS_USER, $this->getUser() );
-                       // Expand templates after getting section content because
-                       // template-added sections don't count and Parser::preprocess()
-                       // will have less input
-                       if ( $content && $this->section !== false ) {
-                               $content = $content->getSection( $this->section, false );
-                               if ( !$content ) {
-                                       $this->dieWithError(
-                                               [
-                                                       'apierror-nosuchsection-what',
-                                                       wfEscapeWikiText( $this->section ),
-                                                       $this->msg( 'revid', $revision->getId() )
-                                               ],
-                                               'nosuchsection'
-                                       );
+               if ( $anyHidden && $revision->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
+                       $vals['suppressed'] = true;
+               }
+
+               return $vals;
+       }
+
+       /**
+        * Extract information from the SlotRecord
+        *
+        * @param SlotRecord $slot
+        * @param int $revDel Revdel status flags, from self::checkRevDel()
+        * @param Content|null &$content Set to the slot's content, if available
+        *  and $this->fetchContent is true
+        * @return array
+        */
+       private function extractSlotInfo( SlotRecord $slot, $revDel, &$content = null ) {
+               $vals = [];
+               ApiResult::setArrayType( $vals, 'assoc' );
+
+               if ( $this->fld_slotsize ) {
+                       $vals['size'] = intval( $slot->getSize() );
+               }
+
+               if ( $this->fld_slotsha1 ) {
+                       if ( ( $revDel & self::IS_DELETED ) ) {
+                               $vals['sha1hidden'] = true;
+                       }
+                       if ( !( $revDel & self::CANNOT_VIEW ) ) {
+                               if ( $slot->getSha1() != '' ) {
+                                       $vals['sha1'] = Wikimedia\base_convert( $slot->getSha1(), 36, 16, 40 );
+                               } else {
+                                       $vals['sha1'] = '';
                                }
                        }
-                       if ( $revision->isDeleted( Revision::DELETED_TEXT ) ) {
+               }
+
+               if ( $this->fld_contentmodel ) {
+                       $vals['contentmodel'] = $slot->getModel();
+               }
+
+               $content = null;
+               if ( $this->fetchContent ) {
+                       if ( ( $revDel & self::IS_DELETED ) ) {
                                $vals['texthidden'] = true;
-                               $anyHidden = true;
-                       } elseif ( !$content ) {
-                               $vals['textmissing'] = true;
+                       }
+                       if ( !( $revDel & self::CANNOT_VIEW ) ) {
+                               try {
+                                       $content = $slot->getContent();
+                               } catch ( RevisionAccessException $e ) {
+                                       // @todo: Gergő says to mention T198099 as a "todo" here.
+                                       $vals['textmissing'] = true;
+                               }
+                               // Expand templates after getting section content because
+                               // template-added sections don't count and Parser::preprocess()
+                               // will have less input
+                               if ( $content && $this->section !== false ) {
+                                       $content = $content->getSection( $this->section, false );
+                                       if ( !$content ) {
+                                               $vals['nosuchsection'] = true;
+                                       }
+                               }
                        }
                }
+
+               return $vals;
+       }
+
+       /**
+        * Format a Content using deprecated options
+        * @param Content $content Content to format
+        * @param RevisionRecord $revision Revision being processed
+        * @return array
+        */
+       private function extractDeprecatedContent( Content $content, RevisionRecord $revision ) {
+               global $wgParser;
+
+               $vals = [];
+               $title = Title::newFromLinkTarget( $revision->getPageAsLinkTarget() );
+
                if ( $this->fld_parsetree || ( $this->fld_content && $this->generateXML ) ) {
-                       if ( $content ) {
-                               if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
-                                       $t = $content->getNativeData(); # note: don't set $text
+                       if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
+                               $t = $content->getNativeData(); # note: don't set $text
 
-                                       $wgParser->startExternalParse(
-                                               $title,
-                                               ParserOptions::newFromContext( $this->getContext() ),
-                                               Parser::OT_PREPROCESS
-                                       );
-                                       $dom = $wgParser->preprocessToDom( $t );
-                                       if ( is_callable( [ $dom, 'saveXML' ] ) ) {
-                                               $xml = $dom->saveXML();
-                                       } else {
-                                               $xml = $dom->__toString();
-                                       }
-                                       $vals['parsetree'] = $xml;
+                               $wgParser->startExternalParse(
+                                       $title,
+                                       ParserOptions::newFromContext( $this->getContext() ),
+                                       Parser::OT_PREPROCESS
+                               );
+                               $dom = $wgParser->preprocessToDom( $t );
+                               if ( is_callable( [ $dom, 'saveXML' ] ) ) {
+                                       $xml = $dom->saveXML();
                                } else {
-                                       $vals['badcontentformatforparsetree'] = true;
-                                       $this->addWarning(
-                                               [
-                                                       'apierror-parsetree-notwikitext-title',
-                                                       wfEscapeWikiText( $title->getPrefixedText() ),
-                                                       $content->getModel()
-                                               ],
-                                               'parsetree-notwikitext'
-                                       );
+                                       $xml = $dom->__toString();
                                }
+                               $vals['parsetree'] = $xml;
+                       } else {
+                               $vals['badcontentformatforparsetree'] = true;
+                               $this->addWarning(
+                                       [
+                                               'apierror-parsetree-notwikitext-title',
+                                               wfEscapeWikiText( $title->getPrefixedText() ),
+                                               $content->getModel()
+                                       ],
+                                       'parsetree-notwikitext'
+                               );
                        }
                }
 
-               if ( $this->fld_content && $content ) {
+               if ( $this->fld_content ) {
                        $text = null;
 
                        if ( $this->expandTemplates && !$this->parseContent ) {
-                               # XXX: implement template expansion for all content types in ContentHandler?
                                if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
                                        $text = $content->getNativeData();
 
@@ -376,7 +563,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                $vals['diff'] = [];
                                $context = new DerivativeContext( $this->getContext() );
                                $context->setTitle( $title );
-                               $handler = $revision->getContentHandler();
+                               $handler = $content->getContentHandler();
 
                                if ( !is_null( $this->difftotext ) ) {
                                        $model = $title->getContentModel();
@@ -398,7 +585,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
 
                                                if ( $this->difftotextpst ) {
                                                        $popts = ParserOptions::newFromContext( $this->getContext() );
-                                                       $difftocontent = $difftocontent->preSaveTransform( $title, $user, $popts );
+                                                       $difftocontent = $difftocontent->preSaveTransform( $title, $this->getUser(), $popts );
                                                }
 
                                                $engine = $handler->createDifferenceEngine( $context );
@@ -421,10 +608,6 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        }
                }
 
-               if ( $anyHidden && $revision->isDeleted( Revision::DELETED_RESTRICTED ) ) {
-                       $vals['suppressed'] = true;
-               }
-
                return $vals;
        }
 
@@ -437,6 +620,12 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
        }
 
        public function getAllowedParams() {
+               $slotRoles = MediaWikiServices::getInstance()->getSlotRoleStore()->getMap();
+               if ( !in_array( 'main', $slotRoles, true ) ) {
+                       $slotRoles[] = 'main';
+               }
+               sort( $slotRoles, SORT_STRING );
+
                return [
                        'prop' => [
                                ApiBase::PARAM_ISMULTI => true,
@@ -448,12 +637,15 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                        'user',
                                        'userid',
                                        'size',
+                                       'slotsize',
                                        'sha1',
+                                       'slotsha1',
                                        'contentmodel',
                                        'comment',
                                        'parsedcomment',
                                        'content',
                                        'tags',
+                                       'roles',
                                        'parsetree',
                                ],
                                ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-prop',
@@ -464,15 +656,27 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                        'user' => 'apihelp-query+revisions+base-paramvalue-prop-user',
                                        'userid' => 'apihelp-query+revisions+base-paramvalue-prop-userid',
                                        'size' => 'apihelp-query+revisions+base-paramvalue-prop-size',
+                                       'slotsize' => 'apihelp-query+revisions+base-paramvalue-prop-slotsize',
                                        'sha1' => 'apihelp-query+revisions+base-paramvalue-prop-sha1',
+                                       'slotsha1' => 'apihelp-query+revisions+base-paramvalue-prop-slotsha1',
                                        'contentmodel' => 'apihelp-query+revisions+base-paramvalue-prop-contentmodel',
                                        'comment' => 'apihelp-query+revisions+base-paramvalue-prop-comment',
                                        'parsedcomment' => 'apihelp-query+revisions+base-paramvalue-prop-parsedcomment',
                                        'content' => 'apihelp-query+revisions+base-paramvalue-prop-content',
                                        'tags' => 'apihelp-query+revisions+base-paramvalue-prop-tags',
+                                       'roles' => 'apihelp-query+revisions+base-paramvalue-prop-roles',
                                        'parsetree' => [ 'apihelp-query+revisions+base-paramvalue-prop-parsetree',
                                                CONTENT_MODEL_WIKITEXT ],
                                ],
+                               ApiBase::PARAM_DEPRECATED_VALUES => [
+                                       'parsetree' => true,
+                               ],
+                       ],
+                       'slots' => [
+                               ApiBase::PARAM_TYPE => $slotRoles,
+                               ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-slots',
+                               ApiBase::PARAM_ISMULTI => true,
+                               ApiBase::PARAM_ALL => true,
                        ],
                        'limit' => [
                                ApiBase::PARAM_TYPE => 'limit',
@@ -515,6 +719,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        'contentformat' => [
                                ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
                                ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-contentformat',
+                               ApiBase::PARAM_DEPRECATED => true,
                        ],
                ];
        }
index fdcaa76..3aa6183 100644 (file)
@@ -20,6 +20,9 @@
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * This query action adds a list of a specified user's contributions to the output.
  *
@@ -399,7 +402,8 @@ class ApiQueryUserContribs extends ApiQueryBase {
                                                $revIds[] = $data[0]->rev_parent_id;
                                        }
                                }
-                               $this->parentLens = Revision::getParentLengths( $dbSecondary, $revIds );
+                               $this->parentLens = MediaWikiServices::getInstance()->getRevisionStore()
+                                       ->listRevisionSizes( $dbSecondary, $revIds );
                        }
 
                        foreach ( $merged as $data ) {
@@ -438,7 +442,7 @@ class ApiQueryUserContribs extends ApiQueryBase {
                $this->resetQueryParams();
                $db = $this->getDB();
 
-               $revQuery = Revision::getQueryInfo( [ 'page' ] );
+               $revQuery = MediaWikiServices::getInstance()->getRevisionStore()->getQueryInfo( [ 'page' ] );
                $this->addTables( $revQuery['tables'] );
                $this->addJoinConds( $revQuery['joins'] );
                $this->addFields( $revQuery['fields'] );
@@ -500,9 +504,9 @@ class ApiQueryUserContribs extends ApiQueryBase {
                // see the username.
                $user = $this->getUser();
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
-                       $bitmask = Revision::DELETED_USER;
+                       $bitmask = RevisionRecord::DELETED_USER;
                } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                       $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
+                       $bitmask = RevisionRecord::DELETED_USER | RevisionRecord::DELETED_RESTRICTED;
                } else {
                        $bitmask = 0;
                }
@@ -619,7 +623,7 @@ class ApiQueryUserContribs extends ApiQueryBase {
                $vals = [];
                $anyHidden = false;
 
-               if ( $row->rev_deleted & Revision::DELETED_TEXT ) {
+               if ( $row->rev_deleted & RevisionRecord::DELETED_TEXT ) {
                        $vals['texthidden'] = true;
                        $anyHidden = true;
                }
@@ -627,7 +631,7 @@ class ApiQueryUserContribs extends ApiQueryBase {
                // Any rows where we can't view the user were filtered out in the query.
                $vals['userid'] = (int)$row->rev_user;
                $vals['user'] = $row->rev_user_text;
-               if ( $row->rev_deleted & Revision::DELETED_USER ) {
+               if ( $row->rev_deleted & RevisionRecord::DELETED_USER ) {
                        $vals['userhidden'] = true;
                        $anyHidden = true;
                }
@@ -658,14 +662,14 @@ class ApiQueryUserContribs extends ApiQueryBase {
                }
 
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                       if ( $row->rev_deleted & Revision::DELETED_COMMENT ) {
+                       if ( $row->rev_deleted & RevisionRecord::DELETED_COMMENT ) {
                                $vals['commenthidden'] = true;
                                $anyHidden = true;
                        }
 
-                       $userCanView = Revision::userCanBitfield(
+                       $userCanView = RevisionRecord::userCanBitfield(
                                $row->rev_deleted,
-                               Revision::DELETED_COMMENT, $this->getUser()
+                               RevisionRecord::DELETED_COMMENT, $this->getUser()
                        );
 
                        if ( $userCanView ) {
@@ -707,7 +711,7 @@ class ApiQueryUserContribs extends ApiQueryBase {
                        }
                }
 
-               if ( $anyHidden && $row->rev_deleted & Revision::DELETED_RESTRICTED ) {
+               if ( $anyHidden && ( $row->rev_deleted & RevisionRecord::DELETED_RESTRICTED ) ) {
                        $vals['suppressed'] = true;
                }
 
index bb09838..5dd247a 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionRecord;
 
 /**
  * This query action allows clients to retrieve a list of recently modified pages
@@ -302,13 +303,13 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
 
                /* Add user data and 'anon' flag, if user is anonymous. */
                if ( $this->fld_user || $this->fld_userid ) {
-                       if ( $recentChangeInfo['rc_deleted'] & Revision::DELETED_USER ) {
+                       if ( $recentChangeInfo['rc_deleted'] & RevisionRecord::DELETED_USER ) {
                                $vals['userhidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( Revision::userCanBitfield(
+                       if ( RevisionRecord::userCanBitfield(
                                $recentChangeInfo['rc_deleted'],
-                               Revision::DELETED_USER,
+                               RevisionRecord::DELETED_USER,
                                $user
                        ) ) {
                                if ( $this->fld_userid ) {
@@ -353,13 +354,13 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
 
                /* Add edit summary / log summary. */
                if ( $this->fld_comment || $this->fld_parsedcomment ) {
-                       if ( $recentChangeInfo['rc_deleted'] & Revision::DELETED_COMMENT ) {
+                       if ( $recentChangeInfo['rc_deleted'] & RevisionRecord::DELETED_COMMENT ) {
                                $vals['commenthidden'] = true;
                                $anyHidden = true;
                        }
-                       if ( Revision::userCanBitfield(
+                       if ( RevisionRecord::userCanBitfield(
                                $recentChangeInfo['rc_deleted'],
-                               Revision::DELETED_COMMENT,
+                               RevisionRecord::DELETED_COMMENT,
                                $user
                        ) ) {
                                $comment = $this->commentStore->getComment( 'rc_comment', $recentChangeInfo )->text;
@@ -407,7 +408,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                        }
                }
 
-               if ( $anyHidden && ( $recentChangeInfo['rc_deleted'] & Revision::DELETED_RESTRICTED ) ) {
+               if ( $anyHidden && ( $recentChangeInfo['rc_deleted'] & RevisionRecord::DELETED_RESTRICTED ) ) {
                        $vals['suppressed'] = true;
                }
 
index 9a793e2..6121c3d 100644 (file)
@@ -21,6 +21,8 @@
  * @since 1.23
  */
 
+use MediaWiki\Storage\RevisionRecord;
+
 /**
  * API interface to RevDel. The API equivalent of Special:RevisionDelete.
  * Requires API write mode to be enabled.
@@ -61,8 +63,8 @@ class ApiRevisionDelete extends ApiBase {
                }
                $bits = [
                        'content' => RevisionDeleter::getRevdelConstant( $params['type'] ),
-                       'comment' => Revision::DELETED_COMMENT,
-                       'user' => Revision::DELETED_USER,
+                       'comment' => RevisionRecord::DELETED_COMMENT,
+                       'user' => RevisionRecord::DELETED_USER,
                ];
                $bitfield = [];
                foreach ( $bits as $key => $bit ) {
@@ -77,11 +79,11 @@ class ApiRevisionDelete extends ApiBase {
 
                if ( $params['suppress'] === 'yes' ) {
                        $this->checkUserRightsAny( 'suppressrevision' );
-                       $bitfield[Revision::DELETED_RESTRICTED] = 1;
+                       $bitfield[RevisionRecord::DELETED_RESTRICTED] = 1;
                } elseif ( $params['suppress'] === 'no' ) {
-                       $bitfield[Revision::DELETED_RESTRICTED] = 0;
+                       $bitfield[RevisionRecord::DELETED_RESTRICTED] = 0;
                } else {
-                       $bitfield[Revision::DELETED_RESTRICTED] = -1;
+                       $bitfield[RevisionRecord::DELETED_RESTRICTED] = -1;
                }
 
                $targetObj = null;
index f7dc4a7..b81c5bf 100644 (file)
@@ -22,6 +22,7 @@
  *
  * @file
  */
+
 use MediaWiki\MediaWikiServices;
 
 /**
@@ -73,10 +74,11 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
                                $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'torevid' ) ] );
                        }
-                       $title = reset( $pageSet->getGoodTitles() );
+                       $titles = $pageSet->getGoodTitles();
+                       $title = reset( $titles );
                        if ( $title ) {
-                               $timestamp = Revision::getTimestampFromId(
-                                       $title, $params['torevid'], Revision::READ_LATEST );
+                               $timestamp = MediaWikiServices::getInstance()->getRevisionStore()
+                                       ->getTimestampFromId( $title, $params['torevid'], IDBAccessObject::READ_LATEST );
                                if ( $timestamp ) {
                                        $timestamp = $dbw->timestamp( $timestamp );
                                } else {
@@ -87,12 +89,14 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
                                $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'newerthanrevid' ) ] );
                        }
-                       $title = reset( $pageSet->getGoodTitles() );
+                       $titles = $pageSet->getGoodTitles();
+                       $title = reset( $titles );
                        if ( $title ) {
-                               $revid = $title->getNextRevisionID(
-                                       $params['newerthanrevid'], Title::GAID_FOR_UPDATE );
+                               $revid = $title->getNextRevisionID( $params['newerthanrevid'], Title::GAID_FOR_UPDATE );
                                if ( $revid ) {
-                                       $timestamp = $dbw->timestamp( Revision::getTimestampFromId( $title, $revid ) );
+                                       $timestamp = $dbw->timestamp(
+                                               MediaWikiServices::getInstance()->getRevisionStore()->getTimestampFromId( $title, $revid )
+                                       );
                                } else {
                                        $timestamp = null;
                                }
index c9f6db3..e0c7a28 100644 (file)
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionStore;
+
 /**
  * @ingroup API
  * @since 1.25
  */
 class ApiTag extends ApiBase {
 
+       /** @var RevisionStore */
+       private $revisionStore;
+
        public function execute() {
+               $this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+
                $params = $this->extractRequestParams();
                $user = $this->getUser();
 
@@ -84,7 +92,7 @@ class ApiTag extends ApiBase {
                                $valid = RecentChange::newFromId( $id );
                                break;
                        case 'revid':
-                               $valid = Revision::newFromId( $id );
+                               $valid = $this->revisionStore->getRevisionById( $id );
                                break;
                        case 'logid':
                                $valid = self::validateLogId( $id );
index d7cdc6c..44b4dfd 100644 (file)
        "apihelp-query+revisions+base-paramvalue-prop-user": "User that made the revision.",
        "apihelp-query+revisions+base-paramvalue-prop-userid": "User ID of the revision creator.",
        "apihelp-query+revisions+base-paramvalue-prop-size": "Length (bytes) of the revision.",
+       "apihelp-query+revisions+base-paramvalue-prop-slotsize": "Length (bytes) of each revision slot.",
        "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) of the revision.",
-       "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "Content model ID of the revision.",
+       "apihelp-query+revisions+base-paramvalue-prop-slotsha1": "SHA-1 (base 16) of each revision slot.",
+       "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "Content model ID of each revision slot.",
        "apihelp-query+revisions+base-paramvalue-prop-comment": "Comment by the user for the revision.",
        "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "Parsed comment by the user for the revision.",
-       "apihelp-query+revisions+base-paramvalue-prop-content": "Text of the revision.",
+       "apihelp-query+revisions+base-paramvalue-prop-content": "Content of each revision slot.",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "Tags for the revision.",
-       "apihelp-query+revisions+base-paramvalue-prop-parsetree": "<span class=\"apihelp-deprecated\">Deprecated.</span> Use <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> or <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd> instead. The XML parse tree of revision content (requires content model <code>$1</code>).",
+       "apihelp-query+revisions+base-paramvalue-prop-roles": "List content slot roles that exist in the revision.",
+       "apihelp-query+revisions+base-paramvalue-prop-parsetree": "Use <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> or <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd> instead. The XML parse tree of revision content (requires content model <code>$1</code>).",
+       "apihelp-query+revisions+base-param-slots": "Which revision slots to return data for, when slot-related properties are included in <var>$1props</var>. If omitted, data from the <kbd>main</kbd> slot will be returned in a backwards-compatible format.",
        "apihelp-query+revisions+base-param-limit": "Limit how many revisions will be returned.",
        "apihelp-query+revisions+base-param-expandtemplates": "Use <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> instead. Expand templates in revision content (requires $1prop=content).",
        "apihelp-query+revisions+base-param-generatexml": "Use <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> or <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd> instead. Generate XML parse tree for revision content (requires $1prop=content).",
        "apiwarn-checktoken-percentencoding": "Check that symbols such as \"+\" in the token are properly percent-encoded in the URL.",
        "apiwarn-compare-nocontentmodel": "No content model could be determined, assuming $1.",
        "apiwarn-deprecation-deletedrevs": "<kbd>list=deletedrevs</kbd> has been deprecated. Please use <kbd>prop=deletedrevisions</kbd> or <kbd>list=alldeletedrevisions</kbd> instead.",
-       "apiwarn-deprecation-expandtemplates-prop": "Because no values have been specified for the <var>prop</var> parameter, a legacy format has been used for the output. This format is deprecated, and in the future, a default value will be set for the <var>prop</var> parameter, causing the new format to always be used.",
        "apiwarn-deprecation-httpsexpected": "HTTP used when HTTPS was expected.",
        "apiwarn-deprecation-login-botpw": "Main-account login via <kbd>action=login</kbd> is deprecated and may stop working without warning. To continue login with <kbd>action=login</kbd>, see [[Special:BotPasswords]]. To safely continue using main-account login, see <kbd>action=clientlogin</kbd>.",
        "apiwarn-deprecation-login-nobotpw": "Main-account login via <kbd>action=login</kbd> is deprecated and may stop working without warning. To safely log in, see <kbd>action=clientlogin</kbd>.",
        "apiwarn-deprecation-login-token": "Fetching a token via <kbd>action=login</kbd> is deprecated. Use <kbd>action=query&meta=tokens&type=login</kbd> instead.",
+       "apiwarn-deprecation-missingparam": "Because <var>$1</var> was not specified, a legacy format has been used for the output. This format is deprecated, and in the future the new format will always be used.",
        "apiwarn-deprecation-parameter": "The parameter <var>$1</var> has been deprecated.",
        "apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> is deprecated since MediaWiki 1.28. Use <kbd>prop=headhtml</kbd> when creating new HTML documents, or <kbd>prop=modules|jsconfigvars</kbd> when updating a document client-side.",
        "apiwarn-deprecation-purge-get": "Use of <kbd>action=purge</kbd> via GET is deprecated. Use POST instead.",
index dd8e529..f158f27 100644 (file)
        "apihelp-query+revisions+base-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+revisions+base|prop|user}}",
        "apihelp-query+revisions+base-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+revisions+base|prop|userid}}",
        "apihelp-query+revisions+base-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+revisions+base|prop|size}}",
+       "apihelp-query+revisions+base-paramvalue-prop-slotsize": "{{doc-apihelp-paramvalue|query+revisions+base|prop|slotsize}}",
        "apihelp-query+revisions+base-paramvalue-prop-sha1": "{{doc-apihelp-paramvalue|query+revisions+base|prop|sha1}}",
+       "apihelp-query+revisions+base-paramvalue-prop-slotsha1": "{{doc-apihelp-paramvalue|query+revisions+base|prop|slotsha1}}",
        "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "{{doc-apihelp-paramvalue|query+revisions+base|prop|contentmodel}}",
        "apihelp-query+revisions+base-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+revisions+base|prop|comment}}",
        "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+revisions+base|prop|parsedcomment}}",
        "apihelp-query+revisions+base-paramvalue-prop-content": "{{doc-apihelp-paramvalue|query+revisions+base|prop|content}}",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "{{doc-apihelp-paramvalue|query+revisions+base|prop|tags}}",
+       "apihelp-query+revisions+base-paramvalue-prop-roles": "{{doc-apihelp-paramvalue|query+revisions+base|prop|roles}}",
        "apihelp-query+revisions+base-paramvalue-prop-parsetree": "{{doc-apihelp-paramvalue|query+revisions+base|prop|parsetree|params=* $1 - Value of the constant CONTENT_MODEL_WIKITEXT|paramstart=2}}",
+       "apihelp-query+revisions+base-param-slots": "{{doc-apihelp-param|query+revisions+base|slots|description=the \"slots\" parameter to revision querying modules|noseealso=1}}",
        "apihelp-query+revisions+base-param-limit": "{{doc-apihelp-param|query+revisions+base|limit|description=the \"limit\" parameter to revision querying modules|noseealso=1}}",
        "apihelp-query+revisions+base-param-expandtemplates": "{{doc-apihelp-param|query+revisions+base|expandtemplates|description=the \"expandtemplates\" parameter to revision querying modules|noseealso=1}}",
        "apihelp-query+revisions+base-param-generatexml": "{{doc-apihelp-param|query+revisions+base|generatexml|description=the \"generatexml\" parameter to revision querying modules|noseealso=1}}",
        "apiwarn-checktoken-percentencoding": "{{doc-apierror}}",
        "apiwarn-compare-nocontentmodel": "{{doc-apierror}}\n\nParameters:\n* $1 - Content model being assumed.",
        "apiwarn-deprecation-deletedrevs": "{{doc-apierror}}",
-       "apiwarn-deprecation-expandtemplates-prop": "{{doc-apierror}}",
        "apiwarn-deprecation-httpsexpected": "{{doc-apierror}}",
        "apiwarn-deprecation-login-botpw": "{{doc-apierror}}",
        "apiwarn-deprecation-login-nobotpw": "{{doc-apierror}}",
        "apiwarn-deprecation-login-token": "{{doc-apierror}}",
+       "apiwarn-deprecation-missingparam": "{{doc-apierror}}\n\nParameters:\n* $1 - Parameter name.",
        "apiwarn-deprecation-parameter": "{{doc-apierror}}\n\nParameters:\n* $1 - Parameter name.",
        "apiwarn-deprecation-parse-headitems": "{{doc-apierror}}",
        "apiwarn-deprecation-purge-get": "{{doc-apierror}}",
index 8e96b31..9f101b6 100644 (file)
@@ -18,7 +18,7 @@
                        "Sanmosa"
                ]
        },
-       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|說明文件]]\n* [[mw:Special:MyLanguage/API:FAQ|常見問題]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 郵遞清單]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 報告錯誤及請求功能]\n</div>\n<strong>狀態資訊:</strong>本頁所展示的所有功能都應正常運作,但API仍在開發,會隨時變化。請訂閱[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 郵遞清單]以便獲得更新通知。\n\n<strong>錯誤的請求:</strong>當API收到錯誤的請求,會發出以「MediaWiki-API-Error」為鍵的HTTP標頭欄位,隨後標頭欄位的值,以及傳回的錯誤碼會設為相同值。詳細資訊請參閱[[mw:Special:MyLanguage/API:Errors_and_warnings|API: 錯誤與警告]]。\n\n<strong>測試:</strong>要簡化API請求的測試過程,請見[[Special:ApiSandbox]]。",
+       "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|說明文件]]\n* [[mw:Special:MyLanguage/API:FAQ|常見問題]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 郵寄清單]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 報告錯誤及請求功能]\n</div>\n<strong>狀態資訊:</strong>本頁所展示的所有功能都應正常運作,但API仍在開發,會隨時變化。請訂閱[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 郵寄清單]以便獲得更新通知。\n\n<strong>錯誤的請求:</strong>當API收到錯誤的請求,會發出以「MediaWiki-API-Error」為鍵的HTTP標頭欄位,隨後標頭欄位的值,以及傳回的錯誤碼會設為相同值。詳細資訊請參閱[[mw:Special:MyLanguage/API:Errors_and_warnings|API: 錯誤與警告]]。\n\n<strong>測試:</strong>要簡化API請求的測試過程,請見[[Special:ApiSandbox]]。",
        "apihelp-main-param-action": "要執行的動作。",
        "apihelp-main-param-format": "輸出的格式。",
        "apihelp-main-param-smaxage": "將HTTP緩存控制頭欄位設為<code>s-maxage</code>秒。錯誤不會做緩存。",
index 39e8bd9..141888c 100644 (file)
@@ -141,14 +141,9 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                }
 
                foreach ( $this->mCategories as &$sortkey ) {
-                       # If the sortkey is longer then 255 bytes,
-                       # it truncated by DB, and then doesn't get
-                       # matched when comparing existing vs current
-                       # categories, causing T27254.
-                       # Also. substr behaves weird when given "".
-                       if ( $sortkey !== '' ) {
-                               $sortkey = substr( $sortkey, 0, 255 );
-                       }
+                       # If the sortkey is longer then 255 bytes, it is truncated by DB, and then doesn't match
+                       # when comparing existing vs current categories, causing T27254.
+                       $sortkey = mb_strcut( $sortkey, 0, 255 );
                }
 
                $this->mRecursive = $recursive;
index 31febc0..3102bfb 100644 (file)
        "config-sqlite-dir-help": "اس‌کیولایت همهٔ اطلاعات را در یک پوشهٔ جداگانه ذخیره می‌کند.\nفهرستی را که به وجود‌ آوردید باید در طی نصب به‌ وسیلهٔ وب‌سرور قابل نوشتن باشد.\n<strong>نباید</strong> از طریق وب در دسترس باشد، به همین دلیل ما آن را در جایی که پوشه‌های پی‌اچ‌پی شما هست، قرار نمی‌دهیم.\nنصب کننده یک پوشهٔ <code>.htaccess</code> همراه آن خواهدآورد،اما اگر این کار را انجام ندهد،کسی می‌تواند به پایگاه اطلاعاتی شما دسترسی پیدا کند.\nاطلاعات خام کاربر شامل (آدرس‌های ایمیل، علامت‌‌ها با شماره‌های رمز عبور) به خوبی پاک کردن تغییرات و دیگر اطلاعات محرمانه در ویکی.\nقرار دادن پایگاه اطلاعاتی باهم را در جایی دیگر در نظر بگیرید، برای مثال در <code>/var/lib/mediawiki/yourwiki</code>.",
        "config-oracle-def-ts": "جدول پیش فرض:",
        "config-oracle-temp-ts": "جدول موقت:",
-       "config-type-mysql": "مای‌اس‌کیو‌ال (یا سازگار)",
+       "config-type-mysql": "MariaDB، مای‌اس‌کیو‌ال (یا سازگار)",
        "config-type-mssql": "سرور مایکروسافت اس‌کیو‌ال",
        "config-support-info": "مدیاویکی سامانه‌های پایگاه اطلاعاتی زیر را حمایت می‌کند:\n$1\nاگر متوجه سامانه پایگاه اطلاعاتی که سعی دارید از فهرست زیر استفاده کنید، نمی‌شوید، بنابراین دستورالعمل‌های مرتبط در بالا را برای فعال کردن پشتیبانی دنبال کنید.",
-       "config-dbsupport-mysql": "*[{{int:version-db-mysql-url}} MySQL] مهم‌ترین هدف برای مدیاویکی است و بهترین پشتیبانی. مدیاویکی همچنین کار می‌کند با [{{int:version-db-mariadb-url}} MariaDB] و [{{int:version-db-percona-url}} Percona Server] که با MySQL سازگار هستند.([https://secure.php.net/manual/en/mysqli.installation.php چگونه php را با MySQL کامپایل کنیم])",
+       "config-dbsupport-mysql": "*[{{int:version-db-mariadb-url}} MariaDB] مهم‌ترین هدف برای مدیاویکی است و بهترین پشتیبانی. مدیاویکی همچنین کار می‌کند با [{{int:version-db-mysql-url}} MariaDB] و [{{int:version-db-percona-url}} Percona Server] که با MariaDB سازگار هستند.([https://secure.php.net/manual/en/mysqli.installation.php چگونه php را با MariaDB کامپایل کنیم])",
        "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} پستگرس‌کیوال] یک سامانه پایگاه اطلاعات متن‌باز پر‌طرفدار است که جایگزینی برای مای‌اس‌کیوال است. ([https://secure.php.net/manual/en/pgsql.installation.php راهنمای تنظیم کردن پی‌اچ‌پی به همراه پستگرس‌کیوال])",
-       "config-dbsupport-sqlite": "*[{{int:version-db-sqlite-url}} اس‌کیولایت] یک سامانه پایگاه اطلاعاتی کم حجمی است که بسیار خوب پشتیبانی شده‌است.\n([http://www.php.net/manual/en/pdo.installation.php چگونگی کامپایل پی‌اچ‌پی با اس‌کیولایت]، از PDO استفاده می‌کند)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] یک پایگاه اطلاعاتی کار تبلیغاتی است.\n([http://www.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
+       "config-dbsupport-sqlite": "*[{{int:version-db-sqlite-url}} اس‌کیولایت] یک سامانه پایگاه اطلاعاتی کم حجمی است که بسیار خوب پشتیبانی شده‌است.\n([https://secure.php.net/manual/en/pdo.installation.php چگونگی کامپایل پی‌اچ‌پی با اس‌کیولایت]، از PDO استفاده می‌کند)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] یک پایگاه اطلاعاتی کار تبلیغاتی است.\n([https://secure.php.net/manual/en/oci8.installation.php How to compile PHP with OCI8 support])",
        "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] یک پایگاه اطلاعاتی موسسهٔ تبلیغاتی برای وینذوز است. ([https://secure.php.net/manual/en/sqlsrv.installation.php How to compile PHP with SQLSRV support])",
-       "config-header-mysql": "تنظیمات مای‌اس‌کیو‌ال",
+       "config-header-mysql": "تنظیمات MariaDB/مای‌اس‌کیو‌ال",
        "config-header-postgres": "تنظیمات پست‌گر‌اس‌کیو‌ال",
        "config-header-sqlite": "تنظیمات اس‌کیو‌لایت",
        "config-header-oracle": "تنظیمات اوراکل",
        "config-db-web-create": "اگر در حال‌حاضر وجود ندارد،حساب ایجاد کنید",
        "config-db-web-no-create-privs": "حسابی که شما برای نصب تعیین کردید،مزایای کافی برای ایجاد یک حساب را ندارد.\nحسابی که شما اینجا تعیین کرده‌اید باید در حال حاضر وجود داشته باشد.",
        "config-mysql-engine": "موتور ذخیره سازی:",
-       "config-mysql-innodb": "اینودی‌بی",
+       "config-mysql-innodb": "اینودی‌بی (پیشنهاد می‌شود)",
        "config-mysql-myisam": "می‌ای‌سم",
        "config-mysql-myisam-dep": "'''هشدار:''' شما مای‌آی‌اس‌ای‌ام را به عنوان موتور ذخیره برای مای‌آی‌اس‌ای‌ام انتخاب کرده‌اید، که برای استفاده با مدیاویکی توصیه نمی‌شود زیرا:\n* به‌علت قفل شدن جدول اجمالاً به طور همزمان پشتیبانی می کند\n* بیشتر از دیگر موتورها برای از بین‌ رفتن مستعد است.\n* مبنای رمز مدیاویکی همیشه مای‌آی‌اس‌ای‌ام را همان طور که باید باشد،کنترل نمی‌کند\nاگر نصب مای‌اس‌کیو‌ال شما اینودی‌بی را پشتیبانی می‌کند،بسیار توصیه می‌شود  که در عوض ،آن را انتخاب کنید.\nاگر نصب مای‌اس‌کیو‌ال شما، اینودی‌بی را پشتیبانی نمی‌کند، ممکن است زمان ارتقاء رسیده باشد.",
        "config-mysql-only-myisam-dep": "'''هشدار:''' مای‌آی‌اس‌ای‌ام تنها موتور ذخیره‌سازی اطلاعات برای مای‌اس‌کیو‌ال در این دستگاه است، و برای استفاده با مدیاویکی توصیه نمی‌شود، زیرا:\n* به‌علت قفل شدن جدول اجمالاً به طور همزمان پشتیبانی می کند\n* بیشتر از دیگر موتورها برای از بین‌ رفتن مستعد است.\n* مبنای رمز مدیاویکی همیشه مای‌آی‌اس‌ای‌ام را همان طور که باید باشد،کنترل نمی‌کند\nنصب مای‌اس‌کیو‌ال شما اینودی‌بی را پشتیبانی نمی‌کند،ممکن است زمان یک ارتقاء رسیده باشد.",
        "config-license-help": "بسیاری از وبگاه‌ها ویرایش‌های ها را با  [https://freedomdefined.org/Definition اجازه‌نامهٔ آزاد] منتشر می‌کنند.\nاین کار به داشتن حس مالکیت جمعی کمک می‌کند و ویرایش‌های طولانی مدت را اشاعه می‌دهد.\nاین برای ویکی‌های خصوصی یا سازمانی الزامی نیست.\n\nاگر شما می‌خواهید از متون ویکی‌پدیا استفاده کنید، یا اینکه به ویکی‌پدیا اجازه دهید از متون شما استفاده کند باید متون خود را با <strong>{{int:config-license-cc-by-sa}}</strong> منتشر کنید.\n\nویکی‌پدیا در گذشته از اجازه‌نامهٔ داده‌های آزاد گنو استفاده می‌کرد.\nاین اجازه‌نامه مورد قبول است، ولی فهم آن آسان نیست.\nهمچنین استفادهٔ دوباره از متون تحت اجازه‌نامهٔ داده‌های آزاد گنو به سختی انجام می‌گیرد.",
        "config-email-settings": "تنظیمات ایمیل",
        "config-enable-email": "فعال‌سازی ایمیل خروجی",
-       "config-enable-email-help": "اگر می‌خواهید ارسال ایمیل کار کند، [Config-dbsupport-oracle/manual/en/mail.configuration.php PHP's mail settings] نیازمند پیکربندی صحیح است.\nاگر هیچ قابلیت ایمیلی نمی‌خواهید، می‌توانید آنها را اینجا غیر‌فعال کنید.",
+       "config-enable-email-help": "اگر می‌خواهید ارسال ایمیل کار کند، [https://secure.php.net/manual/en/mail.configuration.php PHP's mail settings] نیازمند پیکربندی صحیح است.\nاگر هیچ قابلیت ایمیلی نمی‌خواهید، می‌توانید آنها را اینجا غیر‌فعال کنید.",
        "config-email-user": "فعال کردن ایمیل کاربر به کاربر",
        "config-email-user-help": "به همهٔ کاربرانی که ارسال ایمیل را در ترجیحات خود فعال کرده‌اند، اجازه داده خواهد شد که به یکدیگر ایمیل ارسال کنند.",
        "config-email-usertalk": "فعال کردن اطلاع‌رسانی صفحهٔ بحث کاربر",
        "config-nofile": "پروندهٔ «$1» یافت نشد. آیا حذف شده‌است؟",
        "config-extension-link": "آیا می‌دانستید که ویکی شما [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions] را پشتیبانی می‌کند؟\nشما می‌توانید [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions by category]",
        "config-skins-screenshots": "$1 (تصاویر: $2)",
+       "config-extensions-requires": "$1 (نیازمند $2)",
        "config-screenshot": "تصویر",
        "mainpagetext": "'''مدیاویکی با موفقیت نصب شد.'''",
        "mainpagedocfooter": "از [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents راهنمای کاربری]\nبرای اطلاعات بیشتر در مورد به‌کارگیری نرم‌افزار ویکی استفاده کنید.\n\n== آغاز به کار ==\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings فهرست تنظیمات پیکربندی]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ پرسش‌های متداول مدیاویکی]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce فهرست ایمیلی نسخه‌های مدیاویکی]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources محلی‌سازی مدیاویکی به زبان شما]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam یادگیری روش‌های مقابله با هرزنگاری در ویکی]"
index b4658b6..67c1543 100644 (file)
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
        "config-support-info": "MediaWiki soporta os seguintes sistemas de bases de datos:\n\n$1\n\nSe non ve listado a continuación o sistema de base de datos que intenta usar, siga as instrucións ligadas enriba para activar o soporte.",
-       "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] é o obxectivo principal para MediaWiki e está mellor soportado. MediaWiki tamén funciona con [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], que son compatibles con MySQL. ([https://secure.php.net/manual/en/mysqli.installation.php  Como compilar PHP con compatibilidade MySQL])",
+       "config-dbsupport-mysql": "* [{{int:version-db-mariadb-url}} MariaDB] é o obxectivo principal para MediaWiki e é o que mellor soportado está. MediaWiki tamén funciona con [{{int:version-db-mysql-url}} MySQL] e [{{int:version-db-percona-url}} Percona Server], que son compatibles con MariaDB. ([https://secure.php.net/manual/en/mysqli.installation.php Como compilar PHP con compatibilidade MySQL])",
        "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] é un sistema de base de datos popular e de código aberto como alternativa a MySQL. ([https://secure.php.net/manual/en/pgsql.installation.php Como compilar PHP con compatibilidade PostgreSQL])",
-       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] é un sistema de base de datos lixeiro moi ben soportado. ([http://www.php.net/manual/en/pdo.installation.php Como compilar o PHP con soporte SQLite], emprega PDO)",
-       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] é un sistema comercial de xestión de base de datos de nivel empresarial. ([http://www.php.net/manual/en/oci8.installation.php Como compilar o PHP con compatibilidade OCI8])",
+       "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] é un sistema de base de datos lixeiro moi ben soportado. ([https://secure.php.net/manual/en/pdo.installation.php Como compilar o PHP con soporte SQLite], emprega PDO)",
+       "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] é un sistema comercial de xestión de base de datos a nivel empresarial. ([https://secure.php.net/manual/en/oci8.installation.php Como compilar PHP con soporte OCI8])",
        "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] é un sistema comercial de xestión de base de datos de nivel empresarial para Windows. ([https://secure.php.net/manual/en/sqlsrv.installation.php Como compilar o PHP con compatibilidade SQLSRV])",
        "config-header-mysql": "Configuración MariaDB/MySQL",
        "config-header-postgres": "Configuración do PostgreSQL",
        "config-license-help": "Moitos wikis públicos liberan todas as súas contribucións baixo unha [https://freedomdefined.org/Definition/Gl licenza libre].\nIsto axuda a crear un sentido de propiedade comunitaria e anima a seguir contribuíndo durante moito tempo.\nXeralmente, non é necesario nos wikis privados ou de empresas.\n\nSe quere poder empregar textos da Wikipedia, así como que a Wikipedia poida aceptar textos copiados do seu wiki, escolla a licenza <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nA licenza de documentación libre de GNU era a licenza anterior da Wikipedia.\nMalia aínda ser unha licenza válida, é difícil de entender.\nTamén é difícil reusar contidos baixo esta licenza.",
        "config-email-settings": "Configuración do correo electrónico",
        "config-enable-email": "Activar os correos electrónicos de saída",
-       "config-enable-email-help": "Se quere que o correo electrónico funcione, cómpre configurar os [Config-dbsupport-oracle/manual/en/mail.configuration.php parámetros PHP] correctamente.\nSe non quere ningunha característica no correo, pode desactivalas aquí.",
+       "config-enable-email-help": "Se quere que o correo electrónico funcione, cómpre configurar os [https://secure.php.net/manual/en/mail.configuration.php parámetros PHP de correo] correctamente.\nSe non quere ningunha característica de correo electrónico, pode desactivalas aquí.",
        "config-email-user": "Activar o intercambio de correos electrónicos entre usuarios",
        "config-email-user-help": "Permitir que todos os usuarios intercambien correos electrónicos, se o teñen activado nas súas preferencias.",
        "config-email-usertalk": "Activar a notificación da páxina de conversa de usuario",
        "config-cache-options": "Configuración da caché de obxectos:",
        "config-cache-help": "A caché de obxectos emprégase para mellorar a velocidade de MediaWiki mediante a memorización de datos usados con frecuencia.\nÉ amplamente recomendable a súa activación nos sitios de tamaño medio e grande; os sitios pequenos obterán tamén beneficios.",
        "config-cache-none": "Sen caché (non se elimina ningunha funcionalidade, pero pode afectar á velocidade en wikis grandes)",
-       "config-cache-accel": "Caché de obxectos do PHP (APC, APCu, XCache ou WinCache)",
+       "config-cache-accel": "Caché de obxectos PHP (APC, APCu ou WinCache)",
        "config-cache-memcached": "Empregar o Memcached (necesita unha instalación e configuración adicional)",
        "config-memcached-servers": "Servidores da memoria caché:",
        "config-memcached-help": "Lista de enderezos IP para Memcached.\nDebe especificarse un por liña, así como o porto a usar. Por exemplo:\n 127.0.0.1:11211\n 192.168.1.25:1234",
index 7e150e9..66fd723 100644 (file)
@@ -360,7 +360,7 @@ class LinkHolderArray {
                }
                if ( count( $linkcolour_ids ) ) {
                        // pass an array of page_ids to an extension
-                       Hooks::run( 'GetLinkColours', [ $linkcolour_ids, &$colours ] );
+                       Hooks::run( 'GetLinkColours', [ $linkcolour_ids, &$colours, $this->parent->getTitle() ] );
                }
 
                # Do a second query for different language variants of links and categories
@@ -589,7 +589,7 @@ class LinkHolderArray {
                                        }
                                }
                        }
-                       Hooks::run( 'GetLinkColours', [ $linkcolour_ids, &$colours ] );
+                       Hooks::run( 'GetLinkColours', [ $linkcolour_ids, &$colours, $this->parent->getTitle() ] );
 
                        // rebuild the categories in original order (if there are replacements)
                        if ( count( $varCategories ) > 0 ) {
index 5f04e02..a6273c5 100644 (file)
@@ -74,7 +74,8 @@
                        "Aboulouei1",
                        "سامي الرحيلي",
                        "Azouz.anis",
-                       "Elbasyouny"
+                       "Elbasyouny",
+                       "Omar Ghrida"
                ]
        },
        "tog-underline": "سطر تحت الوصلات:",
        "group-autoconfirmed": "مستخدمون مؤكدون تلقائيا",
        "group-bot": "بوتات",
        "group-sysop": "إداريون",
+       "group-interface-admin": "إداريو الواجهة",
        "group-bureaucrat": "بيروقراطيون",
        "group-suppress": "مزيلون",
        "group-all": "(الكل)",
        "group-autoconfirmed-member": "{{GENDER:$1|مستخدم مؤكد تلقائيًا|مستخدمة مؤكدة تلقائيًا}}",
        "group-bot-member": "{{GENDER:$1|بوت}}",
        "group-sysop-member": "{{GENDER:$1|إداري|إدارية}}",
+       "group-interface-admin-member": "{{GENDER:$1|إداري الواجهة}}",
        "group-bureaucrat-member": "{{GENDER:$1|بيروقراط}}",
        "group-suppress-member": "{{GENDER:$1|مزيل|مزيلة}}",
        "grouppage-user": "{{ns:project}}:مستخدمون",
        "grouppage-autoconfirmed": "{{ns:project}}:مستخدمون مؤكدون تلقائيا",
        "grouppage-bot": "{{ns:project}}:بوتات",
        "grouppage-sysop": "{{ns:project}}:إداريون",
+       "grouppage-interface-admin": "{{ns:project}}:إداريو الواجهة",
        "grouppage-bureaucrat": "{{ns:project}}:بيروقراطيون",
        "grouppage-suppress": "{{ns:project}}:خاصية الإزالة",
        "right-read": "قراءة الصفحات",
        "right-editusercss": "تعديل ملفات CSS للمستخدمين الآخرين",
        "right-edituserjson": "تعديل ملفات جسون للمستخدمين الآخرين",
        "right-edituserjs": "تعديل ملفات جافاسكريبت للمستخدمين الآخرين",
+       "right-editsitecss": "تعديل CSS على مستوى الموقع",
+       "right-editsitejson": "تعديل جسون على مستوى الموقع",
+       "right-editsitejs": "تعديل جافاسكريبت على مستوى الموقع",
        "right-editmyusercss": "تعديل ملفات CSS للمستخدم نفسه",
        "right-editmyuserjson": "تعديل ملفات جسون للمستخدم نفسه",
        "right-editmyuserjs": "تعديل ملفات جافاسكربت للمستخدم نفسه",
index e1da695..15c6487 100644 (file)
        "customjsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі, таму што яна ўтрымлівае пэрсанальныя налады іншага ўдзельніка.",
        "customjsprotected": "Вы ня маеце правоў на рэдагаваньне гэтай старонкі JavaScript, таму што яна ўтрымлівае пэрсанальныя налады іншага ўдзельніка.",
        "sitecssprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай CSS-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў",
+       "sitejsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі, бо гэта можа паўплываць на ўсіх удзельнікаў",
        "mycustomcssprotected": "Вы ня маеце дазволу рэдагаваць гэтую CSS-старонку.",
        "mycustomjsonprotected": "Вы ня маеце дазволу на рэдагаваньне гэтай JSON-старонкі.",
        "mycustomjsprotected": "Вы ня маеце дазволу рэдагаваць гэтую JavaScript-старонку.",
        "uploadstash-zero-length": "Файл мае нулявую даўжыню.",
        "invalid-chunk-offset": "Няслушнае зрушэньне фрагмэнту",
        "img-auth-accessdenied": "Доступ забаронены",
-       "img-auth-nopathinfo": "Адсутнічае PATH_INFO.\nВаш сэрвэр не ўстаноўлены на пропуск гэтай інфармацыі.\nМагчма, ён працуе праз CGI і не падтрымлівае img_auth.\nГлядзіце https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
+       "img-auth-nopathinfo": "Адсутнічаюць зьвесткі пра шлях.\nВаш сэрвэр мусіць быць наладжаны на пропуск зьменных REQUEST_URI і/ці PATH_INFO.\nКалі гэта так, паспрабуйце ўключыць $wgUsePathInfo.\nГлядзіце https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Неабходнага шляху няма ў дырэкторыі загрузкі, пазначанай у канфігурацыі.",
        "img-auth-badtitle": "Немагчыма стварыць слушную назву з «$1».",
        "img-auth-nologinnWL": "Вы не ўвайшлі ў сыстэму, а «$1» не знаходзіцца ў белым сьпісе.",
index 1933ba1..505af10 100644 (file)
        "group-autoconfirmed": "Автоматично одобрени потребители",
        "group-bot": "Ботове",
        "group-sysop": "Администратори",
+       "group-interface-admin": "Интерфейсни администратори",
        "group-bureaucrat": "Бюрократи",
        "group-suppress": "Ревизори",
        "group-all": "(всички)",
        "group-autoconfirmed-member": "{{GENDER:$1|автоматично одобрен потребител}}",
        "group-bot-member": "{{GENDER:$1|бот}}",
        "group-sysop-member": "{{GENDER:$1|администратор}}",
+       "group-interface-admin-member": "{{GENDER:$1|интерфейсен администратор|интерфейсна администраторка}}",
        "group-bureaucrat-member": "{{GENDER:$1|бюрократ}}",
        "group-suppress-member": "{{GENDER:$1|ревизор}}",
        "grouppage-user": "{{ns:project}}:Потребители",
        "grouppage-autoconfirmed": "{{ns:project}}:Автоматично одобрени потребители",
        "grouppage-bot": "{{ns:project}}:Ботове",
        "grouppage-sysop": "{{ns:project}}:Администратори",
+       "grouppage-interface-admin": "{{ns:project}}:Интерфейсни администратори",
        "grouppage-bureaucrat": "{{ns:project}}:Бюрократи",
        "grouppage-suppress": "{{ns:project}}:Ревизори",
        "right-read": "Четене на страници",
index f9474c3..8e9e882 100644 (file)
@@ -64,7 +64,7 @@
        "fri": "جمعه",
        "sat": "شنبه",
        "january": "جانڤیە",
-       "february": "فئڤریە",
+       "february": "فڤریٱ",
        "march": "مارس",
        "april": "آڤریل",
        "may_long": "مە",
        "copyrightpage": "{{ns:project}}:کپی رایت",
        "currentevents": "اتفاقات جاری",
        "currentevents-url": "Project:اتفاقات جاری",
-       "disclaimers": "تیە پوٙشنا",
+       "disclaimers": "تی پۊشنیڌنیا",
        "disclaimerpage": "Project: تیە پوشنیدٙئنئ کولی",
        "edithelp": "کمک برای اصلاح",
        "helppage-top-gethelp": "هومیاري",
index 5b8ccfd..38f6b80 100644 (file)
        "group-autoconfirmed": "Usuaris autoconfirmats",
        "group-bot": "Bots",
        "group-sysop": "Administradors",
+       "group-interface-admin": "Administradors de la interfície",
        "group-bureaucrat": "Buròcrates",
        "group-suppress": "Supressors de Flow",
        "group-all": "(tots)",
        "group-autoconfirmed-member": "{{GENDER:$1|usuari autoconfirmat|usuària autoconfirmada}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|administrador|administradora}}",
+       "group-interface-admin-member": "{{GENDER:$1|administrador|administradora}} de la interfície",
        "group-bureaucrat-member": "{{GENDER:$1|buròcrata}}",
        "group-suppress-member": "{{GENDER:$1|supressor|supressora}} de Flow",
        "grouppage-user": "{{ns:project}}:Usuaris",
        "grouppage-autoconfirmed": "{{ns:project}}:Usuaris autoconfirmats",
        "grouppage-bot": "{{ns:project}}:Bots",
        "grouppage-sysop": "{{ns:project}}:Administradors",
+       "grouppage-interface-admin": "{{ns:project}}:Administradors de la interfície",
        "grouppage-bureaucrat": "{{ns:project}}:Buròcrates",
        "grouppage-suppress": "{{ns:project}}:Supressors de Flow",
        "right-read": "Llegir pàgines",
index 4d64e06..cf485b7 100644 (file)
        "group-autoconfirmed-member": "{{GENDER:$1|بەکارھێنەرە خۆبەخۆ پەسندکراوەکان}}",
        "group-bot-member": "بۆت",
        "group-sysop-member": "{{GENDER:$1|بەڕێوەبەر}}",
+       "group-interface-admin-member": "{{GENDER:$1|بەڕێوەبەری ڕووکار}}",
        "group-bureaucrat-member": "{{GENDER:$1|بیوروکرات}}",
        "group-suppress-member": "{{GENDER:$1|چاودێر}}",
        "grouppage-user": "{{ns:project}}:بەکارھێنەران",
index a0e9bca..a199a90 100644 (file)
        "group-autoconfirmed": "Αυτοεπιβεβαιωμένοι χρήστες",
        "group-bot": "Ρομπότ",
        "group-sysop": "Διαχειριστές",
+       "group-interface-admin": "Διαχειριστές διεπαφής",
        "group-bureaucrat": "Γραφειοκράτες",
        "group-suppress": "Παρατηρητές",
        "group-all": "(όλοι)",
        "group-autoconfirmed-member": "{{GENDER:$1|αυτοεπιβεβαιωμένος χρήστης|αυτοεπιβεβαιωμένη χρήστρια}}",
        "group-bot-member": "ρομπότ",
        "group-sysop-member": "{{GENDER:$1|διαχειριστής|διαχειρίστρια}}",
+       "group-interface-admin-member": "{{GENDER:$1|διαχειριστής διεπαφής}}",
        "group-bureaucrat-member": "{{GENDER:$1|γραφειοκράτης|γραφειοκράτις}}",
        "group-suppress-member": "{{GENDER:$1|επιτηρητής|επιτηρήτρια}}",
        "grouppage-user": "{{ns:project}}:Χρήστες",
        "grouppage-autoconfirmed": "{{ns:project}}:Αυτόματα επιβεβαιωμένοι χρήστες",
        "grouppage-bot": "{{ns:project}}:Bots",
        "grouppage-sysop": "{{ns:project}}:Διαχειριστές",
+       "grouppage-interface-admin": "{{ns:project}}:Διαχειριστές διεπαφής",
        "grouppage-bureaucrat": "{{ns:project}}:Γραφειοκράτες",
        "grouppage-suppress": "{{ns:project}}:Παρόραμα",
        "right-read": "Ανάγνωση σελίδων",
index 97ce51e..5b31d45 100644 (file)
        "showhideselectedversions": "Erakutsi/ezkutatu aukeratutako berrikuspenak",
        "editundo": "desegin",
        "diff-empty": "(Ez dago alderik)",
-       "diff-multi-sameuser": "(Erabiltzaile berdinaren {{PLURAL:$1|erdiko ekarpen bat ez da|$1 erdiko ekarpen ez dira}} erakusten)",
-       "diff-multi-otherusers": "({{PLURAL:$1|Tarteko berrikusketa bat|$1 tarteko berrikusketak}}  {{PLURAL:$2|beste erabiltzaile bat|$2 erabiltzaileak}} egina ez da erakusten)",
-       "diff-multi-manyusers": "({{PLURAL:$1|Tarteko berrikusketa bat|$1 tarteko berrikusketak}} by more than $2 {{PLURAL:$2|erabiltzaile batek|erabiltzaile batzuek}} baino gehiagok egina ez erakutsia)",
+       "diff-multi-sameuser": "(Erabiltzaile berak tartean egindako {{PLURAL:$1|ekarpen bat ez da|$1 ekarpen ez dira}} erakusten)",
+       "diff-multi-otherusers": "({{PLURAL:$2|Beste erabiltzaile batek|$2 erabiltzailek}} tartean egindako {{PLURAL:$1|berrikusketa bat ez da erakusten|$1 berrikusketa ez dira erakusten}})",
+       "diff-multi-manyusers": "({{PLURAL:$2|Erabiltzaile batek|$2 erabiltzailek}} baino gehiagok tartean egindako {{PLURAL:$1|berrikusketa bat ez da erakusten|$1 berrikusketa ez dira erakusten}})",
        "diff-paragraph-moved-tonew": "Paragrafoa mugitu egin da. Egin klik beste kokaleku batera salto egiteko.",
        "diff-paragraph-moved-toold": "Paragrafoa mugitu egin da. Egin klik aurretiko kokalekura salto egiteko.",
        "difference-missing-revision": " ($1) ezberdinatasunaren  {{PLURAL:$2|Berrikusketa bat|$2 berrikusketa}} ez {{PLURAL:$2|da|dira}} aurkitu.\n\nHau, orokorrean ezabatu egin den orri batera deskonektatua dagoen esteka desegonkor baten ondorioz gertatzen da.\n\nHemen xehetasunak aurki daitezke: [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
        "tags-delete-submit": "Betirako ezabatu etiketa hau",
        "tags-delete-not-allowed": "Luzapen batek definitutako etiketak ezin dira ezabatu, luzapenak bereziki baimendu ezean.",
        "tags-delete-not-found": "\"$1\" etiketa  ez da existitzen.",
-       "tags-delete-too-many-uses": "\"$1\" etiketa $2 {{PLURAL:$2|berrikusketa bat|berrikusketa}} baino gehiagotan aplikatu egin denez ezingo da ezabatu",
+       "tags-delete-too-many-uses": "«$1» etiketa $2 {{PLURAL:$2|berrikusketa batean|berrikusketatan}} baino gehiagotan aplikatu denez, ezingo da ezabatu.",
        "tags-delete-warnings-after-delete": "\"$1\" etiketa ezabatu egin da, baina hurrengo {{PLURAL:$2|abisua|abisuak}} aurkitu d(ir)a:",
        "tags-delete-no-permission": "Ez daukazu baimenik etiketa aldaketak ezabatzeko.",
        "tags-activate-title": "Etiketa aktibatu",
        "logentry-delete-delete_redir": "$1 wikilariak {{GENDER:$2|}} «$3» birbideraketa ezabatu du, gainidatzita",
        "logentry-delete-restore": "$1 administratzaileak «$3» orria {{GENDER:$2|lehengoratu}} du",
        "logentry-delete-restore-nocount": "$1-k {{GENDER:$2|leheneratutako}} $3 orria.",
-       "restore-count-revisions": "{{PLURAL:$1|berrikusketa 1|$1 berrikusketa}}",
+       "restore-count-revisions": "{{PLURAL:$1|1 berrikusketa|$1 berrikusketa}}",
        "restore-count-files": "{{PLURAL:$1|Fitxategi 1|$1 fitxategi}}",
        "logentry-delete-event": "$1 wikilariak ikusgaitasuna {{GENDER:$2|aldatu}} {{PLURAL:$5|dio erregistroko sarrera bati|die erregistroko $5 sarrerari}}, $3 orrian: $4",
        "logentry-delete-revision": "$1 wikilariak ikusgaitasuna {{GENDER:$2|aldatu}} {{PLURAL:$5|dio erregistroko sarrera bati|die erregistroko $5 sarrerari}}, $3 orrian: $4",
index 329a19c..e853143 100644 (file)
        "tog-watchlisthideminor": "ویرایش‌های جزئی در فهرست پی‌گیری‌ها پنهان شود",
        "tog-watchlisthideliu": "ویرایش‌های کاربران وارد شده به سامانه در فهرست پی‌گیری‌ها پنهان شود",
        "tog-watchlistreloadautomatically": "زمانی که یک پالایه تغییر کرد فهرست پیگیری به صورت خودکار به روز شود (نیازمند جاوااسکریپت)",
-       "tog-watchlistunwatchlinks": "اÙ\81زÙ\88دÙ\86 Ù¾Û\8cÙ\88Ù\86دÙ\87اÛ\8c Ù\85ستÙ\82Û\8cÙ\85 Ø®Ø±Ù\88ج Ø§Ø² Ù¾Û\8câ\80\8cÚ¯Û\8cرÛ\8c Ø¨Ù\87 Ù\81Ù\87رست Ù¾Û\8câ\80\8cÚ¯Û\8cرÛ\8c (جاواسکریپت ممکن است نیاز شود)",
+       "tog-watchlistunwatchlinks": "اÙ\81زÙ\88دÙ\86 Ù\85شخصâ\80\8cÚ©Ù\86Ù\86دÙ\87اÛ\8c Ø¹Ø¯Ù\85 Ù¾Û\8cÚ¯Û\8cرÛ\8c/Ù¾Û\8cÚ¯Û\8cرÛ\8c ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) Ø¨Ù\87 ØµÙ\81حات Ù¾Û\8cÚ¯Û\8cرÛ\8c Ø¯Ø§Ø±Ø§Û\8c ØªØºÛ\8cÛ\8cرات (جاواسکریپت ممکن است نیاز شود)",
        "tog-watchlisthideanons": "ویرایش‌های کاربران ناشناس در فهرست پی‌گیری‌ها پنهان شود",
        "tog-watchlisthidepatrolled": "ویرایش‌های گشت‌خورده در فهرست پی‌گیری‌ها پنهان شود",
        "tog-watchlisthidecategorization": "نهفتن رده‌بندی صفحه‌ها",
        "customcssprotected": "شما اجازهٔ ویرایش این صفحهٔ سی‌اس‌اس را ندارید، زیرا حاوی تنظیم‌های شخصی یک کاربر دیگر است.",
        "customjsonprotected": "شما اجازهٔ ویرایش در این صفحهٔ JSON را ندارید چون دارای تنظیمات شخصی کاربران است.",
        "customjsprotected": "شما اجازهٔ ویرایش این صفحهٔ جاوااسکریپت را ندارید، زیرا حاوی تنظیم‌های شخصی یک کاربر دیگر است.",
+       "sitecssprotected": "به دلیل تاثیر سراسری بر روی همه بازدیدکنندگان،امکان ویرایش این صفحه css برای شما نیست.",
+       "sitejsonprotected": "به دلیل تاثیر سراسری بر روی همه بازدیدکنندگان،امکان ویرایش این صفحه JSON برای شما نیست.",
+       "sitejsprotected": "به دلیل تاثیر سراسری بر روی همه بازدیدکنندگان،امکان ویرایش این صفحه جاوااسکریپت برای شما نیست.",
        "mycustomcssprotected": "شما دارای مجوز ویرایش این صفحهٔ سی‌اس‌اس نیستید.",
+       "mycustomjsonprotected": "شما اجازه ویرایش این صفحه JSON را ندارید.",
        "mycustomjsprotected": "شما دارای مجوز ویرایش این صفحهٔ جاوااسکریپت نیستید.",
        "myprivateinfoprotected": "شما دارای مجوز ویرایش اطلاعات شخصی خود نیستید.",
        "mypreferencesprotected": "شما دارای مجوز ویرایش تنظیمات خود نیستید.",
        "password-login-forbidden": "استفاده از این نام کاربری و گذرواژه ممنوع است.",
        "mailmypassword": "بازنشانی گذرواژه",
        "passwordremindertitle": "یادآور گذرواژهٔ {{SITENAME}}",
-       "passwordremindertext": "Û\8cÚ© Ù\86Ù\81ر (احتÙ\85اÙ\84اÙ\8b Ø®Ù\88د Ø´Ù\85اØ\8c Ø¨Ø§ Ù\86شاÙ\86Û\8c Ø¢Û\8câ\80\8cÙ¾Û\8c $1) Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 Ø¬Ø¯Û\8cدÛ\8c Ø¨Ø±Ø§Û\8c Ø­Ø³Ø§Ø¨ Ú©Ø§Ø±Ø¨Ø±Û\8c Ø´Ù\85ا Ø¯Ø± {{SITENAME}} Ø¯Ø±Ø®Ù\88است Ú©Ø±Ø¯Ù\87â\80\8cاست ($4). \nÛ\8cÚ© Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 Ù\85Ù\88Ù\82ت Ø¨Ø±Ø§Û\8c Ú©Ø§Ø±Ø¨Ø± Â«$2» Ø³Ø§Ø®ØªÙ\87 Ø´Ø¯Ù\87 Ù\88 Ø¨Ø±Ø§Ø¨Ø± Ø¨Ø§ Â«$3» Ù\82رار Ø¯Ø§Ø¯Ù\87 Ø´Ø¯Ù\87â\80\8cاست.\nاگر Ù\87دÙ\81تاÙ\86 Ù\87Ù\85Û\8cÙ\86 Ø¨Ù\88دÙ\87â\80\8cاستØ\8c Ø§Ú©Ù\86Ù\88Ù\86 Ø¨Ø§Û\8cد Ù\88ارد Ø³Ø§Ù\85اÙ\86Ù\87 Ø´Ù\88Û\8cد Ù\88 Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 Ø¬Ø¯Û\8cدÛ\8c Ø¨Ø±Ú¯Ø²Û\8cÙ\86Û\8cد.\nگذرÙ\88اÚ\98Ù\87Ù\94 Ù\85Ù\88Ù\82ت Ø´Ù\85ا Ø¸Ø±Ù\81 {{PLURAL:$5|Û\8cÚ© Ø±Ù\88ز|$5 Ø±Ù\88ز}} Ø¨Ø§Ø·Ù\84 Ù\85Û\8câ\80\8cØ´Ù\88د.\n\nاگر Ú©Ø³ Ø¯Û\8cگرÛ\8c Ø§Û\8cÙ\86 Ø¯Ø±Ø®Ù\88است Ø±Ø§ Ú©Ø±Ø¯Ù\87â\80\8cاست Û\8cا Ø§Û\8cÙ\86Ú©Ù\87 Ø´Ù\85ا Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 Ù¾Û\8cØ´Û\8cÙ\86 Ø®Ù\88د Ø±Ø§ Ø¨Ù\87 Û\8cاد Ø¢Ù\88ردÙ\87â\80\8cاÛ\8cد Ù\88 Ø¯Û\8cگر ØªÙ\85اÛ\8cÙ\84Û\8c Ø¨Ù\87 ØªØºÛ\8cÛ\8cر Ø¢Ù\86 Ù\86دارÛ\8cدØ\8c Ù\85Û\8câ\80\8cتÙ\88اÙ\86Û\8cد Ø§Û\8cÙ\86 Ù¾Û\8cغاÙ\85 Ø±Ø§ Ù\86ادÛ\8cدÙ\87 Ø¨Ú¯Û\8cرÛ\8cد Ù\88 Ù\87Ù\85اÙ\86 Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 Ù¾Û\8cØ´Û\8cÙ\86 Ø±Ø§ Ø¨Ù\87 Ú©Ø§Ø± Ø¨Ø±Û\8cد.",
+       "passwordremindertext": "یک نفر (با نشانی آی‌پی $1) گذرواژهٔ جدیدی برای حساب کاربری شما در {{SITENAME}} درخواست کرده‌است ($4). \nیک گذرواژهٔ موقت برای کاربر «$2» ساخته شده و برابر با «$3» قرار داده شده‌است.\nاگر هدفتان همین بوده‌است، اکنون باید وارد سامانه شوید و گذرواژهٔ جدیدی برگزینید.\nگذرواژهٔ موقت شما ظرف {{PLURAL:$5|یک روز|$5 روز}} باطل می‌شود.\n\nاگر کس دیگری این درخواست را کرده‌است یا اینکه شما گذرواژهٔ پیشین خود را به یاد آورده‌اید و دیگر تمایلی به تغییر آن ندارید، می‌توانید این پیغام را نادیده بگیرید و همان گذرواژهٔ پیشین را به کار برید.",
        "noemail": "هیچ آدرس ایمیلی برای کاربر «$1» ثبت نشده است.",
        "noemailcreate": "شما باید یک آدرس ایمیل درست فراهم کنید",
        "passwordsent": "گذرواژه‌ای جدید به آدرس ایمیل ثبت شده برای «$1» ارسال شد.\nلطفاً پس از دریافت آن، دوباره به سیستم وارد شوید.",
        "botpasswords-existing": "گذرواژه‌های موجود ربات",
        "botpasswords-createnew": "ایجاد گذرواژه ربات",
        "botpasswords-editexisting": "ویرایش گذرواژه موجود ربات",
+       "botpasswords-label-needsreset": "(نیاز به تنظیم مجدد گذرواژه)",
        "botpasswords-label-appid": "نام ربات:",
        "botpasswords-label-create": "ایجاد",
        "botpasswords-label-update": "به‌روز رسانی",
        "botpasswords-restriction-failed": "محدودیت‌های گذرواژهٔ ربات از این ورود جلوگیری می‌کند.",
        "botpasswords-invalid-name": "نام کاربری مشخص شده دارای جداکنندهٔ گذرواژهٔ رباتی نیست («$1»).",
        "botpasswords-not-exist": "کاربر «$1» گذرواژهٔ رباتی نام‌دهی شدهٔ «$2» ندارد.",
+       "botpasswords-needs-reset": "گذرواژهٔ رباتی برای ربات «$2» و {{GENDER:$1|کاربر}} «$1» باید از نو تنظیم شود.",
        "resetpass_forbidden": "نمی‌توان گذرواژه‌ها را تغییر داد",
        "resetpass_forbidden-reason": "نمی‌توانید گذرواژه‌ها را تغییر داد: $1",
        "resetpass-no-info": "برای دسترسی مستقیم به این صفحه شما باید به سامانه وارد شده باشید.",
        "resetpass-temp-password": "گذرواژهٔ موقت:",
        "resetpass-abort-generic": "تغییر گذرواژه به دست یکی از افزونه‌ها لغو شده است.",
        "resetpass-expired": "رمز عبور شما منقضی شده‌است. لطفاً برای ورود رمز عبور جدیدی را تنظیم کنید.",
-       "resetpass-expired-soft": "رمز عبور شما منقضی شده‌است و نیاز به تنظیم مجدد دارد. لطفاً اکنون رمز عبور جدیدی را انتخاب کنید، یا برای تنظیم مجدد آن در آینده، دکمهٔ «{{int:authprovider-resetpass-skip-label}}» را کلیک کنید.",
-       "resetpass-validity-soft": "گذرÙ\88اÙ\87Ù\94 Ø´Ù\85ا ØµØ­Û\8cØ­ Ù\86Û\8cست: $1\n\nÙ\84Ø·Ù\81اÙ\8b Û\8cÚ© Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 ØªØ§Ø²Ù\87 Ø§Ù\84Ø¢Ù\86 Ø§Ù\86تخاب Ú©Ù\86Û\8cد Û\8cا Ø¨Ø± Â«{{int:authprovider-resetpass-skip-label}}» Ú©Ù\84Û\8cÚ© Ú©Ù\86Û\8cد Ú©Ù\87 Ø¯Ù\88بارÙ\87 Ø¢Ù\86 Ø±Ø§ Ø¨Ø¹Ø¯Ø§Ù\8b Ø§Ù\86تخاب Ú©Ù\86ید.",
+       "resetpass-expired-soft": "رمز عبور شما منقضی شده‌است و نیاز به تغییر دارد. لطفاً اکنون رمز عبور جدیدی را انتخاب کنید، یا برای تغییر آن در آینده، دکمهٔ «{{int:authprovider-resetpass-skip-label}}» را کلیک کنید.",
+       "resetpass-validity-soft": "گذرÙ\88اÙ\87Ù\94 Ø´Ù\85ا ØµØ­Û\8cØ­ Ù\86Û\8cست: $1\n\nÙ\84Ø·Ù\81اÙ\8b Û\8cÚ© Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 ØªØ§Ø²Ù\87 Ø§Ù\84Ø¢Ù\86 Ø§Ù\86تخاب Ú©Ù\86Û\8cد Û\8cا Ø¨Ø± Â«{{int:authprovider-resetpass-skip-label}}» Ú©Ù\84Û\8cÚ© Ú©Ù\86Û\8cد Ú©Ù\87 Ø¯Ù\88بارÙ\87 Ø¢Ù\86 Ø±Ø§ Ø¨Ø¹Ø¯Ø§Ù\8b ØªØºÛ\8cÛ\8cر Ø¯Ù\87ید.",
        "passwordreset": "بازنشانی گذرواژه",
        "passwordreset-text-one": "برای بازنشانی گذرواژه‌تان این فرم را کامل کنید.",
        "passwordreset-text-many": "{{PLURAL:$1|برای دریافت یک گذرواژهٔ موقت از طریق ایمیل، یکی از خانه‌ها را پر کنید.}}",
        "subject-preview": "پیش‌نمایش موضوع:",
        "previewerrortext": "در زمان تلاش برای نمایش دادن تغییرات شما، خطایی رخ داد.",
        "blockedtitle": "کاربر بسته شده‌است",
-       "blockedtext": "<strong>دسترسی حساب کاربری یا نشانی آی‌پی شما بسته شده‌است.</strong>\n\nاین قطع دسترسی توسط $1 انجام شده است.\nدلیل ارائه‌شده چنین است: <em>$2</em>\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «ایمیل به این کاربر» استفاده کنید مگر آنکه آدرس ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
-       "autoblockedtext": "دسترسی نشانی آی‌پی شما قطع شده‌است، زیرا این نشانی آی‌پی توسط کاربر دیگری استفاده شده که دسترسی او توسط $1 قطع شده‌است.\nدلیل ارائه‌شده چنین است:\n\n:''$2''\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «ایمیل به این کاربر» استفاده کنید مگر آنکه نشانی ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
+       "blockedtext": "<strong>دسترسی حساب کاربری یا نشانی آی‌پی شما بسته شده‌است.</strong>\n\nاین قطع دسترسی توسط $1 انجام شده است.\nدلیل ارائه‌شده چنین است: <em>$2</em>\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «{{int:emailuser}}» استفاده کنید مگر آنکه آدرس ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
+       "autoblockedtext": "دسترسی نشانی آی‌پی شما قطع شده‌است، زیرا این نشانی آی‌پی توسط کاربر دیگری استفاده شده که دسترسی او توسط $1 قطع شده‌است.\nدلیل ارائه‌شده چنین است:\n\n:''$2''\n\n* شروع قطع دسترسی: $8\n* پایان قطع دسترسی: $6\n* کاربری هدف قطع دسترسی: $7\n\nشما می‌توانید با $1 یا [[{{MediaWiki:Grouppage-sysop}}|مدیری]] دیگر تماس بگیرید و در این باره صحبت کنید.\nتوجه کنید که شما نمی‌توانید از قابلیت «{{int:emailuser}}» استفاده کنید مگر آنکه نشانی ایمیل معتبری در [[Special:Preferences|ترجیحات کاربری]] خودتان ثبت کرده باشید و نیز باید امکان استفاده از این قابلیت برای شما قطع نشده باشد.\nنشانی آی‌پی فعلی شما $3 و شمارهٔ قطع دسترسی شما $5 است.\nلطفاً تمامی جزئیات فوق را در کلیهٔ درخواست‌هایی که در این باره مطرح می‌کنید ذکر کنید.",
        "systemblockedtext": "نام کاربری یا نشانی آی‌پی شما خودکار توسط مدیاویکی مسدود شده‌است.\nدلیل ارائه‌شده:\n\n:<em>$2</em>\n\n* آغاز بلاک: $8\n* پایان بلاک: $6\n* قطع دسترسی‌شده مورد نظر: $7\n\nنشانی آی‌پی کنونی شما $3 است.\nخواهشمند است تمام جزئیات بالا را در هر پرس‌وجویی که انجام می‌دهید قرار دهید.",
        "blockednoreason": "دلیلی مشخص نشده‌است",
        "whitelistedittext": "برای ویرایش مقاله‌ها باید $1.",
        "blocked-notice-logextract": "دسترسی این کاربر در حال حاضر بسته است.\nآخرین مورد سیاهه قطع دسترسی در زیر آمده‌است:",
        "clearyourcache": "<strong>نکته:</strong> پس از ذخیره کردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.\n*<strong>فایرفاکس / سافاری:</strong> کلید <em>Shift</em> را نگه دارید و روی دکمهٔ <em>Reload</em> کلیک کنید، یا کلید‌های <em>Ctrl-F5</em> یا <em>Ctrl-R</em> را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های <em>⌘-R</em>)\n*<strong>گوگل کروم:</strong> کلیدهای <em>Ctrl+Shift+R</em> را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های <em>⌘-Shift-R</em>)\n*<strong>اینترنت اکسپلورر:</strong> کلید <em>Ctrl</em> را نگه‌دارید و روی دکمهٔ <em>Refresh</em> کلیک کنید، یا کلید‌های <em>Ctrl-F5</em> را با هم فشار دهید\n*<strong>اپرا:</strong> بروید به <em>Menu → Settings</em> (<em>Opera → Preferences</em> on a Mac) and then to <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
        "usercssyoucanpreview": "'''نکته:''' پیش از ذخیره کردن پرونده سی‌اس‌اس خود، با دکمهٔ '''{{int:showpreview}}''' آن را آزمایش کنید.",
+       "userjsonyoucanpreview": "<strong>نکته:</strong> از دکمه \"{{int:showpreview}}\" برای آزمودن JSON پیش از ذخیره استفاده کنید.",
        "userjsyoucanpreview": "'''نکته:''' پیش از ذخیره کردن پروندهٔ جاوااسکریپت خود، با دکمهٔ '''{{int:showpreview}}''' آن را آزمایش کنید.",
        "usercsspreview": "'''فراموش مکنید که شما فقط دارید پیش‌نمایش سی‌اس‌اس کاربری‌تان را می‌بینید.'''\n'''این سی‌اس‌اس هنوز ذخیره نشده‌است!'''",
+       "userjsonpreview": "<strong>توجه داشته باشید که شما در حال آزمودن و پیش نمایش گرفتن از تنظیمات JSON هستید و هنوز آن را ذخیره نکردید!</strong>",
        "userjspreview": "'''به یاد داشته باشید که شما فقط دارید جاوااسکریپت کاربری‌تان را امتحان می‌کنید/پیش‌نمایش آن را می‌بینید.'''\n'''این جاوااسکریپت هنوز ذخیره نشده‌است!'''",
        "sitecsspreview": "'''به یاد داشته باشید که شما فقط دارید پیش‌نمایش این سی‌اس‌اس را می‌بینید.'''\n'''این سی‌اس‌اس هنوز ذخیره نشده‌است!'''",
+       "sitejsonpreview": "<strong>توجه داشته باشید که شما در حال آزمودن و پیش نمایش گرفتن از تنظیمات JSON هستید و هنوز آن را ذخیره نکردید!</strong>",
        "sitejspreview": "'''به یاد داشته باشید که شما فقط دارید پیش‌نمایش این جاوااسکریپت را می‌بینید.'''\n'''این جاوااسکریپت هنوز ذخیره نشده‌است!'''",
-       "userinvalidconfigtitle": "'''هشدار:''' پوسته‌ای به نام «$1» وجود ندارد.\nبه یاد داشته باشید که صفحه‌های شخصی ‎.css و ‎.js باید عنوانی با حروف کوچک داشته باشند؛ نمونه: {{ns:user}}:فو/vector.css در مقابل {{ns:user}}:فو/Vector.css.",
+       "userinvalidconfigtitle": "<strong>هشدار:</strong> پوسته‌ای به نام «$1» وجود ندارد.\nبه یاد داشته باشید که صفحه‌های شخصی ‎.css ،.json و ‎.js باید عنوانی با حروف کوچک داشته باشند؛ نمونه: {{ns:user}}:فو/vector.css در مقابل {{ns:user}}:فو/Vector.css.",
        "updated": "(به‌روز شد)",
        "note": "'''نکته:'''",
        "previewnote": "'''به یاد داشته باشید که این فقط پیش‌نمایش است.'''\nتغییرات شما هنوز ذخیره نشده‌است!",
        "longpageerror": "'''خطا: متنی که ارسال کرده‌اید {{PLURAL:$1|یک کیلوبایت|$1 کیلوبایت}} طول دارد. این مقدار از مقدار بیشینهٔ {{PLURAL:$2|یک کیلوبایت|$2 کیلوبایت}} بیشتر است.'''\nنمی‌توان آن را ذخیره کرد.",
        "readonlywarning": "<strong>هشدار: پایگاه داده برای نگهداری قفل شده‌است، به همین علت هم‌اکنون نمی‌توانید ویرایش‌هایتان را ذخیره کنید.</strong>\nاگر می‌خواهید متن را در یک پروندهٔ متنی کپی کنید و برای آینده ذخیره‌اش کنید.\n\nمدیری که آن را قفل کرده این توضیح را ارائه کرده‌است: $1",
        "protectedpagewarning": "'''هشدار: این صفحه قفل شده‌است تا فقط کاربران با دسترسی مدیریت بتوانند ویرایشش کنند.'''\nآخرین موارد سیاهه در زیر آمده‌است:",
-       "semiprotectedpagewarning": "'''توجه:''' این صفحه قفل شده‌است تا تنها کاربران ثبت‌نام‌کرده قادر به ویرایش آن باشند.\nآخرین موارد سیاهه در زیر آمده‌است:",
+       "semiprotectedpagewarning": "<strong>توجه:</strong>این صفحه قفل شده‌است تا تنها کاربران ثبت‌نام‌کرده قادر به ویرایش آن باشند.\nآخرین موارد سیاهه در زیر آمده‌است:",
        "cascadeprotectedwarning": "<strong>هشدار:</strong> این صفحه به علت قرارگرفتن در {{PLURAL:$1|صفحهٔ|صفحه‌های}} آبشاری-محافظت‌شدهٔ زیر قفل شده‌است تا فقط [[Special:ListGroupRights|گروه خاصی از کاربران]] بتوانند ویرایشش کنند.",
        "titleprotectedwarning": "'''هشدار: این صفحه به شکلی قفل شده‌است که برای ایجاد آن [[Special:ListGroupRights|اختیارات خاصی]] لازم است.'''\nآخرین موارد سیاهه در زیر آمده است:",
        "templatesused": "{{PLURAL:$1|الگوی|الگوهای}} به‌کاررفته در این صفحه:",
        "diff-paragraph-moved-toold": "پاراگراف جابه‌جا شده بود. کلیک کنید تا به جای قدیمش بروید.",
        "difference-missing-revision": "{{PLURAL:$2|یک ویرایش|$2 ویرایش}}  از تفاوت نسخه‌ها ($1) {{PLURAL:$2|یافت|یافت}}  نشد.\n\nاین اتفاق معمولاً در اثر دنبال کردن پیوند تفاوتی به یک صفحهٔ حذف‌شده پیش می‌آید.\nمی‌توانید جزئیات بیشتر را در [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سیاههٔ حذف] بیابید.",
        "searchresults": "نتایج جستجو",
+       "search-filter-title-prefix-reset": "جستجوی همه صفحات",
        "searchresults-title": "نتایج جستجو برای «$1»",
        "titlematches": "تطبیق عنوان مقاله",
        "textmatches": "تطبیق متن مقاله",
        "prefs-dateformat": "آرایش تاریخ",
        "prefs-timeoffset": "فاصلهٔ زمانی",
        "prefs-advancedediting": "تنظیمات عمومی",
+       "prefs-developertools": "ابزارهای توسعه‌دهندگان",
        "prefs-editor": "ویرایشگر",
        "prefs-preview": "پیش‌نمایش",
        "prefs-advancedrc": "گزینه‌های پیشرفته",
        "group-autoconfirmed": "کاربران تأییدشدهٔ خودکار",
        "group-bot": "ربات‌ها",
        "group-sysop": "مدیران",
+       "group-interface-admin": "مدیران رابط کاربری",
        "group-bureaucrat": "دیوان‌سالاران",
        "group-suppress": "فرونشانندگان",
        "group-all": "(همه)",
        "group-autoconfirmed-member": "{{GENDER:$1|کاربر تأییدشده}}",
        "group-bot-member": "ربات",
        "group-sysop-member": "{{GENDER:$1|مدیر}}",
+       "group-interface-admin-member": "مدیر رابط کاربری",
        "group-bureaucrat-member": "{{GENDER:$1|دیوان‌سالار}}",
        "group-suppress-member": "{{GENDER:$1|فرونشاننده}}",
        "grouppage-user": "{{ns:project}}:کاربران",
        "rcfilters-other-review-tools": "دیگر ابزارهای بازبینی",
        "rcfilters-group-results-by-page": "گروه‌بندی نتایج بر اساس صفحه",
        "rcfilters-activefilters": "پالایه‌های فعال",
+       "rcfilters-activefilters-hide": "نهفتن",
+       "rcfilters-activefilters-show": "نمایش",
        "rcfilters-advancedfilters": "پالایه‌‌های پیشرفته",
        "rcfilters-limit-title": "تعداد تغییرات برای نمایش",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|تغییر|تغییر}}, $2",
        "rcfilters-empty-filter": "پالایه‌ای فعال نیست. همهٔ مشارکت‌های دیده می‌شوند.",
        "rcfilters-filterlist-title": "پالایه‌ها",
        "rcfilters-filterlist-whatsthis": "این چطور کار می‌کند؟",
-       "rcfilters-filterlist-feedbacklink": "به ما در مورد این پالایه‌های جدید بازخورد دهید",
+       "rcfilters-filterlist-feedbacklink": "به ما در مورد این پالایه‌ها بازخورد دهید",
        "rcfilters-highlightbutton-title": "پررنگ کردن نتایج",
        "rcfilters-highlightmenu-title": "انتخاب رنگ",
        "rcfilters-highlightmenu-help": "یک رنگ انتخاب کنید تا این خصوصیت پر رنگ شود",
        "recentchangeslinked-feed": "تغییرات مرتبط",
        "recentchangeslinked-toolbox": "تغییرات مرتبط",
        "recentchangeslinked-title": "تغییرات مرتبط با $1",
-       "recentchangeslinked-summary": "نام یک صفحه را وارد کنید تا تغییرات صفحه‌هایی که به آن پیوند داده‌اند یا از آن پیوند گرفته‌اند را ببینید. (برای مشاهدهٔ اعضای یک رده، ورودی را به صورت رده:نام رده وارد کنید). تغییرات در صفحه‌هایی که در  [[Special:Watchlist|فهرست پی‌گیری‌های شما]] هستند <strong>ضخیم</strong> نمای می‌یابند.",
+       "recentchangeslinked-summary": "نام یک صفحه را وارد کنید تا تغییرات صفحه‌هایی که به آن پیوند داده‌اند یا از آن پیوند گرفته‌اند را ببینید. (برای مشاهدهٔ اعضای یک رده، ورودی را به صورت {{ns:category}}:نام رده وارد کنید). تغییرات در صفحه‌هایی که در  [[Special:Watchlist|فهرست پی‌گیری‌های شما]] هستند <strong>ضخیم</strong> نمای می‌یابند.",
        "recentchangeslinked-page": "نام صفحه:",
        "recentchangeslinked-to": "نمایش تغییرات صفحه‌هایی که به صفحهٔ داده‌شده پیوند دارند",
        "recentchanges-page-added-to-category": "[[:$1]] به رده اضافه شد",
        "deadendpages": "صفحه‌های بن‌بست",
        "deadendpagestext": "صفحه‌های زیر به هیچ صفحهٔ دیگری در {{SITENAME}} پیوند ندارند.",
        "protectedpages": "صفحه‌های محافظت‌شده",
+       "protectedpages-filters": "پالایه‌ها:",
        "protectedpages-indef": "فقط محافظت‌های بی‌پایان",
        "protectedpages-summary": "در این صفحه فهرست صفحات موجود است که در حال حاضر محافظت شده اند. برای فهرست عنوان‌هایی که از ایجاد محافظت شده‌اند، به [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]] مراجعه کنید.",
        "protectedpages-cascade": "فقط محافظت‌های آبشاری",
        "apisandbox-dynamic-error-exists": "پارامتری به نام \"$1\"هم اکنون وجود دارد.",
        "apisandbox-deprecated-parameters": "پارامتر های نامناسب",
        "apisandbox-fetch-token": "پرکردن خودکار توکن",
+       "apisandbox-add-multi": "افزودن",
        "apisandbox-submit-invalid-fields-title": "بعضی از بخش‌ها نامعتبر هستند.",
        "apisandbox-submit-invalid-fields-message": "لطفا موارد مشخص شده را اصلاح کرده و دوباره امتحان کنید.",
        "apisandbox-results": "نتیجه‌ها",
        "speciallogtitlelabel": "هدف (عنوان یا {{ns:user}}:نام کاربر برای کاربر):",
        "log": "سیاهه‌ها",
        "logeventslist-submit": "نمایش",
+       "logeventslist-patrol-log": "سیاههٔ گشت",
+       "logeventslist-tag-log": "سیاهه برچسب",
        "all-logs-page": "تمام سیاهه‌های عمومی",
        "alllogstext": "نمایش یک‌جای تمام سیاهه‌های موجود در {{SITENAME}}.\nمی‌توانید با انتخاب نوع سیاهه، نام کاربری (حساس به کوچکی و بزرگی حروف) و صفحه‌های تغییریافته (حساس به بزرگی و کوچکی حروف)، نمایش را محدودتر سازید.",
        "logempty": "مورد منطبق با منظور شما در سیاهه یافت نشد.",
        "version-specialpages": "صفحه‌های ویژه",
        "version-parserhooks": "قلاب‌های تجزیه‌گر",
        "version-variables": "متغیرها",
+       "version-editors": "ویرایشگران",
        "version-antispam": "جلوگیری از هرزنامه",
        "version-other": "غیره",
        "version-mediahandlers": "به‌دست‌گیرنده‌های رسانه‌ها",
        "pagedata-title": "اطلاعات صفحه",
        "pagedata-text": "این صفحه یک رابط داده به صفحات است. لطفا نام صفحه را در آدرس به شکل زیرصفحه وارد کنید.\n* مذاکره محتوا با استفاده از هدر Accept ممکن است. این به این معنی است که داده‌ّای صفحه در قالبی که ترجیح دهید باز خواهد شد.",
        "pagedata-not-acceptable": "هیچ قالب تطبیقی یافت نشد. انواع MIME پشتیبانی شده: $1",
-       "pagedata-bad-title": "عنوان نامعتبر: «$1»."
+       "pagedata-bad-title": "عنوان نامعتبر: «$1».",
+       "passwordpolicies": "سیاست‌های گذرواژه",
+       "passwordpolicies-group": "گروه",
+       "passwordpolicies-policies": "سیاست‌ها"
 }
index 25edc81..bd1e00a 100644 (file)
        "customcssprotected": "Sinulla ei ole oikeutta muuttaa tätä CSS-sivua, koska se sisältää toisen käyttäjän henkilökohtaisia asetuksia.",
        "customjsonprotected": "Sinulla ei ole oikeutta muuttaa tätä JSON-sivua, koska se sisältää toisen käyttäjän henkilökohtaisia asetuksia.",
        "customjsprotected": "Sinulla ei ole oikeutta muuttaa tätä JavaScript-sivua, koska se sisältää toisen käyttäjän henkilökohtaisia asetuksia.",
-       "sitecssprotected": "Sinulla ei ole oikeuksia muokata tätä CSS-sivua, koska se voi vaikuttaa muihin käyttäjiin",
-       "sitejsonprotected": "Sinulla ei ole oikeuksia muokata tätä JSON-sivua, koska se voi vaikuttaa muihin käyttäjiin",
-       "sitejsprotected": "Sinulla ei ole oikeuksia muokata tätä JavaScript-sivua, koska se voi vaikuttaa muihin käyttäjiin",
+       "sitecssprotected": "Sinulla ei ole oikeutta muokata tätä CSS-sivua, koska se saattaa vaikuttaa kaikkiin sivuston käyttäjiin",
+       "sitejsonprotected": "Sinulla ei ole oikeutta muokata tätä JSON-sivua, koska se saattaa vaikuttaa kaikkiin sivuston käyttäjiin",
+       "sitejsprotected": "Sinulla ei ole oikeutta muokata tätä JavaScript-sivua, koska se saattaa vaikuttaa kaikkiin sivuston käyttäjiin",
        "mycustomcssprotected": "Sinulla ei ole oikeutta muokata tätä CSS-sivua.",
        "mycustomjsonprotected": "Sinulla ei ole oikeutta muokata tätä JSON-sivua.",
        "mycustomjsprotected": "Sinulla ei ole oikeutta muokata tätä JavaScript-sivua.",
        "group-autoconfirmed": "automaattisesti hyväksytyt käyttäjät",
        "group-bot": "botit",
        "group-sysop": "ylläpitäjät",
-       "group-interface-admin": "Käyttöliittymän ylläpitäjät",
+       "group-interface-admin": "käyttöliittymän ylläpitäjät",
        "group-bureaucrat": "byrokraatit",
        "group-suppress": "häivyttäjät (suppressors)",
        "group-all": "(kaikki)",
        "grouppage-autoconfirmed": "{{ns:project}}:Automaattisesti hyväksytyt käyttäjät",
        "grouppage-bot": "{{ns:project}}:Botit",
        "grouppage-sysop": "{{ns:project}}:Ylläpitäjät",
+       "grouppage-interface-admin": "{{ns:project}}:Käyttöliittymän ylläpitäjät",
        "grouppage-bureaucrat": "{{ns:project}}:Byrokraatit",
        "grouppage-suppress": "{{ns:project}}:Häivytysoikeudet",
        "right-read": "Lukea sivuja",
        "right-editcontentmodel": "Muokata sivun sisältömallia (content model)",
        "right-editinterface": "Muokata käyttöliittymätekstejä",
        "right-editusercss": "Muokata toisten käyttäjien CSS-tiedostoja",
-       "right-edituserjson": "Muokkaa toisten käyttäjien JSON-tiedostoja",
+       "right-edituserjson": "Muokata toisten käyttäjien JSON-tiedostoja",
        "right-edituserjs": "Muokata toisten käyttäjien JavaScript-tiedostoja",
+       "right-editsitecss": "muokata CSS-koodia koko sivustolla",
+       "right-editsitejson": "muokata JSON-koodia koko sivustolla",
+       "right-editsitejs": "muokata JavaScriptiä koko sivustolla",
        "right-editmyusercss": "Muokata omia CSS-tiedostoja",
        "right-editmyuserjson": "Muokkaa omia JSON-tiedostoja",
        "right-editmyuserjs": "Muokata omia JavaScript-tiedostoja",
        "grant-createaccount": "Luoda käyttäjätunnuksia",
        "grant-createeditmovepage": "Luoda, muokata ja siirtää sivuja",
        "grant-delete": "Poistaa sivuja, yksittäisiä versioita ja lokimerkintöjä",
-       "grant-editinterface": "Muokata järjestelmäviesti-nimiavaruutta ja käyttäjien CSS/JSON/JavaScript-sivuja",
+       "grant-editinterface": "Muokata järjestelmäviesti-nimiavaruutta sekä CSS-/JSON-/JavaScript-sivuja sivustonlaajuisesti ja myös käyttäjäkohtaisesti",
        "grant-editmycssjs": "Muokata käyttäjän omia CSS/JSON/JavaScript-sivuja",
        "grant-editmyoptions": "Muokata käyttäjän omia asetuksia",
        "grant-editmywatchlist": "Muokata tarkkailulistaasi",
+       "grant-editsiteconfig": "muokata CSS-/JS-sivuja sivustonlaajuisesti ja käyttäjäkohtaisesti",
        "grant-editpage": "Muokata olemassa olevia sivuja",
        "grant-editprotected": "Muokata suojattuja sivuja",
        "grant-highvolume": "Suorittaa paljon muokkauksia",
        "http-timed-out": "HTTP-pyyntö aikakatkaistiin.",
        "http-curl-error": "Virhe noudettaessa verkko-osoitetta: $1",
        "http-bad-status": "HTTP-pyynnön aikana oli ongelma: $1 $2",
+       "http-internal-error": "HTTP: sisäinen virhe.",
        "upload-curl-error6": "Toimimaton osoite",
        "upload-curl-error6-text": "Antamaasi osoitteeseen ei saatu yhteyttä. Varmista, että osoite on oikein ja että sivusto on saavutettavissa.",
        "upload-curl-error28": "Etälähetyksen aikakatkaisu",
index 82fff58..199787d 100644 (file)
                        "Pols12",
                        "KATRINE1992",
                        "Friday83260",
-                       "Niridya"
+                       "Niridya",
+                       "Pamputt"
                ]
        },
        "tog-underline": "Soulignement des liens :",
        "group-autoconfirmed-member": "{{GENDER:$1|utilisateur autoconfirmé|utilisatrice autoconfirmée}}",
        "group-bot-member": "{{GENDER:$1|robot}}",
        "group-sysop-member": "{{GENDER:$1|administrateur|administratrice}}",
-       "group-interface-admin-member": "{{GENDER:$1|administrateur d'interface}}",
+       "group-interface-admin-member": "{{GENDER:$1|administrateur dinterface}}",
        "group-bureaucrat-member": "{{GENDER:$1|bureaucrate}}",
        "group-suppress-member": "{{GENDER:$1|limitateur|limitatrice}}",
        "grouppage-user": "{{ns:project}}:Utilisateurs",
index 2b51042..3af4877 100644 (file)
        "converter-manual-rule-error": "Detectouse un erro na regra manual de conversión da lingua",
        "undo-success": "A edición pódese desfacer.\nComprobe a comparación que aparece a continuación para confirmar que isto é o que desexa facer; despois, garde os cambios para desfacer a edición.",
        "undo-failure": "Non se pode desfacer a edición debido a un conflito con algunha das edicións intermedias.",
+       "undo-main-slot-only": "A edición non puido desfacerse xa que implica contido que se atopa fóra da posición principal.",
        "undo-norev": "A edición non se pode desfacer porque non existe ou foi eliminada.",
        "undo-nochange": "Semella que alguén xa desfixo a edición.",
        "undo-summary": "Desfíxose a edición $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|conversa]])",
        "recentchangescount": "Número de edicións a amosar por defecto nos cambios recentes, nos historiais de páxina e nos rexistrosː",
        "prefs-help-recentchangescount": "Número máximo: 1000",
        "prefs-help-watchlist-token2": "Esta é a clave secreta da fonte de novas web para a súa lista de vixilancia.\nCalquera persoa que a saiba poderá ler a súa lista de vixilancia; non comparta esta clave.\nSe o precisa, [[Special:ResetTokens|pode restablecela]].",
-       "prefs-help-tokenmanagement": "Podes ver e restaurar a chave secreta para a túa conta que pode acceder á fonte web da túa lista de vixiancia. Calquera que coñeza a chave poderá leer a túa lista de vixiancia.",
+       "prefs-help-tokenmanagement": "Podes ver e restaurar a chave secreta para a túa conta que pode acceder á fonte web da túa lista de vixiancia. Calquera que coñeza a chave poderá leer a túa lista de vixiancia, non a comparta.",
        "savedprefs": "Gardáronse as súas preferencias.",
        "savedrights": "Gardáronse os grupos de {{GENDER:$1|usuario|usuaria}} de $1.",
        "timezonelegend": "Fuso horario:",
        "rcfilters-activefilters": "Filtros activos",
        "rcfilters-activefilters-hide": "Agochar",
        "rcfilters-activefilters-show": "Mostrar",
+       "rcfilters-activefilters-hide-tooltip": "Agochar a zona de filtros activos",
+       "rcfilters-activefilters-show-tooltip": "Amosar a zona de filtros activos",
        "rcfilters-advancedfilters": "Filtros avanzados",
        "rcfilters-limit-title": "Resultados a amosar",
        "rcfilters-limit-and-date-label": "$1 {{PLURAL:$1|cambio|cambios}}, $2",
        "rcfilters-filter-humans-label": "Humano (non bot)",
        "rcfilters-filter-humans-description": "Edicións realizadas por editores humanos.",
        "rcfilters-filtergroup-reviewstatus": "Estado de revisión",
+       "rcfilters-filter-reviewstatus-unpatrolled-description": "Edicións non marcadas como patrulladas nin manual nin automaticamente.",
        "rcfilters-filter-reviewstatus-unpatrolled-label": "Sen patrullar",
        "rcfilters-filter-reviewstatus-manual-description": "Edicións marcadas manualmente como vixiadas.",
        "rcfilters-filter-reviewstatus-manual-label": "Vixiadas manualmente",
        "rcfilters-preference-label": "Ocultar a versión mellorada de cambios recentes",
        "rcfilters-preference-help": "Reverte o redeseño da interface de 2017 e tódalas ferramentas engadidas dende entón.",
        "rcfilters-watchlist-preference-label": "Agochar a versión mellorada da lista de vixiancia",
+       "rcfilters-watchlist-preference-help": "Revirte o redeseño da interface de 2017 e tódalas ferramentas engadidas dende entón.",
        "rcfilters-filter-showlinkedfrom-label": "Amosar os cambios en páxinas ligadas desde",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Páxinas ligadas desde</strong> a páxina seleccionada",
        "rcfilters-filter-showlinkedto-label": "Amosar os cambios en páxinas que ligan con",
        "uploadstash-zero-length": "O ficheiro ten tamaño cero.",
        "invalid-chunk-offset": "Desprazamento inválido do fragmento",
        "img-auth-accessdenied": "Acceso rexeitado",
-       "img-auth-nopathinfo": "Falta a PATH_INFO.\nO seu servidor non está configurado para pasar esta información.\nPode ser que estea baseado en CGI e non soporte img_auth.\nVéxase https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
+       "img-auth-nopathinfo": "Falta a información da ruta.\nO seu servidor debe configurarse para pasar as variables REQUEST_URI e/ou PATH_INFO.\nSe o está, ténteo de novo activando $wgUsePathInfo.\nVexa https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "A ruta solicitada non está no directorio de carga configurado.",
        "img-auth-badtitle": "Non é posible construír un título válido a partir de \"$1\".",
        "img-auth-nologinnWL": "Non accedeu ao sistema e \"$1\" non está na lista de branca.",
        "apisandbox-dynamic-parameters-add-label": "Engadir un parámetro:",
        "apisandbox-dynamic-parameters-add-placeholder": "Nome do parámetro",
        "apisandbox-dynamic-error-exists": "Xa existe un parámetro co nome \"$1\".",
+       "apisandbox-templated-parameter-reason": "Este [[Special:ApiHelp/main#main/templatedparams|parámetro modelado]] ofrécese en base {{PLURAL:$1|ó valor|ós valores}} de $2.",
        "apisandbox-deprecated-parameters": "Parámetros obsoletos",
        "apisandbox-fetch-token": "Encher automaticamente o identificador",
        "apisandbox-add-multi": "Engadir",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|byte|bytes}}",
        "limitreport-expansiondepth": "Máxima profundidade de expansión",
        "limitreport-expensivefunctioncount": "Número de funcións analíticas custosas",
+       "limitreport-unstrip-depth": "Profundidade da recursividade de eliminación de etiquetas",
+       "limitreport-unstrip-size": "Tamaño trala expansión da eliminación de etiquetas",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|byte|bytes}}",
        "expandtemplates": "Expandir os modelos",
        "expand_templates_intro": "Esta páxina especial toma texto wiki e expande todos os modelos dentro del recursivamente.\nTamén expande as funcións de análise como\n<code><nowiki>{{</nowiki>#language:…}}</code> e variables como\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nDe feito, expande case calquera cousa entre dúas chaves.",
        "pagedata-text": "Esta páxina porporciona unha interface de datos para páxinas. Por favor, proporcione o título da páxina na URL, usando a sintaxe de subpáxinas.\n* A negociación de contido aplícase baseándose na cabeceira Accept do seu cliente. Isto significa que os datos da páxina serán proporcionados no formato preferido polo seu cliente.",
        "pagedata-not-acceptable": "Non se atopou ningún formato correspondente. Tipos MIME soportadosː $1",
        "pagedata-bad-title": "Título non válido: $1.",
+       "unregistered-user-config": "Por motivos de seguridade as subpáxinas de usuario JavaScript, CSS e JSON non se poden cargar para usuarios non rexistrados.",
        "passwordpolicies": "Políticas de contrasinais",
+       "passwordpolicies-summary": "Esta é unha lista das políticas de contrasinais efectivas para os grupos de usuarios definidos nesta wiki.",
        "passwordpolicies-group": "Grupo",
        "passwordpolicies-policies": "Políticas",
        "passwordpolicies-policy-minimalpasswordlength": "O contrasinal debe conter como mínimo $1 {{PLURAL:$1|carácter|caracteres}}",
        "passwordpolicies-policy-minimumpasswordlengthtologin": "O contrasinal debe conter como mínimo $1 {{PLURAL:$1|carácter|caracteres}} para poder iniciar a sesión",
        "passwordpolicies-policy-passwordcannotmatchusername": "O contrasinal non pode coincidir co nome de usuario",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "O contrasinal non pode coincidir con contrasinais incluidos na lista negra",
-       "passwordpolicies-policy-maximalpasswordlength": "O contrasinal debe conter menos de $1 {{PLURAL:$1|carácter|caracteres}}"
+       "passwordpolicies-policy-maximalpasswordlength": "O contrasinal debe conter menos de $1 {{PLURAL:$1|carácter|caracteres}}",
+       "passwordpolicies-policy-passwordcannotbepopular": "O contrasinal non pode {{PLURAL:$1|ser o contrasinal máis habitual|estar na lista dos $1 máis habituais}}",
+       "easydeflate-invaliddeflate": "O contido fornecido non está debidamente comprimido"
 }
index d5d9435..7efe8d2 100644 (file)
        "imported-log-entries": "આયાતી $1 {{PLURAL:$1|log entry|log entries}}.",
        "importfailed": "આયાત નિષ્ફળ: <nowiki>$1</nowiki>",
        "importunknownsource": "અજ્ઞાત આયાતી સ્રોત પ્રકાર",
-       "importcantopen": "આયાતી ફાઈલ નખોલી શકાઈ",
+       "importcantopen": "આયાતી ફાઈલ ન ખોલી શકાઈ",
        "importbadinterwiki": "ખરાબ આંતરીકા વિકિ કડી",
        "importsuccess": "આયાત સંપૂર્ણ",
        "importnosources": "કોઇ પણ આંતર વિકિ સ્રોત જણાવાયા નથી અને સીધા ઇતિહાસ ફાઇલ ચડાવવા પર રોક લાગેલી છે.",
index 153d249..1babfda 100644 (file)
        "group-autoconfirmed": "Utenti autoconvalidati",
        "group-bot": "Bot",
        "group-sysop": "Amministratori",
+       "group-interface-admin": "Amministratori dell'interfaccia",
        "group-bureaucrat": "Burocrati",
        "group-suppress": "Soppressori",
        "group-all": "(tutti)",
        "group-autoconfirmed-member": "{{GENDER:$1|utente autoconvalidato|utente autoconvalidata|utente autoconvalidato/a}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|amministratore|amministratrice|amministratore/trice}}",
+       "group-interface-admin-member": "{{GENDER:$1|amministratore|amministratrice|amministratore/trice}} dell'interfaccia",
        "group-bureaucrat-member": "{{GENDER:$1|burocrate}}",
        "group-suppress-member": "{{GENDER:$1|soppressore|sopprimitrice}}",
        "grouppage-user": "{{ns:project}}:Utenti",
        "grouppage-autoconfirmed": "{{ns:project}}:Utenti autoconvalidati",
        "grouppage-bot": "{{ns:project}}:Bot",
        "grouppage-sysop": "{{ns:project}}:Amministratori",
+       "grouppage-interface-admin": "{{ns:project}}:Amministratori dell'interfaccia",
        "grouppage-bureaucrat": "{{ns:project}}:Burocrati",
        "grouppage-suppress": "{{ns:project}}:Soppressori",
        "right-read": "Legge pagine",
        "grant-createaccount": "Crea un'utenza",
        "grant-createeditmovepage": "Crea, modifica e sposta le pagine",
        "grant-delete": "Cancella pagine, versioni, e voci di registro",
-       "grant-editinterface": "Modifica il namespace MediaWiki e i CSS/JSON/JavaScript degli utenti",
+       "grant-editinterface": "Modifica il namespace MediaWiki e i JSON del sito/utenti",
        "grant-editmycssjs": "Modifica i CSS/JSON/JavaScript della tua utenza",
        "grant-editmyoptions": "Modifica le preferenze della tua utenza",
        "grant-editmywatchlist": "Modifica i tuoi osservati speciali",
        "uploadstash-zero-length": "Il file ha lunghezza zero.",
        "invalid-chunk-offset": "Offset della parte non valido.",
        "img-auth-accessdenied": "Accesso negato",
-       "img-auth-nopathinfo": "PATH_INFO mancante.\nIl server non è impostato per passare questa informazione.\nPotrebbe essere basato su CGI e non può supportare img_auth.\nVedi https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
+       "img-auth-nopathinfo": "Informazioni mancanti sul percorso.\nIl server deve essere è impostato per passare le variabili REQUEST_URI e/o PATH_INFO.\nSe è così, abilita $wgUsePathInfo.\nVedi https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "Il percorso richiesto non si trova nella directory di upload configurata.",
        "img-auth-badtitle": "Impossibile costruire un titolo valido da \"$1\".",
        "img-auth-nologinnWL": "Non si è effettuato l'accesso e \"$1\" non è nella whitelist.",
index f60fe3a..ef0f171 100644 (file)
        "group-autoconfirmed-member": "{{GENDER:$1|ავტომატურად დადასტურებული მომხმარებელი}}",
        "group-bot-member": "{{GENDER:$1|ბოტი}}",
        "group-sysop-member": "{{GENDER:$1|ადმინისტრატორი}}",
+       "group-interface-admin-member": "{{GENDER:$1|ინტერფეისის ადმინისტრატორი}}",
        "group-bureaucrat-member": "{{GENDER:$1|ბიუროკრატი}}",
        "group-suppress-member": "{{GENDER:$1|რევიზორები}}",
        "grouppage-user": "{{ns:project}}:მომხმარებლები",
index ba71f5a..9230c36 100644 (file)
        "diff-paragraph-moved-toold": "문단이 이동되었습니다. 오래된 위치로 이동하려면 클릭하십시오.",
        "difference-missing-revision": "문서 비교에서 {{PLURAL:$2|하나|$2개}}의 판($1)을 찾을 수 {{PLURAL:$2|없습니다}}.\n\n이 문제는 주로 삭제된 문서를 가리키는 오래된 문서 비교 링크로 인해 발생합니다.\n자세한 내용은 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 삭제 기록]에서 확인할 수 있습니다.",
        "searchresults": "검색 결과",
+       "search-filter-title-prefix": "제목이 \"$1\"로 시작하는 문서만 검색합니다",
        "search-filter-title-prefix-reset": "모든 문서 검색",
        "searchresults-title": "\"$1\"에 대한 검색 결과",
        "titlematches": "문서 제목 일치",
index aa91165..d8e0678 100644 (file)
        "group-autoconfirmed": "autobevestigde gebruikers",
        "group-bot": "bots",
        "group-sysop": "beheerders",
-       "group-interface-admin": "Interfacebeheerders",
+       "group-interface-admin": "Interfacemoderator",
        "group-bureaucrat": "bureaucraten",
        "group-suppress": "toezichthouders",
        "group-all": "(iedereen)",
        "group-autoconfirmed-member": "{{GENDER:$1|autobevestigde gebruiker}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|beheerder}}",
-       "group-interface-admin-member": "{{GENDER:$1|interfacebeheerder}}",
+       "group-interface-admin-member": "{{GENDER:$1|interfacemoderator}}",
        "group-bureaucrat-member": "{{GENDER:$1|bureaucraat}}",
        "group-suppress-member": "{{GENDER:$1|toezichthouder}}",
        "grouppage-user": "{{ns:project}}:Gebruikers",
        "grouppage-autoconfirmed": "{{ns:project}}:Geregistreerde gebruikers",
        "grouppage-bot": "{{ns:project}}:Bots",
        "grouppage-sysop": "{{ns:project}}:Beheerders",
-       "grouppage-interface-admin": "{{ns:project}}:Interfacebeheerders",
+       "grouppage-interface-admin": "{{ns:project}}:Interfacemoderator",
        "grouppage-bureaucrat": "{{ns:project}}:Bureaucraten",
        "grouppage-suppress": "{{ns:project}}:Toezicht",
        "right-read": "Pagina's bekijken",
        "right-editsitejson": "Wikibrede JSON bewerken",
        "right-editsitejs": "Wikibrede JavaScript bewerken",
        "right-editmyusercss": "Uw eigen CSS-pagina's bewerken",
-       "right-editmyuserjson": "Uw eigen JSONpagina's bewerken",
+       "right-editmyuserjson": "Uw eigen JSON-pagina's bewerken",
        "right-editmyuserjs": "Uw eigen JavaScriptpagina's bewerken",
        "right-viewmywatchlist": "Uw eigen volglijst bekijken",
        "right-editmywatchlist": "Uw eigen volglijst bewerken. Via sommige handelingen kunnen nog steeds pagina's toegevoegd worden, zelfs zonder deze bevoegdheid",
        "grant-createaccount": "Accounts aanmaken",
        "grant-createeditmovepage": "Pagina's aanmaken, bewerken en hernoemen",
        "grant-delete": "Pagina's, wijzigingen en logboekregels verwijderen",
-       "grant-editinterface": "De naamruimte MediaWiki en wikibrede JSON/JSON van gebruikers bewerken",
+       "grant-editinterface": "De MediaWiki-naamruimte en JSON van de wiki en gebruikers bewerken",
        "grant-editmycssjs": "Eigen CSS, JSON en JavaScript bewerken",
        "grant-editmyoptions": "Eigen voorkeuren instellen",
        "grant-editmywatchlist": "Eigen volglijst bewerken",
-       "grant-editsiteconfig": "Globale CSS/JS en gebruikers CSS/JS bewerken",
+       "grant-editsiteconfig": "CSS/JS van de wiki en gebruikers bewerken",
        "grant-editpage": "Bestaande pagina's bewerken",
        "grant-editprotected": "Beveiligde pagina's bewerken",
        "grant-highvolume": "Veel bewerkingen in korte tijd maken",
index 4b5d69f..3dd1344 100644 (file)
        "revdelete-show-file-submit": "Ja",
        "revdelete-selected-text": "{{PLURAL:$1|Vald versjon|Valde versjonar}} av [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Vald loggoppføring|Valde loggoppføringar}}:",
+       "revdelete-text-text": "Sletta versjonar vil framleis syna i historikken til sida, men delar av innhaldet deira vil vera utilgjengeleg for ålmenta.",
+       "revdelete-text-others": "Andre administratorar vil framleis ha tilgang til det løynde innhaldet og kan attoppretta det, minder vidare avgrensingar er sette.",
        "revdelete-confirm": "Stadfest at du ynskjer å gjera dette, at du skjønar konsekvensane, og at du gjer det i samsvar med [[{{MediaWiki:Policy-url}}|retningslinene]].",
        "revdelete-suppress-text": "Løyning av sideversjonar bør '''berre''' nyttast i desse tilfella:\n* Mogeleg ærekrenkjande informasjon\n* Upassanda personleg informasjon\n*: ''heimeadresser og -telefonnummer,  personnummer, osb.''",
        "revdelete-legend": "Set avgrensing av synlegdom",
index 2ba449a..e8740e6 100644 (file)
        "grouppage-bureaucrat": "{{doc-group|bureaucrat|page}}",
        "grouppage-suppress": "{{doc-group|suppress|page}}\n{{Identical|Suppress}}",
        "right-read": "{{doc-right|read}}\nBasic right to read any page.",
-       "right-edit": "{{doc-right|edit}}\nBasic right to edit pages that are not protected.\n{{Identical|Edit page}}",
+       "right-edit": "Description of edit right",
        "right-createpage": "{{doc-right|createpage}}\nBasic right to create pages. The right to edit discussion/talk pages is {{msg-mw|right-createtalk}}.",
        "right-createtalk": "{{doc-right|createtalk}}\nBasic right to create discussion/talk pages. The right to edit other pages is {{msg-mw|right-createpage}}.",
        "right-createaccount": "{{doc-right|createaccount}}\nThe right to [[Special:CreateAccount|create a user account]].",
index 91b9c2e..07cf146 100644 (file)
        "uploadnologin": "داخل ٿيل ناھيو",
        "uploadnologintext": "فائيل چاڙهڻ لاءِ $1.",
        "uploaderror": "چاڙھ چُڪَ",
+       "uploadtext": "فائل چاڙهڻ لاءِ هيٺيون فارم استعمال ڪيو.\nپراڻا چاڙهيل فائل ڏسڻ يا ڳولڻ لاءِ [[Special:FileList|چاڙهيل فائلن جي فهرست]] تي وڃو، ٻهير چاڙهيل فائل [[Special:Log/upload|چاڙهيل لاگ]] ۽ ختم ڪيل [[Special:Log/delete|ڊاٺ لاگ]] تي ڏسي سگھجن ٿا.\n\nفائل جي استعمال لاءِ هيٺ ڏيکاريل طريقو استعمال ڪري سگھجي ٿو:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:فائل جو نالو.jpg]]</nowiki></code></strong> فائل جي مڪمل استعمال لاءِ\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:فائل جو نالو.png|200px|thumb|left|متبادل اکر]]</nowiki></code></strong> هن جي مدد سان تصوير جي سائيز ڏئي سگھجي ٿي جيئن 200 پگزل\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> فائل کي ڏيکارڻ کان بغير شامل ڪرڻ",
        "uploadlogpage": "چاڙھ لاگ",
        "filename": "فائيل نانءُ",
        "filedesc": "خلاصو",
index 8a1fe35..963b58e 100644 (file)
        "speciallogtitlelabel": "Циљ (наслов или {{ns:user}}:корисничко име):",
        "log": "Дневници",
        "logeventslist-submit": "Прикажи",
+       "logeventslist-more-filters": "Прикажи додатне дневнике:",
        "logeventslist-patrol-log": "Дневник патролирања",
        "logeventslist-tag-log": "Дневник ознака",
        "all-logs-page": "Сви јавни дневници",
index 578d73f..8f4753c 100644 (file)
        "speciallogtitlelabel": "Cilj (naslov ili {{ns:user}}:korisničko ime):",
        "log": "Dnevnici",
        "logeventslist-submit": "Prikaži",
+       "logeventslist-more-filters": "Prikaz dodatnih dnevnika:",
        "all-logs-page": "Svi javni dnevnici",
        "alllogstext": "Skupni prikaz svih dostupnih istorija ovog vikija.\nMožete suziti prikaz odabirući vrstu istorije, korisničkog imena ili tražene stranice.",
        "logempty": "Nema pronađenih unosa u dnevniku.",
index 3e9d359..92c9f29 100644 (file)
        "botpasswords-insert-failed": "బాట్ పేరు \"$1\"ను చేర్చలేకపోయాం. దీన్ని ఇంతకు ముందే చేర్చారా ఏంటి?",
        "botpasswords-update-failed": "బాట్ పేరు \"$1\" ను తాజాకరించలేకపోయాం. దీన్ని తొలగించారా?",
        "botpasswords-created-title": "బాట్ సంకేతపదాన్ని సృష్టించాం",
-       "botpasswords-created-body": "వాడుకరి \"$2\" కు చెందిన \"$1\" అనే బాట్‌కు బాట్ సంకేతపదాన్ని సృష్టించాం.",
+       "botpasswords-created-body": "{{GENDER:$2|వాడుకరి}} \"$2\" కు చెందిన \"$1\" అనే బాట్‌కు బాట్ సంకేతపదాన్ని సృష్టించాం.",
        "botpasswords-updated-title": "బాట్ సంకేతపదాన్ని తాజాకరించాం",
-       "botpasswords-updated-body": "వాడుకరి \"$2\" కు చెందిన \"$1\" అనే బాట్‌ యొక్క బాట్ సంకేతపదాన్ని తాజాకరించాం.",
+       "botpasswords-updated-body": "{{GENDER:$2|వాడుకరి}} \"$2\" కు చెందిన \"$1\" అనే బాట్‌ యొక్క బాట్ సంకేతపదాన్ని తాజాకరించాం.",
        "botpasswords-deleted-title": "బాట్ సంకేతపదాన్ని తొలగించాం",
-       "botpasswords-deleted-body": "వాడుకరి \"$2\" కు చెందిన \"$1\" అనే బాట్‌ యొక్క బాట్ సంకేతపదాన్ని తొలగించాం.",
+       "botpasswords-deleted-body": "{{GENDER:$2|వాడుకరి}} \"$2\" కు చెందిన \"$1\" అనే బాట్‌ యొక్క బాట్ సంకేతపదాన్ని తొలగించాం.",
        "botpasswords-newpassword": "<strong>$1</strong> తో లాగినయేందుకు కొత్త సంకేతపదం <strong>$2</strong>. <em>భావి ఉపయోగం కోసం దీన్ని జాగ్రత్త చేసుకోండి.</em><br> (లాగిన్ పేరుగా వాడుకరిపేరే ఉండాల్సిన పాత బాట్‌ల విషయంలో <strong>$3</strong> ను వాడుకరిపేరుగాను, <strong>$4</strong> ను సంకేతపదంగానూ వాడుకోవచ్చు.)",
+       "botpasswords-invalid-name": "ఇచ్చిన వాడుకరిపేరులో బాట్ సంకేతపదం సెపరేటరు (\"$1\") లేదు.",
        "botpasswords-not-exist": "వాడుకరి \"$1\" కి \"$2\" అనే బాట్ సంకేతపదం లేదు.",
+       "botpasswords-needs-reset": "{{GENDER:$1|వాడుకరి}}కి చెందిన బాట్ పేరు, \"$2\", యొక్క బాట్ సంకేతపదాన్ని- \"$1\" - మార్చాలి.",
        "resetpass_forbidden": "సంకేతపదాలను మార్చటం కుదరదు",
        "resetpass_forbidden-reason": "సంకేతపదాలు మార్చజాలరు: $1",
        "resetpass-no-info": "ఈ పేజీని నేరుగా చూడటానికి మీరు లాగినయి వుండాలి.",
index 20af4c0..8bc3135 100644 (file)
        "uctop": "(موجودہ نسخہ)",
        "month": "مہینہ (اور اُس سے قبل):",
        "year": "سال (اور اُس سے قبل):",
+       "date": "تاریخ سے (اور اس سے قبل)",
        "sp-contributions-newbies": "محض جدید صارفین کی شراکتیں دکھائیں",
        "sp-contributions-newbies-sub": "جدید صارفین کے",
        "sp-contributions-newbies-title": "جدید صارفین کی شراکتیں",
index 1d2dad0..3f2dbc6 100644 (file)
                        "EagerLin",
                        "Deathkon",
                        "RyRubyy",
-                       "Wxyveronica"
+                       "Wxyveronica",
+                       "夢蝶葬花"
                ]
        },
        "tog-underline": "链接下划线:",
        "customcssprotected": "您没有权限编辑此CSS页面,因为它包含另一位用户的个人设置。",
        "customjsonprotected": "您没有权限编辑此JSON页面,因为它包含另一位用户的个人设置。",
        "customjsprotected": "您没有权限编辑此JavaScript页面,因为它包含另一位用户的个人设置。",
+       "sitecssprotected": "您无权编辑此CSS页面,因为它可能会影响所有访问者",
+       "sitejsonprotected": "您无权编辑此JSON页面,因为它可能会影响所有访问者",
+       "sitejsprotected": "您无权编辑此JavaScript页面,因为它可能会影响所有访问者",
        "mycustomcssprotected": "您没有权限编辑这个 CSS 页面。",
        "mycustomjsonprotected": "您没有权限编辑这个JSON页面。",
        "mycustomjsprotected": "您没有权限编辑这个 JavaScript 页面。",
        "group-autoconfirmed": "自动确认用户",
        "group-bot": "机器人",
        "group-sysop": "管理员",
+       "group-interface-admin": "界面管理员",
        "group-bureaucrat": "行政员",
        "group-suppress": "Flow监督员",
        "group-all": "(所有)",
        "group-autoconfirmed-member": "{{GENDER:$1|自动确认用户}}",
        "group-bot-member": "{{GENDER:$1|机器人}}",
        "group-sysop-member": "{{GENDER:$1|管理员}}",
+       "group-interface-admin-member": "{{GENDER:$1|界面编辑者}}",
        "group-bureaucrat-member": "{{GENDER:$1|行政员}}",
        "group-suppress-member": "{{GENDER:$1|Flow监督员}}",
        "grouppage-user": "{{ns:project}}:用户",
        "grouppage-autoconfirmed": "{{ns:project}}:自动确认用户",
        "grouppage-bot": "{{ns:project}}:机器人",
        "grouppage-sysop": "{{ns:project}}:管理员",
+       "grouppage-interface-admin": "{{ns:project}}:界面编辑者",
        "grouppage-bureaucrat": "{{ns:project}}:行政员",
        "grouppage-suppress": "{{ns:project}}:监督",
        "right-read": "阅读页面",
        "right-editusercss": "编辑其他用户的CSS文件",
        "right-edituserjson": "编辑其他用户的JSON文件",
        "right-edituserjs": "编辑其他用户的JavaScript文件",
+       "right-editsitecss": "编辑全站CSS",
+       "right-editsitejson": "编辑全站JSON",
+       "right-editsitejs": "编辑全站JavaScript",
        "right-editmyusercss": "编辑您的用户CSS文件",
        "right-editmyuserjson": "编辑您的用户JSON文件",
        "right-editmyuserjs": "编辑您的用户JavaScript文件",
index 38a1d68..1ed5e95 100644 (file)
@@ -26,16 +26,19 @@ class ApiQueryRevisionsTest extends ApiTestCase {
                        'prop' => 'revisions',
                        'titles' => $pageName,
                        'rvprop' => 'content',
+                       'rvslots' => 'main',
                ] );
                $this->assertArrayHasKey( 'query', $apiResult[0] );
                $this->assertArrayHasKey( 'pages', $apiResult[0]['query'] );
                foreach ( $apiResult[0]['query']['pages'] as $page ) {
                        $this->assertArrayHasKey( 'revisions', $page );
                        foreach ( $page['revisions'] as $revision ) {
-                               $this->assertArrayHasKey( 'contentformat', $revision,
+                               $this->assertArrayHasKey( 'slots', $revision );
+                               $this->assertArrayHasKey( 'main', $revision['slots'] );
+                               $this->assertArrayHasKey( 'contentformat', $revision['slots']['main'],
                                        'contentformat should be included when asking content so client knows how to interpret it'
                                );
-                               $this->assertArrayHasKey( 'contentmodel', $revision,
+                               $this->assertArrayHasKey( 'contentmodel', $revision['slots']['main'],
                                        'contentmodel should be included when asking content so client knows how to interpret it'
                                );
                        }