Merge "Move watcheditem classes to watcheditem directory"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sun, 12 Nov 2017 05:57:27 +0000 (05:57 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sun, 12 Nov 2017 05:57:28 +0000 (05:57 +0000)
67 files changed:
RELEASE-NOTES-1.30
RELEASE-NOTES-1.31
autoload.php
composer.json
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/Html.php
includes/Setup.php
includes/Title.php
includes/api/i18n/ko.json
includes/api/i18n/nb.json
includes/db/MWLBFactory.php
includes/deferred/HTMLCacheUpdate.php
includes/deferred/LinksUpdate.php
includes/filerepo/file/File.php
includes/filerepo/file/LocalFile.php
includes/installer/i18n/eu.json
includes/jobqueue/jobs/HTMLCacheUpdateJob.php
includes/libs/HashRing.php
includes/page/PageArchive.php
includes/page/WikiFilePage.php
includes/page/WikiPage.php
includes/profiler/ProfilerFunctions.php [deleted file]
languages/i18n/ast.json
languages/i18n/be-tarask.json
languages/i18n/de.json
languages/i18n/et.json
languages/i18n/fr.json
languages/i18n/ga.json
languages/i18n/gl.json
languages/i18n/hu.json
languages/i18n/la.json
languages/i18n/lad.json
languages/i18n/lb.json
languages/i18n/lki.json
languages/i18n/lv.json
languages/i18n/map-bms.json
languages/i18n/mr.json
languages/i18n/nb.json
languages/i18n/nl.json
languages/i18n/ps.json
languages/i18n/pt-br.json
languages/i18n/sat.json
languages/i18n/shn.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/messages/MessagesMwl.php
maintenance/checkComposerLockUpToDate.php
maintenance/populateRecentChangesSource.php
maintenance/userOptions.inc [deleted file]
maintenance/userOptions.php
resources/src/mediawiki.action/mediawiki.action.history.styles.css
resources/src/mediawiki.skinning/interface.css
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.styles.less
resources/src/mediawiki/mediawiki.notification.css
tests/common/TestsAutoLoader.php
tests/parser/parserTests.txt
tests/phpunit/autoload.ide.php
tests/phpunit/includes/RevisionContentHandlerDbTest.php [new file with mode: 0644]
tests/phpunit/includes/RevisionDbTestBase.php [new file with mode: 0644]
tests/phpunit/includes/RevisionIntegrationTest.php [deleted file]
tests/phpunit/includes/RevisionNoContentHandlerDbTest.php [new file with mode: 0644]
tests/phpunit/includes/RevisionTest.php [new file with mode: 0644]
tests/phpunit/includes/RevisionUnitTest.php [deleted file]

index f79ae83..d92c38c 100644 (file)
@@ -80,12 +80,18 @@ section).
 === External library changes in 1.30 ===
 
 ==== Upgraded external libraries ====
-* mediawiki/mediawiki-codesniffer updated to 0.8.1.
-* wikimedia/composer-merge-plugin updated to 1.4.1.
+* Updated justinrainbow/json-schema from v3.0 to v5.2.
+* Updated mediawiki/mediawiki-codesniffer from v0.7.2 to v0.12.0.
+* Updated wikimedia/composer-merge-plugin from v1.4.0 to v1.4.1.
+* Updated wikimedia/relpath from v1.0.3 to v2.0.0.
+* Updated OOjs from v2.0.0 to v2.1.0.
+* Updated OOUI from v0.21.1 to v0.23.0.
+* Updated QUnit from v1.23.1 to v2.4.0.
 
 ==== New external libraries ====
 * The class \TestingAccessWrapper has been moved to the external library
   wikimedia/testing-access-wrapper and renamed \Wikimedia\TestingAccessWrapper.
+* Purtle, a fast, lightweight RDF generator.
 
 ==== Removed and replaced external libraries ====
 * …
index 9a4c74c..026de58 100644 (file)
@@ -24,7 +24,7 @@ production.
 === External library changes in 1.31 ===
 
 ==== Upgraded external libraries ====
-* 
+* Updated dev dependancy phpunit/phpunit from v4.8.35 to v4.8.36.
 
 ==== New external libraries ====
 * …
index 5496e3c..edac2c5 100644 (file)
@@ -1568,7 +1568,7 @@ $wgAutoloadLocalClasses = [
        'UserMailer' => __DIR__ . '/includes/mail/UserMailer.php',
        'UserNamePrefixSearch' => __DIR__ . '/includes/user/UserNamePrefixSearch.php',
        'UserNotLoggedIn' => __DIR__ . '/includes/exception/UserNotLoggedIn.php',
-       'UserOptions' => __DIR__ . '/maintenance/userOptions.inc',
+       'UserOptionsMaintenance' => __DIR__ . '/maintenance/userOptions.php',
        'UserPasswordPolicy' => __DIR__ . '/includes/password/UserPasswordPolicy.php',
        'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
index 7031cad..71c9398 100644 (file)
@@ -58,7 +58,7 @@
                "monolog/monolog": "~1.22.1",
                "nikic/php-parser": "2.1.0",
                "nmred/kafka-php": "0.1.5",
-               "phpunit/phpunit": "4.8.35",
+               "phpunit/phpunit": "4.8.36",
                "psy/psysh": "0.8.11",
                "wikimedia/avro": "1.7.7",
                "wikimedia/testing-access-wrapper": "~1.0",
index d9f032c..3cd7ef1 100644 (file)
@@ -5785,7 +5785,7 @@ $wgPasswordAttemptThrottle = [
 ];
 
 /**
- * @var Array Map of (grant => right => boolean)
+ * @var array Map of (grant => right => boolean)
  * Users authorize consumers (like Apps) to act on their behalf but only with
  * a subset of the user's normal account rights (signed off on by the user).
  * The possible rights to grant to a consumer are bundled into groups called
@@ -5887,7 +5887,7 @@ $wgGrantPermissions['createaccount']['createaccount'] = true;
 $wgGrantPermissions['privateinfo']['viewmyprivateinfo'] = true;
 
 /**
- * @var Array Map of grants to their UI grouping
+ * @var array Map of grants to their UI grouping
  * @since 1.27
  */
 $wgGrantPermissionGroups = [
index 4260c99..ff224c5 100644 (file)
@@ -3288,7 +3288,7 @@ class EditPage {
 
        protected function showFormBeforeText() {
                $out = $this->context->getOutput();
-               $out->addHTML( Html::hidden( 'wpSection', htmlspecialchars( $this->section ) ) );
+               $out->addHTML( Html::hidden( 'wpSection', $this->section ) );
                $out->addHTML( Html::hidden( 'wpStarttime', $this->starttime ) );
                $out->addHTML( Html::hidden( 'wpEdittime', $this->edittime ) );
                $out->addHTML( Html::hidden( 'editRevId', $this->editRevId ) );
index 1cff881..404d115 100644 (file)
@@ -3487,3 +3487,37 @@ function wfArrayPlus2d( array $baseArray, array $newValues ) {
 
        return $baseArray;
 }
+
+/**
+ * Get system resource usage of current request context.
+ * Invokes the getrusage(2) system call, requesting RUSAGE_SELF if on PHP5
+ * or RUSAGE_THREAD if on HHVM. Returns false if getrusage is not available.
+ *
+ * @since 1.24
+ * @return array|bool Resource usage data or false if no data available.
+ */
+function wfGetRusage() {
+       if ( !function_exists( 'getrusage' ) ) {
+               return false;
+       } elseif ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
+               return getrusage( 2 /* RUSAGE_THREAD */ );
+       } else {
+               return getrusage( 0 /* RUSAGE_SELF */ );
+       }
+}
+
+/**
+ * Begin profiling of a function
+ * @param string $functionname Name of the function we will profile
+ * @deprecated since 1.25
+ */
+function wfProfileIn( $functionname ) {
+}
+
+/**
+ * Stop profiling of a function
+ * @param string $functionname Name of the function we have profiled
+ * @deprecated since 1.25
+ */
+function wfProfileOut( $functionname = 'missing' ) {
+}
index 8fe4dbe..0988b05 100644 (file)
@@ -544,28 +544,7 @@ class Html {
                        if ( in_array( $key, self::$boolAttribs ) ) {
                                $ret .= " $key=\"\"";
                        } else {
-                               // Apparently we need to entity-encode \n, \r, \t, although the
-                               // spec doesn't mention that.  Since we're doing strtr() anyway,
-                               // we may as well not call htmlspecialchars().
-                               // @todo FIXME: Verify that we actually need to
-                               // escape \n\r\t here, and explain why, exactly.
-                               // We could call Sanitizer::encodeAttribute() for this, but we
-                               // don't because we're stubborn and like our marginal savings on
-                               // byte size from not having to encode unnecessary quotes.
-                               // The only difference between this transform and the one by
-                               // Sanitizer::encodeAttribute() is ' is not encoded.
-                               $map = [
-                                       '&' => '&amp;',
-                                       '"' => '&quot;',
-                                       '>' => '&gt;',
-                                       // '<' allegedly allowed per spec
-                                       // but breaks some tools if not escaped.
-                                       "<" => '&lt;',
-                                       "\n" => '&#10;',
-                                       "\r" => '&#13;',
-                                       "\t" => '&#9;'
-                               ];
-                               $ret .= " $key=$quote" . strtr( $value, $map ) . $quote;
+                               $ret .= " $key=$quote" . Sanitizer::encodeAttribute( $value ) . $quote;
                        }
                }
                return $ret;
index e4396ba..4c281b1 100644 (file)
@@ -37,8 +37,11 @@ if ( !defined( 'MEDIAWIKI' ) ) {
  * Pre-config setup: Before loading LocalSettings.php
  */
 
-// Grab profiling functions
-require_once "$IP/includes/profiler/ProfilerFunctions.php";
+// Get profiler configuraton
+$wgProfiler = [];
+if ( file_exists( "$IP/StartProfiler.php" ) ) {
+       require "$IP/StartProfiler.php";
+}
 
 // Start the autoloader, so that extensions can derive classes from core files
 require_once "$IP/includes/AutoLoader.php";
@@ -46,12 +49,6 @@ require_once "$IP/includes/AutoLoader.php";
 // Load up some global defines
 require_once "$IP/includes/Defines.php";
 
-// Start the profiler
-$wgProfiler = [];
-if ( file_exists( "$IP/StartProfiler.php" ) ) {
-       require "$IP/StartProfiler.php";
-}
-
 // Load default settings
 require_once "$IP/includes/DefaultSettings.php";
 
index d043b44..829be44 100644 (file)
@@ -4622,9 +4622,11 @@ class Title implements LinkTarget {
         * on the number of links. Typically called on create and delete.
         */
        public function touchLinks() {
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'pagelinks' ) );
+               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'pagelinks', 'page-touch' ) );
                if ( $this->getNamespace() == NS_CATEGORY ) {
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'categorylinks' ) );
+                       DeferredUpdates::addUpdate(
+                               new HTMLCacheUpdate( $this, 'categorylinks', 'category-touch' )
+                       );
                }
        }
 
index 0410ddf..a2dc344 100644 (file)
        "apihelp-import-param-xml": "업로드한 XML 파일.",
        "apihelp-linkaccount-summary": "서드파티 제공자의 계정을 현재 사용자와 연결합니다.",
        "apihelp-login-summary": "로그인한 다음 인증 쿠키를 가져옵니다.",
+       "apihelp-login-extended-description": "이 동작은 [[Special:BotPasswords|특수:BotPasswords]]와 함께 사용해야만 합니다. 주 계정 로그인을 위해 사용하는 것은 권장되지 않으며 경고 없이 실패할 수 있습니다. 주 계정에 안전하게 로그인하려면 <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>을 사용하십시오.",
        "apihelp-login-param-name": "사용자 이름.",
        "apihelp-login-param-password": "비밀번호.",
        "apihelp-login-param-domain": "도메인 (선택).",
index 1c8877c..2e89ea3 100644 (file)
        "apihelp-options-example-complex": "Tilbakestill alle innstillinger, og sett så <kbd>skin</kbd> og <kbd>nickname</kbd>.",
        "apihelp-paraminfo-summary": "Hent informasjon om API-moduler.",
        "apihelp-paraminfo-param-helpformat": "Format for hjelpestrenger.",
+       "apihelp-parse-param-prop": "Hvilke informasjonsdeler som skal hentes:",
+       "apihelp-parse-paramvalue-prop-categorieshtml": "Gir HTML-versjonen av kategoriene.",
+       "apihelp-parse-paramvalue-prop-headitems": "Gir elementer som skal puttes i <code>&lt;head&gt;</code>-taggen til siden.",
+       "apihelp-patrol-summary": "Patruljer en side eller revisjon.",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Legger til filens tittel.",
        "apihelp-query+allfileusages-param-limit": "Hvor mange elementer som skal returneres totalt.",
        "apihelp-query+allfileusages-param-dir": "Retningen det skal listes opp i.",
index 5196ac2..aa1918d 100644 (file)
@@ -142,16 +142,18 @@ abstract class MWLBFactory {
                        }
                }
 
+               $services = MediaWikiServices::getInstance();
+
                // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
-               $sCache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
+               $sCache = $services->getLocalServerObjectCache();
                if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
                        $lbConf['srvCache'] = $sCache;
                }
-               $cCache = ObjectCache::getLocalClusterInstance();
-               if ( $cCache->getQoS( $cCache::ATTR_EMULATION ) > $cCache::QOS_EMULATION_SQL ) {
-                       $lbConf['memStash'] = $cCache;
+               $mStash = $services->getMainObjectStash();
+               if ( $mStash->getQoS( $mStash::ATTR_EMULATION ) > $mStash::QOS_EMULATION_SQL ) {
+                       $lbConf['memStash'] = $mStash;
                }
-               $wCache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+               $wCache = $services->getMainWANObjectCache();
                if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
                        $lbConf['wanCache'] = $wCache;
                }
index db3790f..29846bf 100644 (file)
@@ -26,7 +26,7 @@
  *
  * @ingroup Cache
  */
-class HTMLCacheUpdate implements DeferrableUpdate {
+class HTMLCacheUpdate extends DataUpdate {
        /** @var Title */
        public $mTitle;
 
@@ -36,14 +36,24 @@ class HTMLCacheUpdate implements DeferrableUpdate {
        /**
         * @param Title $titleTo
         * @param string $table
+        * @param string $causeAction Triggering action
+        * @param string $causeAgent Triggering user
         */
-       function __construct( Title $titleTo, $table ) {
+       function __construct(
+               Title $titleTo, $table, $causeAction = 'unknown', $causeAgent = 'unknown'
+       ) {
                $this->mTitle = $titleTo;
                $this->mTable = $table;
+               $this->causeAction = $causeAction;
+               $this->causeAgent = $causeAgent;
        }
 
        public function doUpdate() {
-               $job = HTMLCacheUpdateJob::newForBacklinks( $this->mTitle, $this->mTable );
+               $job = HTMLCacheUpdateJob::newForBacklinks(
+                       $this->mTitle,
+                       $this->mTable,
+                       [ 'causeAction' => $this->getCauseAction(), 'causeAgent' => $this->getCauseAgent() ]
+               );
 
                JobQueueGroup::singleton()->lazyPush( $job );
        }
index c27826d..8913642 100644 (file)
@@ -1055,7 +1055,9 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                                        $inv = [ $inv ];
                                }
                                foreach ( $inv as $table ) {
-                                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->mTitle, $table ) );
+                                       DeferredUpdates::addUpdate(
+                                               new HTMLCacheUpdate( $this->mTitle, $table, 'page-props' )
+                                       );
                                }
                        }
                }
index 32f4504..54bd0a5 100644 (file)
@@ -1445,7 +1445,9 @@ abstract class File implements IDBAccessObject {
                // Purge cache of all pages using this file
                $title = $this->getTitle();
                if ( $title ) {
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'imagelinks' ) );
+                       DeferredUpdates::addUpdate(
+                               new HTMLCacheUpdate( $title, 'imagelinks', 'file-purge' )
+                       );
                }
        }
 
index 44c90af..bb12515 100644 (file)
@@ -1740,7 +1740,9 @@ class LocalFile extends File {
                }
 
                # Invalidate cache for all pages using this file
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->getTitle(), 'imagelinks' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $this->getTitle(), 'imagelinks', 'file-upload' )
+               );
 
                return Status::newGood();
        }
index 4d6095c..0925091 100644 (file)
        "config-missing-db-host": "\"{{int:config-db-host}}\"-rentzako balioa sartu behar duzu.",
        "config-missing-db-server-oracle": "\"{{int:config-db-host-oracle}}\"-rentzako balioa sartu behar duzu.",
        "config-invalid-db-server-oracle": "\"$1\" TNS datu basea baliogabea.\nErabili \"TNS izena\" edo \"Konektagarritasun erraza\" katea ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Oracle Naming Methods]).",
+       "config-invalid-db-name": "Datu-basearen izen okerra \"$1\"\nErabil ezazu ASCII letrak bakarrik (a-z, A-Z), zenbakiak (09), behe-gidoiak (_) eta gidoiak (-)",
+       "config-invalid-db-prefix": "Datu-basearen aurrizki okerra \"$1\"\nErabil ezazu ASCII letrak bakarrik (a-z, A-Z) behe-gidoiak (_) eta gidoiak (-)",
        "config-connection-error": "$1\n\nHost-a, erabiltzaile izena eta pasahitza egiaztatu eta saiatu berriro.",
+       "config-invalid-schema": "MediaWikiko eskema okerra \"$1\"\nErabil ezazu ASCII letrak bakarrik (a-z, A-Z) behe-gidoiak (_).",
        "config-db-sys-create-oracle": "Instalatzaileak bakarrik jasaten du SYSBDA kontu bat erabiltzaile kontu berri bat sortzeko.",
        "config-db-sys-user-exists-oracle": "$1 erabiltzaile kontua dagoeneko existitzen da. SYSDBA kontu berri bat sortzeko erabili daiteke soilik!",
        "config-postgres-old": "PostgreSQL $1 edo berriagoa behar da. Zuk $2 badaukazu.",
index 4d75cb3..34028df 100644 (file)
@@ -47,14 +47,16 @@ class HTMLCacheUpdateJob extends Job {
                        // Multiple pages per job make matches unlikely
                        !( isset( $params['pages'] ) && count( $params['pages'] ) != 1 )
                );
+               $this->params += [ 'causeAction' => 'unknown', 'causeAgent' => 'unknown' ];
        }
 
        /**
         * @param Title $title Title to purge backlink pages from
         * @param string $table Backlink table name
+        * @param array $params Additional job parameters
         * @return HTMLCacheUpdateJob
         */
-       public static function newForBacklinks( Title $title, $table ) {
+       public static function newForBacklinks( Title $title, $table, $params = [] ) {
                return new self(
                        $title,
                        [
@@ -62,7 +64,7 @@ class HTMLCacheUpdateJob extends Job {
                                'recursive' => true
                        ] + Job::newRootJobParams( // "overall" refresh links job info
                                "htmlCacheUpdate:{$table}:{$title->getPrefixedText()}"
-                       )
+                       ) + $params
                );
        }
 
@@ -75,6 +77,11 @@ class HTMLCacheUpdateJob extends Job {
 
                // Job to purge all (or a range of) backlink pages for a page
                if ( !empty( $this->params['recursive'] ) ) {
+                       // Carry over information for de-duplication
+                       $extraParams = $this->getRootJobParams();
+                       // Carry over cause information for logging
+                       $extraParams['causeAction'] = $this->params['causeAction'];
+                       $extraParams['causeAgent'] = $this->params['causeAgent'];
                        // Convert this into no more than $wgUpdateRowsPerJob HTMLCacheUpdateJob per-title
                        // jobs and possibly a recursive HTMLCacheUpdateJob job for the rest of the backlinks
                        $jobs = BacklinkJobUtils::partitionBacklinkJob(
@@ -82,7 +89,7 @@ class HTMLCacheUpdateJob extends Job {
                                $wgUpdateRowsPerJob,
                                $wgUpdateRowsPerQuery, // jobs-per-title
                                // Carry over information for de-duplication
-                               [ 'params' => $this->getRootJobParams() ]
+                               [ 'params' => $extraParams ]
                        );
                        JobQueueGroup::singleton()->push( $jobs );
                // Job to purge pages for a set of titles
index f61c139..21558f7 100644 (file)
  * @since 1.22
  */
 class HashRing {
-       /** @var Array (location => weight) */
+       /** @var array (location => weight) */
        protected $sourceMap = [];
-       /** @var Array (location => (start, end)) */
+       /** @var array (location => (start, end)) */
        protected $ring = [];
 
        /** @var HashRing|null */
        protected $liveRing;
-       /** @var Array (location => UNIX timestamp) */
+       /** @var array (location => UNIX timestamp) */
        protected $ejectionExpiries = [];
        /** @var int UNIX timestamp */
        protected $ejectionNextExpiry = INF;
index 209551b..c03d6b2 100644 (file)
@@ -764,7 +764,9 @@ class PageArchive {
                        Hooks::run( 'ArticleUndelete',
                                [ &$this->title, $created, $comment, $oldPageId, $restoredPages ] );
                        if ( $this->title->getNamespace() == NS_FILE ) {
-                               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->title, 'imagelinks' ) );
+                               DeferredUpdates::addUpdate(
+                                       new HTMLCacheUpdate( $this->title, 'imagelinks', 'file-restore' )
+                               );
                        }
                }
 
index 972a397..4c2ebdc 100644 (file)
@@ -173,7 +173,9 @@ class WikiFilePage extends WikiPage {
 
                if ( $this->mFile->exists() ) {
                        wfDebug( 'ImagePage::doPurge purging ' . $this->mFile->getName() . "\n" );
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->mTitle, 'imagelinks' ) );
+                       DeferredUpdates::addUpdate(
+                               new HTMLCacheUpdate( $this->mTitle, 'imagelinks', 'file-purge' )
+                       );
                } else {
                        wfDebug( 'ImagePage::doPurge no image for '
                                . $this->mFile->getName() . "; limiting purge to cache only\n" );
index 95b7be2..8b34928 100644 (file)
@@ -3317,7 +3317,9 @@ class WikiPage implements Page, IDBAccessObject {
                MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
 
                // Invalidate caches of articles which include this page
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'templatelinks' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $title, 'templatelinks', 'page-create' )
+               );
 
                if ( $title->getNamespace() == NS_CATEGORY ) {
                        // Load the Category object, which will schedule a job to create
@@ -3355,7 +3357,9 @@ class WikiPage implements Page, IDBAccessObject {
 
                // Images
                if ( $title->getNamespace() == NS_FILE ) {
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'imagelinks' ) );
+                       DeferredUpdates::addUpdate(
+                               new HTMLCacheUpdate( $title, 'imagelinks', 'page-delete' )
+                       );
                }
 
                // User talk pages
@@ -3378,10 +3382,14 @@ class WikiPage implements Page, IDBAccessObject {
         */
        public static function onArticleEdit( Title $title, Revision $revision = null ) {
                // Invalidate caches of articles which include this page
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'templatelinks' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $title, 'templatelinks', 'page-edit' )
+               );
 
                // Invalidate the caches of all pages which redirect here
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'redirect' ) );
+               DeferredUpdates::addUpdate(
+                       new HTMLCacheUpdate( $title, 'redirect', 'page-edit' )
+               );
 
                MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
 
diff --git a/includes/profiler/ProfilerFunctions.php b/includes/profiler/ProfilerFunctions.php
deleted file mode 100644 (file)
index cc71630..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-/**
- * Core profiling functions. Have to exist before basically anything.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Profiler
- */
-
-/**
- * Get system resource usage of current request context.
- * Invokes the getrusage(2) system call, requesting RUSAGE_SELF if on PHP5
- * or RUSAGE_THREAD if on HHVM. Returns false if getrusage is not available.
- *
- * @since 1.24
- * @return array|bool Resource usage data or false if no data available.
- */
-function wfGetRusage() {
-       if ( !function_exists( 'getrusage' ) ) {
-               return false;
-       } elseif ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
-               return getrusage( 2 /* RUSAGE_THREAD */ );
-       } else {
-               return getrusage( 0 /* RUSAGE_SELF */ );
-       }
-}
-
-/**
- * Begin profiling of a function
- * @param string $functionname Name of the function we will profile
- * @deprecated since 1.25
- */
-function wfProfileIn( $functionname ) {
-}
-
-/**
- * Stop profiling of a function
- * @param string $functionname Name of the function we have profiled
- * @deprecated since 1.25
- */
-function wfProfileOut( $functionname = 'missing' ) {
-}
index e3bd03b..46ea545 100644 (file)
        "uploadstash-file-not-found-no-thumb": "Nun pudo llograse la miniatura.",
        "uploadstash-file-not-found-no-local-path": "Nun hai una ruta llocal pal elementu redimensionáu.",
        "uploadstash-file-not-found-no-object": "Nun pudo crease l'oxetu de ficheru llocal pa la miniatura.",
-       "uploadstash-file-not-found-no-remote-thumb": "Falló la descarga de la miniatura: $1\nurl = $2",
+       "uploadstash-file-not-found-no-remote-thumb": "Fallu al llograr la miniatura: $1\nurl = $2",
        "uploadstash-file-not-found-missing-content-type": "Falta la cabecera de triba de conteníu.",
        "uploadstash-file-not-found-not-exists": "Nun pudo alcontrase la ruta, o nun ye un ficheru.",
        "uploadstash-file-too-large": "Nun puede sirvise un ficheru mayor de $1 bytes.",
index d8fd47c..ab9c87b 100644 (file)
        "uploadstash-thumbnail": "прагляд мініятуры",
        "uploadstash-exception": "Не магу захаваць загрузку ў сховішчы ($1): «$2».",
        "uploadstash-bad-path": "Шлях не існуе.",
+       "uploadstash-bad-path-invalid": "Шлях не зьяўляецца слушным.",
+       "uploadstash-bad-path-unknown-type": "Невядомы тып «$1».",
+       "uploadstash-bad-path-unrecognized-thumb-name": "Невядомая назва мініятуры.",
        "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.",
index 8275d2c..227d2bb 100644 (file)
        "tog-numberheadings": "Überschriften automatisch nummerieren",
        "tog-showtoolbar": "Bearbeiten-Werkzeugleiste anzeigen",
        "tog-editondblclick": "Seiten mit Doppelklick bearbeiten",
-       "tog-editsectiononrightclick": "Einzelne Abschnitte per Rechtsklick bearbeiten",
+       "tog-editsectiononrightclick": "Einzelne Abschnitte per Rechtsklick auf die Überschrift bearbeiten",
        "tog-watchcreations": "Selbst erstellte Seiten und hochgeladene Dateien automatisch beobachten",
        "tog-watchdefault": "Selbst geänderte Seiten und Dateien automatisch beobachten",
        "tog-watchmoves": "Selbst verschobene Seiten und Dateien automatisch beobachten",
index ce275c8..9803dab 100644 (file)
        "readonly": "Andmebaas lukustatud",
        "enterlockreason": "Sisesta lukustamise põhjus ning juurdepääsu taastamise ligikaudne aeg",
        "readonlytext": "Andmebaas on praegu lukustatud. Uusi sissekandeid ja muid muudatusi ei saa teha. Tõenäoliselt toimub andmebaasi plaanipärane hooldus, mille järel tavaline olukord taastub.\nSüsteemiadministraator, kes andmebaasi lukustas, andis järgmise selgituse: $1",
-       "missing-article": "Andmebaas ei leidnud küsitud lehekülje \"$1\" $2 teksti.\n\nPõhjuseks võib olla võrdlus- või ajaloolink kustutatud leheküljele.\n\nKui tegemist ei ole nimetatud olukorraga, võib tegu olla ka süsteemi veaga.\nSellisel juhul tuleks teavitada [[Special:ListUsers/sysop|administraatorit]], edastades talle ka käesoleva lehe internetiaadressi.",
+       "missing-article": "Andmebaasist ei leidnud päritud lehekülje \"$1\" $2 teksti.\n\nPõhjuseks võib olla võrdlus- või ajaloolink kustutatud leheküljele.\n\nKui asi ei ole selles, võib tegu olla süsteemi veaga.\nPalun teata sellest [[Special:ListUsers/sysop|administraatorile]], edastades ka lehekülje internetiaadressi.",
        "missingarticle-rev": "(redaktsioon: $1)",
        "missingarticle-diff": "(redaktsioonid: $1, $2)",
        "readonly_lag": "Andmebaas on automaatselt lukustatud, seniks kuni sekundaarsed andmebaasiserverid on primaarserveriga samal järjel.",
        "password-login-forbidden": "Selle kasutajanime ja parooli kasutamine on keelatud.",
        "mailmypassword": "Lähtesta parool",
        "passwordremindertitle": "{{SITENAME}} – ajutine parool",
-       "passwordremindertext": "Keegi IP-aadressiga $1, tõenäoliselt sa ise, palus, et talle saadetaks {{GRAMMAR:elative|{{SITENAME}}}} uus parool ($4). Kasutaja \"$2\" ajutiseks paroolis seati \"$3\". Kui soovid tõepoolest uut parooli, pead sisse logima ja uue parooli valima. Ajutine parool aegub {{PLURAL:$5|ühe päeva|$5 päeva}} pärast.\n\nKui uut parooli palus keegi teine või sulle meenus vana parool ja sa ei soovi seda enam muuta, võid käesolevat teadet eirata ning jätkata endise parooli kasutamist.",
+       "passwordremindertext": "Keegi IP-aadressiga $1, tõenäoliselt sa ise, palus, et talle\nsaadetaks {{GRAMMAR:elative|{{SITENAME}}}} uus parool ($4).\nKasutaja \"$2\" ajutiseks paroolis seati \"$3\". Kui soovid tõepoolest\nuut parooli, pead sisse logima ja uue parooli valima.\nAjutine parool aegub {{PLURAL:$5|ühe|$5}} päeva pärast.\n\nKui uut parooli palus keegi teine või sulle meenus vana parool\nja sa ei soovi seda enam muuta, võid seda teadet eirata ning\njätkata senise parooli kasutamist.",
        "noemail": "Kasutaja $1 e-posti aadressi meil kahjuks pole.",
        "noemailcreate": "Pead sisestama korrektse e-posti aadressi",
        "passwordsent": "Uus parool on saadetud kasutaja $1 registreeritud e-postiaadressil.\nPärast parooli saamist logige palun sisse.",
        "accountcreated": "Konto loodud",
        "accountcreatedtext": "Kasutaja [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|talk]]) konto on loodud.",
        "createaccount-title": "{{GRAMMAR:illative|{{SITENAME}}}} konto loomine",
-       "createaccount-text": "Keegi on loonud {{GRAMMAR:illative|{{SITENAME}}}} ($4) sinu e-posti aadressile vastava kasutajatunnuse \"$2\". Parooliks seati \"$3\". Logi sisse ja muuda oma parool.\n\nKui kasutajakonto loomine on eksitus, võid käesolevat sõnumit lihtsalt eirata.",
+       "createaccount-text": "Keegi on loonud {{GRAMMAR:illative|{{SITENAME}}}} ($4) sinu e-posti aadressile vastava kasutajatunnuse \"$2\". Parooliks seati \"$3\". Peaksid sisse logima ja parooli muutma.\n\nKui kasutajakonto loomine oli eksitus, võid seda sõnumit lihtsalt eirata.",
        "login-throttled": "Oled lühikese aja jooksul proovinud liiga palju kordi sisse logida.\nPalun oota $1, enne kui uuesti proovid.",
        "login-abort-generic": "Sisselogimine ebaõnnestus – Katkestatud",
        "login-migrated-generic": "Sinu konto on migreeritud ja sinu kasutajanime pole enam selles vikis.",
        "anonpreviewwarning": "''Sa pole sisse logitud. Selle lehe redigeerimislogisse salvestatakse su IP-aadress.''",
        "missingsummary": "'''Meeldetuletus:''' Sa ei ole lisanud muudatuse resümeed.\nKui vajutad uuesti salvestamise nupule, salvestatakse muudatus ilma resümeeta.",
        "selfredirect": "<strong>Hoiatus:</strong> Suunad selle lehekülje iseeneda juurde.\nVõimalik, et oled määranud ümbersuunamise jaoks vale sihtleheküljeks või redigeerid vale lehekülge.\nÜmbersuunamine luuakse sellest hoolimata, kui klõpsad uuesti \"$1\".",
-       "missingcommenttext": "Palun sisesta siit allapoole kommentaar.",
+       "missingcommenttext": "Palun sisesta kommentaar.",
        "missingcommentheader": "<strong>Meeldetuletus:</strong> Sa pole kirjutanud kommentaarile teemat.\nKui klõpsad uuesti \"$1\", salvestatakse su kommentaar ilma teemata.",
        "summary-preview": "Resümee eelvaade:",
        "subject-preview": "Resümee eelvaade:",
        "newarticle": "(Uus)",
        "newarticletext": "Lehekülge, kuhu link sind suunas, pole veel.\nEt lehekülg luua, alusta allolevas kastis kirjutamist (lisateave [$1 juhendist]).\nKui sattusid siia kogemata, klõpsa brauseri ''tagasi''-nupule.",
        "anontalkpagetext": "----''See on anonüümse kasutaja arutelulehekülg. See kasutaja pole kontot loonud või ei kasuta seda. Sellepärast tuleb meil kasutaja tuvastamiseks kasutada tema IP-aadressi. Sellist IP-aadressi võib kasutada mitu kasutajat. Kui oled osutatud IP-aadressi kasutaja ning leiad, et siinsed kommentaarid ei puutu kuidagi sinusse, [[Special:CreateAccount|loo palun kasutajakonto]] või [[Special:UserLogin|logi sisse]], et sind edaspidi teiste anonüümsete kasutajatega segi ei aetaks.''",
-       "noarticletext": "Käesoleval leheküljel hetkel teksti ei ole.\nVõid [[Special:Search/{{PAGENAME}}|otsida pealkirjaks olevat fraasi]] teistelt lehtedelt,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} uurida asjassepuutuvaid logisid] või [{{fullurl:{{FULLPAGENAME}}|action=edit}} puuduva lehekülje ise luua]</span>.",
+       "noarticletext": "Siin leheküljel puudub praegu tekst.\nSaad [[Special:Search/{{PAGENAME}}|otsida pealkirjateksti]] teistelt lehekülgedelt,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} uurida asjassepuutuvaid logisid]\nvõi [{{fullurl:{{FULLPAGENAME}}|action=edit}} puuduva lehekülje luua]</span>.",
        "noarticletext-nopermission": "Sellel leheküljel pole praegu teksti.\nSaad [[Special:Search/{{PAGENAME}}|otsida selle lehekülje pealkirja]] teistelt lehekülgedelt või <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} otsida seonduvatest logidest]</span>, aga sul pole õigust seda lehekülge alustada.",
        "missing-revision": "Lehekülje \"{{FULLPAGENAME}}\" redaktsiooni $1 pole.\n\nHarilikult tähendab see seda, et sind siia juhatanud link on vananenud ja siin asunud lehekülg on kustutatud.\nÜksikasjad leiad [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} kustutamislogist].",
        "userpage-userdoesnotexist": "Kasutajakontot \"<nowiki>$1</nowiki>\" pole olemas.\nPalun mõtle järele, kas soovid seda lehte luua või muuta.",
        "recentchanges-legend": "Viimaste muudatuste seaded",
        "recentchanges-summary": "Jälgi sellel leheküljel viimaseid muudatusi.",
        "recentchanges-noresult": "Selles ajavahemikus pole tehtud neile kriteeriumitele vastavaid muudatusi.",
+       "recentchanges-timeout": "See otsing aegus. Võid proovida teisi otsiparameetreid.",
+       "recentchanges-network": "Tehnilise tõrke tõttu ei õnnestunud tulemusi laadida. Palun proovi lehekülge värskendada.",
        "recentchanges-feed-description": "Jälgi vikisse tehtud viimaseid muudatusi.",
        "recentchanges-label-newpage": "Uus lehekülg",
        "recentchanges-label-minor": "Pisiparandus",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|tund|tundi}}",
        "rcfilters-highlighted-filters-list": "Esile tõstetud: $1",
        "rcfilters-quickfilters": "Salvestatud filtrid",
-       "rcfilters-quickfilters-placeholder-title": "Linke pole veel salvestatud",
+       "rcfilters-quickfilters-placeholder-title": "Filtreid pole veel salvestatud",
        "rcfilters-quickfilters-placeholder-description": "Et filtri sätted salvestada ja et neid hiljem uuesti kasutada, klõpsa alloleva aktiivsete filtrite loendi juures järjehoidjaikooni.",
        "rcfilters-savedqueries-defaultlabel": "Salvestatud filtrid",
        "rcfilters-savedqueries-rename": "Nimeta ümber",
        "rcfilters-savedqueries-apply-and-setdefault-label": "Koosta vaikefilter",
        "rcfilters-savedqueries-cancel-label": "Loobu",
        "rcfilters-savedqueries-add-new-title": "Salvesta filtri praegused sätted",
+       "rcfilters-savedqueries-already-saved": "Need filtrid on juba salvestatud",
        "rcfilters-restore-default-filters": "Taasta vaikefiltrid",
        "rcfilters-clear-all-filters": "Eemalda kõik filtrid",
        "rcfilters-show-new-changes": "Vaata uusimaid muudatusi",
-       "rcfilters-search-placeholder": "Filtri viimaseid muudatusi (sirvi või alusta tippimist)",
+       "rcfilters-search-placeholder": "Filtri muudatusi (kasuta menüüd või otsi filtri nime)",
        "rcfilters-invalid-filter": "Vigane filter",
        "rcfilters-empty-filter": "Aktiivsed filtrid puuduvad. Näidatakse kogu kaastööd.",
        "rcfilters-filterlist-title": "Filtrid",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:mitte</strong> $1",
        "rcfilters-exclude-button-off": "Jäta valitud välja",
        "rcfilters-exclude-button-on": "Valitud välja jäetud",
-       "rcfilters-view-advanced-filters-label": "Täpsemad filtrid",
        "rcfilters-view-tags": "Märgistatud muudatused",
        "rcfilters-view-namespaces-tooltip": "Filtri tulemusi nimeruumide lõikes",
        "rcfilters-view-tags-tooltip": "Filtri tulemusi muudatusmärgiste lõikes",
        "rcfilters-view-return-to-default-tooltip": "Naase filtri peamenüüsse",
+       "rcfilters-view-tags-help-icon-tooltip": "Uuri veel märgistatud muudatuste kohta",
        "rcfilters-liveupdates-button": "Uuendused reaalajas",
        "rcfilters-liveupdates-button-title-on": "Lülita reaalajas uuendamine välja",
        "rcfilters-liveupdates-button-title-off": "Näita uusi muudatusi kohe nende tegemise järel",
        "uploaded-script-svg": "Üleslaaditud SVG-failist leiti skriptitav element \"$1\".",
        "uploaded-hostile-svg": "Üleslaaditud SVG-faili laadielemendist leiti ebaturvaline CSS.",
        "uploaded-event-handler-on-svg": "Sündmuse halduse atribuutide <code>$1=\"$2\"</code> seadmine pole SVG-failis lubatud.",
-       "uploaded-href-attribute-svg": "SVG-failis on lubatud href-atribuudiga viidata ainult sihtkohta skeemiga http:// või https://. Leiti <code>&lt;$1 $2=\"$3\"&gt;</code>.",
+       "uploaded-href-attribute-svg": "Element <a> saab href-atribuudi väärtuses linkida ainult sihtobjektile data: (manusfail), http:// või https:// või fragmendile (#, sama-dokument).  Teistes elementides, nagu <image>, on lubatud ainult data: ja fragment. Proovi SVG-faili eksportimisel faile manustada. Leiti <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-href-unsafe-target-svg": "Üleslaaditud SVG-failist leiti href, mis viitab ebaturvalistele andmetele: URI sihtkoht <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-animate-svg": "Üleslaaditud SVG-failist leiti silt \"animate\", mis võib href-i muuta, kasutades from-atribuuti <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-setting-event-handler-svg": "Sündmuse halduse atribuutide seadmine on keelatud, üleslaaditud SVG-failist leiti <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploadstash-refresh": "Värskenda faililoendit",
        "uploadstash-thumbnail": "vaata pisipilti",
        "uploadstash-exception": "Üleslaaditavat faili ei õnnestunud peithoidlas talletada ($1): \"$2\".",
+       "uploadstash-bad-path": "Teed pole olemas.",
+       "uploadstash-bad-path-invalid": "Tee pole sobiv.",
+       "uploadstash-bad-path-unknown-type": "Tundmatu tüüp \"$1\".",
+       "uploadstash-bad-path-unrecognized-thumb-name": "Tundmatu pisipildi nimi.",
+       "uploadstash-bad-path-no-handler": "Faili $2 MIME tüübile $1 ei leitud töötlejat.",
+       "uploadstash-bad-path-bad-format": "Võti \"$1\" pole sobivas vormingus.",
+       "uploadstash-file-not-found": "Peithoidlas ei leidu võtit \"$1\".",
+       "uploadstash-file-not-found-no-thumb": "Pisipilti ei õnnestu hankida.",
+       "uploadstash-file-not-found-no-local-path": "Mastaabitud elemendi kohalikku teed ei leitud.",
+       "uploadstash-file-not-found-no-object": "Pisipildi kohalikku failiobjekti ei õnnestunud luua.",
+       "uploadstash-file-not-found-no-remote-thumb": "Pisipilti ei õnnestunud hankida: $1\nURL = $2",
+       "uploadstash-file-not-found-missing-content-type": "Sisutüübi päis puudub.",
+       "uploadstash-file-not-found-not-exists": "Ei õnnestunud leida teed või faili ennast.",
+       "uploadstash-file-too-large": "$1 baidist suuremat faili ei saa töödelda.",
+       "uploadstash-not-logged-in": "Ükski kasutaja pole sisse logitud, fail peab kuuluma kasutajatele.",
+       "uploadstash-wrong-owner": "See fail ($1) ei kuulu praegusele kasutajale.",
+       "uploadstash-no-such-key": "Puudub selline võti ($1), ei saa eemaldada.",
+       "uploadstash-no-extension": "Faililaiend puudub.",
+       "uploadstash-zero-length": "Faili suurus on tühiväärtusega.",
        "invalid-chunk-offset": "Tüki vigane nihe",
        "img-auth-accessdenied": "Juurdepääs keelatud",
        "img-auth-nopathinfo": "PATH_INFO puudub.\nSinu server pole seadistatud seda teavet edastama.\nSee võib olla CGI-põhine ja ei toeta img_auth-i.\nVaata lehekülge https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "protect-expiring": "aegumistähtaeg $1 (UTC)",
        "protect-expiring-local": "aegumistähtaeg $1",
        "protect-expiry-indefinite": "tähtajatu",
-       "protect-cascade": "Kaitse lehekülgi, mis on lülitatud käesoleva lehekülje koosseisu (kaskaadkaitse)",
+       "protect-cascade": "Kaitse lehekülgi, mis on siinse lehekülje koosseisus (kaskaadkaitse)",
        "protect-cantedit": "Sa ei saa lehekülje kaitsetaset muuta, sest sul puudub lehekülje redigeerimise õigus.",
        "protect-othertime": "Muu aeg:",
        "protect-othertime-op": "muu aeg",
        "ipb_blocked_as_range": "Tõrge: IP-aadressi $1 pole eraldi blokeeritud ja blokeeringut ei saa eemaldada.\nSee kuulub aga blokeeritud IP-vahemikku $2, mille blokeeringut saab eemaldada.",
        "ip_range_invalid": "Vigane IP-vahemik.",
        "ip_range_toolarge": "Suuremad aadressiblokid kui /$1 pole lubatud.",
+       "ip_range_exceeded": "See IP-aadressivahemik ületab maksimumvahemikku. Lubatud vahemik: /$1.",
+       "ip_range_toolow": "IP-aadressivahemikud on sisuliselt keelatud.",
        "proxyblocker": "Proksiblokeerija",
        "proxyblockreason": "Sinu IP-aadress on blokeeritud, sest see on avatud proksi. Palun võta ühendust oma internetiteenuse pakkujaga või tehnilise toega ja teata neile sellest probleemist.",
        "sorbsreason": "Sinu IP-aadress on {{GRAMMAR:genitive|{{SITENAME}}}} kasutatavas DNS-põhises mustas nimekirjas märgitud kui avatud proksi.",
index 04559d2..6f3a711 100644 (file)
                        "DePlusJean",
                        "Pierpao",
                        "Vexthedorito",
-                       "Djiboun"
+                       "Djiboun",
+                       "Pols12"
                ]
        },
        "tog-underline": "Soulignement des liens :",
        "tog-watchuploads": "Ajouter les nouveaux fichiers que j’importe à ma liste de suivi",
        "tog-watchrollback": "Ajouter à ma liste de suivi les pages sur lesquelles j’ai effectué une révocation",
        "tog-minordefault": "Marquer toutes mes modifications comme étant mineures par défaut",
-       "tog-previewontop": "Afficher la prévisualisation au dessus de la zone d’édition",
+       "tog-previewontop": "Afficher la prévisualisation au-dessus de la zone de modification",
        "tog-previewonfirst": "Afficher la prévisualisation lors de la première modification",
        "tog-enotifwatchlistpages": "M’avertir par courriel lorsqu’une page ou un fichier de ma liste de suivi est modifié",
        "tog-enotifusertalkpages": "M’avertir par courriel lorsque ma page de discussion est modifiée",
        "underline-always": "Toujours",
        "underline-never": "Jamais",
        "underline-default": "Valeur par défaut du thème ou du navigateur",
-       "editfont-style": "Style de police de la zone d’édition :",
+       "editfont-style": "Style de police de la zone de modification :",
        "editfont-monospace": "Police à chasse fixe",
        "editfont-sansserif": "Police sans-serif",
        "editfont-serif": "Police serif",
        "uploadstash-file-not-found-no-remote-thumb": "La récupération de la vignette a échoué : $1\nurl = $2",
        "uploadstash-file-not-found-missing-content-type": "Entête content-type manquant.",
        "uploadstash-file-not-found-not-exists": "Impossible de trouver le chemin, ou bien ce n’est pas un fichier.",
-       "uploadstash-file-too-large": "Impossible de fournir un fichier pus gros que $1 octets.",
+       "uploadstash-file-too-large": "Impossible de fournir un fichier plus grand que $1 octets.",
        "uploadstash-not-logged-in": "Aucun utilisateur n’est connecté, les fichiers doivent appartenir à des utilisateurs.",
        "uploadstash-wrong-owner": "Ce fichier ($1) n’appartient pas à l’utilisateur courant.",
-       "uploadstash-no-such-key": "Aucune clé semblable ($1), impossible de supprimer.",
+       "uploadstash-no-such-key": "Aucune clé ($1), impossible de supprimer.",
        "uploadstash-no-extension": "L’extension est nulle.",
        "uploadstash-zero-length": "La taille du fichier est zéro.",
        "invalid-chunk-offset": "Offset de segment non valide",
        "autoredircomment": "Page redirigée vers [[$1]]",
        "autosumm-new": "Page créée avec « $1 »",
        "autosumm-newblank": "Page vide créée",
-       "size-bytes": "$1&nbsp;o",
+       "size-bytes": "$1 {{PLURAL:$1|octet|octets}}",
        "size-kilobytes": "$1&nbsp;Kio",
        "size-megabytes": "$1&nbsp;Mio",
        "size-gigabytes": "$1&nbsp;Gio",
        "feedback-close": "Terminé",
        "feedback-external-bug-report-button": "Signaler un bogue technique",
        "feedback-dialog-title": "Soumettre un commentaire",
-       "feedback-dialog-intro": "Vous pouvez utiliser le simple formulaire ci-dessous pour faire parvenir vos commentaires. Votre commentaire sera ajouté à la page « $1 », ainsi que votre nom d’utilisateur.",
+       "feedback-dialog-intro": "Vous pouvez utiliser le simple formulaire ci-dessous pour faire parvenir votre commentaire. Il sera ajouté à la page « $1 », avec votre nom d’utilisateur.",
        "feedback-error1": "Erreur : résultat de l'API non reconnu",
        "feedback-error2": "Erreur : la modification a échoué",
        "feedback-error3": "Erreur : aucune réponse de l'API",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>désactivé</strong>)",
        "mediastatistics": "Statistiques sur les médias",
        "mediastatistics-summary": "Statistiques sur les types de fichiers téléversés. Elles ne prennent en compte que la version la plus récente des fichiers. Les versions anciennes ou supprimées sont exclues.",
+       "mediastatistics-nfiles": "$1 ($2 %)",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 octet|$1 octets}} ($2 ; $3%)",
        "mediastatistics-bytespertype": "Taille totale de fichiers pour cette section : {{PLURAL:$1|$1 octet|$1 octets}} ($2 ; $3%).",
        "mediastatistics-allbytes": "Taille totale pour tous les fichiers : {{PLURAL:$1|$1 octet|$1 octets}} ($2).",
        "authprovider-confirmlink-message": "D’après vos dernières tentatives de connexion, les comptes suivants peuvent être liés à votre compte wiki. Les lier vous permettra de se connecter via ces comptes. Veuillez sélectionner lesquels doivent être liés.",
        "authprovider-confirmlink-request-label": "Comptes qui doivent être liés",
        "authprovider-confirmlink-success-line": "$1 : Liés avec succès.",
+       "authprovider-confirmlink-failed-line": "$1 : $2",
        "authprovider-confirmlink-failed": "La liaison du compte n’a pas bien réussi : $1",
        "authprovider-confirmlink-ok-help": "Continuer après l’affichage des messages d’échec de liaison.",
        "authprovider-resetpass-skip-label": "Sauter",
index 19b55a2..e956dcc 100644 (file)
        "search-redirect": "(athsheoladh $1)",
        "search-section": "(gearradh $1)",
        "search-suggest": "An raibh $1 á lorg agat?",
+       "search-rewritten": "Ag taispeáint torthaí le haghaidh $1. Ina ionad sin, cuardaigh le haghaidh $2.",
        "search-interwiki-caption": "Comhthionscadail",
        "search-interwiki-default": "Torthaí ó $1:",
        "search-interwiki-more": "(níos mó)",
        "stub-threshold-disabled": "Díchumasaithe",
        "recentchangesdays": "Méid laethanta le taispeáint sna hathruithe is déanaí:",
        "recentchangesdays-max": "(uasmhéid $1 {{PLURAL:$1|lá|lá}})",
-       "recentchangescount": "Méid athrú le taispeáint:",
+       "recentchangescount": "Méid athruithe le taispeáint:",
        "savedprefs": "Sábháladh do chuid sainroghanna.",
        "timezonelegend": "Crios ama:",
        "localtime": "An t-am áitiúil:",
        "rcfilters-other-review-tools": "Uirlisí athbhreithnithe eile",
        "rcfilters-activefilters": "Scagairí gníomhacha",
        "rcfilters-advancedfilters": "Ardscagairí",
-       "rcfilters-limit-shownum": "Taispeáin an {{$1 athrú}} is déanaí",
+       "rcfilters-limit-title": "Athruithe le taispeáint",
+       "rcfilters-limit-shownum": "Taispeáin an $1 athrú is déanaí",
        "rcfilters-days-title": "Le líon áirithe laethanta anuas",
        "rcfilters-hours-title": "Uaireanta is déanaí",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|lá}}",
        "rc_categories_any": "Aon chatagóir",
        "rc-change-size-new": "$1 {{PLURAL:$1|bheart|beart}} tar éis an athraithe",
        "newsectionsummary": "/* $1 */ mír nua",
-       "rc-enhanced-expand": "Taispeáin mionsonraithe (JavaScript riachtanach)",
+       "rc-enhanced-expand": "Taispeáin mionsonraithe",
        "rc-enhanced-hide": "Folaigh shonraí",
        "recentchangeslinked": "Athruithe gaolmhara",
        "recentchangeslinked-feed": "Athruithe gaolmhara",
        "undeleteinvert": "Cuir an roghnú bun os cionn",
        "undeletecomment": "Tuairisc:",
        "undelete-search-box": "Cuardaigh leathanaigh scriosta",
+       "undelete-search-prefix": "Taispeáin leathanaigh ag tosú le:",
        "undelete-search-submit": "Cuardaigh",
        "namespace": "Ainmspás:",
        "invert": "Iompaigh rogha bunoscionn",
        "bad_image_list": "Is é seo a leanas an formáid:\n\nNíl ach míreanna liosta amháin (línte ag tosú le *) san áireamh.\nIs riachtanach gur nasc do dhrochchomhad é an chéad nasc ar líne.\nIs eisceachtaí iad na naisc eile ar an líne céanna, .i. leathanaigh gur féidir an comhad a bheith orthu go hinlíne.",
        "metadata": "Meiteasonraí",
        "metadata-help": "Tá breis eolais sa comhad seo, curtha, is dócha, as ceamara digiteach ná scanóir a chruthaigh ná a digitigh é.\nMá tá an comhad mionathraithe as an bunleagan, b'fhéidir nach mbeidh ceann de na sonraí fágtha sa comhad atá athruithe.",
-       "metadata-expand": "Taispeáin sonraí síneadh",
+       "metadata-expand": "Taispeáin sonraí sínte",
        "metadata-collapse": "Folaigh sonraí síneadh",
        "metadata-fields": "Beidh na meiteasonraí EXIF seo a leanas dá dtaispeáint ar an leathanach íomhá nuair atá an clár meiteasonraí ceilte.\nBeidh na cinn eile ceilte de réir réamhshocraithe.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "exif-imagewidth": "Leithead",
        "table_pager_prev": "Leathanach roimhe",
        "table_pager_first": "Céad leathanach",
        "table_pager_last": "Deireadh leathanach",
+       "table_pager_limit": "Taispeáin $1 mír/leathanach",
        "table_pager_limit_submit": "Gabh",
        "table_pager_empty": "Folamh",
        "autoredircomment": "Ag athdhíriú go [[$1]]",
        "specialpages-group-spam": "Uirlisí turscar",
        "blankpage": "Leathanach bán",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|chlib amháin|clib}}]]: $2)",
+       "diff-form-submit": "Taispeáin difríochtaí",
        "htmlform-selectorother-other": "Eile",
        "logentry-move-move": "{{GENDER:$2|Bhog}} $1 an leathanach $3 go $4",
        "feedback-cancel": "Cealaigh",
index 51286cd..e8ae8e4 100644 (file)
        "rcfilters-savedqueries-apply-and-setdefault-label": "Crear filtro por defecto",
        "rcfilters-savedqueries-cancel-label": "Cancelar",
        "rcfilters-savedqueries-add-new-title": "Gardar a configuración do filtro actual",
+       "rcfilters-savedqueries-already-saved": "Estes filtro xa están gardados",
        "rcfilters-restore-default-filters": "Restaurar os filtros por defecto",
        "rcfilters-clear-all-filters": "Borrar todos os filtros",
        "rcfilters-show-new-changes": "Mostrar os cambios máis recentes",
index 58a0c36..6584a3d 100644 (file)
        "rcfilters-savedqueries-apply-and-setdefault-label": "Alapértelmezett szűrő készítése",
        "rcfilters-savedqueries-cancel-label": "Mégse",
        "rcfilters-savedqueries-add-new-title": "Szűrők mentése gyors hivatkozásként",
+       "rcfilters-savedqueries-already-saved": "Ezek a szűrők már el lettek mentve",
        "rcfilters-restore-default-filters": "Alapértelmezett szűrők visszaállítása",
        "rcfilters-clear-all-filters": "Összes szűrő kikapcsolása",
        "rcfilters-show-new-changes": "Legfrissebb változtatások megtekintése",
        "uploadstash-refresh": "Fájlok listájának frissítése",
        "uploadstash-thumbnail": "bélyegkép megjelenítése",
        "uploadstash-exception": "Nem sikerült eltárolni a feltöltést a stash-ben ($1): „$2”",
+       "uploadstash-bad-path": "Útvonal nem létezik",
+       "uploadstash-bad-path-invalid": "Érvénytelen útvonal",
+       "uploadstash-bad-path-unknown-type": "Ismeretlen típus: „$1”",
        "invalid-chunk-offset": "Érvénytelen darab eltolás",
        "img-auth-accessdenied": "Hozzáférés megtagadva",
        "img-auth-nopathinfo": "Hiányzó PATH_INFO.\nA szerver nincs beállítva, hogy továbbítsa ezt az információt.\nLehet, hogy CGI-alapú, és nem támogatja az img_auth-ot.\nLásd https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization!",
index 0c52fb4..a70c190 100644 (file)
@@ -73,7 +73,6 @@
        "underline-never": "Numquam",
        "underline-default": "Defalta navigatri interretialis",
        "editfont-style": "Stilus:",
-       "editfont-default": "iuxta navigatrum",
        "editfont-sansserif": "Fons Sans-serif",
        "editfont-serif": "Fons Serif",
        "sunday": "dies Solis",
        "anontalk": "Disputatio",
        "navigation": "Navigatio",
        "and": "&#32;et",
-       "qbfind": "Invenire",
-       "qbbrowse": "Perspicere",
-       "qbedit": "Recensere",
-       "qbpageoptions": "Optiones paginae",
-       "qbmyoptions": "Paginae meae",
        "faq": "Quaestiones frequentes",
-       "faqpage": "Project:Quaestiones frequentes",
        "actions": "Actiones",
        "namespaces": "Spatia nominalia",
        "variants": "Variantes",
        "view-foreign": "Legere apud {{grammar:accusative|$1}}",
        "edit": "Recensere",
        "create": "Creare",
-       "editthispage": "Recensere hanc paginam",
-       "create-this-page": "Creare hanc paginam",
        "delete": "Delere",
-       "deletethispage": "Delere hanc paginam",
-       "undeletethispage": "Hanc paginam restituere",
        "undelete_short": "{{PLURAL:$1|Unam recensionem|$1 recensiones}} restituere",
        "viewdeleted_short": "{{PLURAL:$1|unam redactionem deletam|$1 redactiones deletas}} inspicere",
        "protect": "Protegere",
        "protect_change": "mutare",
-       "protectthispage": "Protegere hanc paginam",
        "unprotect": "Protectionem mutare",
-       "unprotectthispage": "Protectionem huius paginae mutare",
        "newpage": "Nova pagina",
-       "talkpage": "Disputare hanc paginam",
        "talkpagelinktext": "Disputatio",
        "specialpage": "Pagina specialis",
        "personaltools": "Instrumenta personalia",
-       "articlepage": "Videre rem",
        "talk": "Disputatio",
        "views": "Visae",
        "toolbox": "Arca ferramentorum",
-       "userpage": "Videre paginam usoris",
-       "projectpage": "Videre consilium",
        "imagepage": "Videre paginam fasciculi",
        "mediawikipage": "Videre nuntium",
        "templatepage": "Videre formulam",
        "explainconflict": "Alius hanc paginam mutavit postquam eadem recensere incipiebas.\nCapsa superior paginae verba recentissima continet.\nMutationes tuae in capsa inferiore monstrantur.\nMutationes tuae in verba superiora adiungare debes.\n'''Solum''' verba capsae superioris servabuntur quando \"$1\" premes.",
        "yourtext": "Tua redactio",
        "storedversion": "Redactio modo servata",
-       "nonunicodebrowser": "'''CAVETO: Navigatorium retiale tuum systemati UNICODE morem non gerit. Modum habemus quo commentationes sine damno recenseas: litterae non-ASCII in capsa sub veste hexadecimali ostendentur.'''",
        "editingold": "'''CAVE, ne huius paginae redactionem recenses obsoletam!\nQua servata omnes recensiones abhinc factas peribunt.'''",
        "yourdiff": "Differentia",
        "copyrightwarning": "Nota bene omnia contributa divulgari sub ''$2'' (vide singula apud $1).\nNisi vis verba tua crudelissime recenseri, mutari, et ad libidinem redistribui, noli ea submittere.<br />\nNobis etiam spondes te esse ipsum horum verborum scriptorem primum, aut ex opere in \"dominio publico\" exscripsisse.\n'''NOLI OPERIBUS SUB IURE DIVULGANDI UTI SINE POTESTATE!'''",
        "sp-contributions-username": "Locus IP aut nomen usoris:",
        "sp-contributions-submit": "Quaerere",
        "whatlinkshere": "Nexus ad paginam",
-       "whatlinkshere-title": "Paginae quae ad \"$1\" nectunt",
+       "whatlinkshere-title": "Paginae quae ad \"$1\" nectuntur",
        "whatlinkshere-page": "Pagina:",
        "linkshere": "Paginae sequentes ad '''[[:$1]]''' nectunt:",
        "nolinkshere": "Nullae paginae ad '''[[:$1]]''' nectunt.",
        "whatlinkshere-hideimages": "$1 nexus fasciculi",
        "whatlinkshere-filters": "Filtra",
        "blockip": "Usorem obstruere",
-       "blockip-legend": "Usorem vel locum IP obstruere",
        "blockiptext": "Forma infra data utere, ut quendam usorem vel locum IP arceas a scribendo.\nQuod non nisi secundum [[{{MediaWiki:Policy-url}}|hoc consilium]] fiat, ut vandalismus supprimatur.\nRationem certam da (exempli gratia titulos paginarum, quibus iste usor more vandalico nocuit)!",
        "ipaddressorusername": "Locus IP aut nomen usoris:",
        "ipbexpiry": "Exitus:",
        "compare-page2": "Pagina 2",
        "compare-rev1": "Redactio una",
        "compare-rev2": "Redactio altera",
+       "diff-form": "'''forma'''",
        "htmlform-submit": "Submittere",
        "htmlform-reset": "Mutationes abrogare",
        "htmlform-selectorother-other": "Aliud",
index 1f945f3..fd8844b 100644 (file)
        "otherlanguages": "En otras linguas",
        "redirectedfrom": "(Redirijado de $1)",
        "redirectpagesub": "Hoja redirigida",
-       "lastmodifiedat": "Esta hoja fue trocada por la vez dalcavo en el $1, a las $2 la ora.",
+       "lastmodifiedat": "Esta hoja la vez dalcavo se trocó enel $1, a las $2 la ora.",
        "viewcount": "Este pajina fue vijitado {{PLURAL:$1|una vez|$1 vezes}}.",
        "protectedpage": "Hoja guardada",
        "jumpto": "Saltar a:",
        "pool-timeout": "Tiempo de asperar esta asperando por el kandado",
        "pool-queuefull": "Kola de lavoro esta yeno",
        "pool-errorunknown": "Yerro deskonosido",
-       "aboutsite": "Encima de {{SITENAME}}",
+       "aboutsite": "Encima {{GENDER:{{SITENAME}}|del|de la|de}} {{SITENAME}}",
        "aboutpage": "Project:Encima de",
        "copyright": "El kontenido se puede topar debasho de la $1 salvo ke indika al kontrario.",
        "copyrightpage": "{{ns:project}}:Derechos del otor",
        "tooltip-pt-login": "Te consejamos de entrar a tu cuento, portanto no sos obligado",
        "tooltip-pt-logout": "Sal de tu cuento",
        "tooltip-pt-createaccount": "Te consejamos de avrir un cuento y hazer entrada allá, portanto no sos obligado",
-       "tooltip-ca-talk": "Diskusyón encima del artíkolo",
-       "tooltip-ca-edit": "Puedes trocar esta hoja. Ma te rogamos para que eches una ojada (previsteo) antes de enrejistrarla.",
+       "tooltip-ca-talk": "Diskusyón encima del contènido desta hoja",
+       "tooltip-ca-edit": "Troca esta hoja",
        "tooltip-ca-addsection": "Ajusta un kapítolo muevo",
        "tooltip-ca-viewsource": "Esta hoja está guadrada.\nPuedes ver su manadero",
        "tooltip-ca-history": "Enderechamientos passados desta hoja",
        "tooltip-n-portal": "Encima del projeto, lo que se puede hazer y ande se topa las cosas",
        "tooltip-n-currentevents": "Jhaberes de oy día en ancho",
        "tooltip-n-recentchanges": "La lista de los trocamientos dalcavo enel viki",
-       "tooltip-n-randompage": "Carga una hoja por azardo",
+       "tooltip-n-randompage": "Avre una hoja por azardo",
        "tooltip-n-help": "Para saver mas y tomar ayudo",
-       "tooltip-t-whatlinkshere": "Una lista de todas las hojas del viki que tienen atamientos a esta hoja",
+       "tooltip-t-whatlinkshere": "La lista de todas las hojas del viki que tienen atamientos a esta hoja",
        "tooltip-t-recentchangeslinked": "Los trocamientos dalcavo en las hojas atadas a la ésta",
        "tooltip-feed-rss": "Sindicación RSS de esta hoja",
        "tooltip-feed-atom": "Canal Atomo parâ esta hoja",
        "tooltip-t-emailuser": "A este usuario, mándale una letra electrόnica (ímey)",
        "tooltip-t-upload": "Suve dosyas",
        "tooltip-t-specialpages": "La lista de todas las hojas especiales",
-       "tooltip-t-print": "La forma apropiada parâ imprimir esta hoja",
+       "tooltip-t-print": "La vista desta hoja apropiada para imprimir",
        "tooltip-t-permalink": "Atamiento permanente (fikso) a este enderechamiento de la hoja",
        "tooltip-ca-nstab-main": "Ve el artíkolo",
        "tooltip-ca-nstab-user": "Ver la hoja del usador",
index 7e96931..ad5a415 100644 (file)
        "subject-preview": "Sujet kucken ouni ze späicheren:",
        "previewerrortext": "Beim Versuch fir Är Ännerungen ze weisen, ass e Feeler geschitt.",
        "blockedtitle": "Benotzer ass gespaart",
-       "blockedtext": "Äre Benotzernumm oder Är IP-Adress gouf gespaart.\n\nD'Spär gouf vum $1 gemaach. Als Grond gouf ''$2'' uginn.\n\n* Ufank vun der Spär: $8\n* Enn vun der Spär: $6\n* Spär betrëfft: $7\n\nDir kënnt den/d' $1 kontaktéieren oder ee vun den aneren [[{{MediaWiki:Grouppage-sysop}}|Administrateure]] fir iwwer d'Spär ze schwätzen.\n\nDëst sollt Der besonnesch maachen, wann Der d'Gefill hutt, datt de Grond fir d'Spären net bei Iech läit.\nD'Ursaach dofir ass an deem Fall, datt der eng dynamesch IP hutt, iwwer en Access-Provider, iwwer deen och aner Leit fueren.\nAus deem Grond ass et recommandéiert, sech e Benotzernumm zouzeleeën, fir all Mëssverständnes z'evitéieren.\n\nDir kënnt d'Funktioun \"Dësem Benotzer eng E-Mail schécken\" nëmme benotzen, wann Dir eng gëlteg E-Mail Adress bei Ären [[Special:Preferences|Astellungen]] aginn hutt.\nÄr aktuell IP-Adress ass $3 an d'Nummer vun der Spär ass #$5.\nSchreift all dës Informatioune w.e.g. bei all Ufro derbäi.",
+       "blockedtext": "Äre Benotzernumm oder Är IP-Adress gouf gespaart.\n\nD'Spär gouf vum $1 gemaach. Als Grond gouf ''$2'' uginn.\n\n* Ufank vun der Spär: $8\n* Enn vun der Spär: $6\n* Spär betrëfft: $7\n\nDir kënnt den/d' $1 kontaktéieren oder ee vun den aneren [[{{MediaWiki:Grouppage-sysop}}|Administrateure]] fir iwwer d'Spär ze schwätzen.\n\nDëst sollt Dir besonnesch maachen, wann Dir d'Gefill hutt, datt de Grond fir d'Spären net bei Iech läit.\nD'Ursaach dofir ass an deem Fall, datt Dir eng dynamesch IP hutt, iwwer en Access-Provider, iwwer deen och aner Leit fueren.\nAus deem Grond ass et recommandéiert, sech e Benotzernumm zouzeleeën, fir all Mëssverständnes z'evitéieren.\n\nDir kënnt d'Funktioun \"Dësem Benotzer eng E-Mail schécken\" nëmme benotzen, wann Dir eng gëlteg E-Mail Adress bei Ären [[Special:Preferences|Astellungen]] aginn hutt.\nÄr aktuell IP-Adress ass $3 an d'Nummer vun der Spär ass #$5.\nSchreift all dës Informatioune w.e.g. bei all Ufro derbäi.",
        "autoblockedtext": "Är IP-Adress gouf automatesch gespaart, well se vun engem anere Benotzer gebraucht gouf, an dee vum $1 gespaart gouf.\nDe Grond dofir war:\n\n:''$2''\n\n* Ufank vun der Spär: $8\n* Dauer vun der Spär: $6\n* D'Spär leeft of: $7\n\nDir kënnt de(n) $1 oder soss een [[{{MediaWiki:Grouppage-sysop}}|Administrateur]] kontaktéieren, fir iwwer déi Spär ze diskutéieren.\n\nBedenkt datt Dir d'Funktioun \"Dësem Benotzer eng E-Mail schécken\" benotze kënnt wann Dir eng gëlteg E-Mail-Adress an Ären [[Special:Preferences|Astellungen]] uginn hutt a wann dat net fir Iech gespaart gouf.\n\nÄr aktuell IP-Adress ass $3 an d'Nummer vun Ärer Spär ass $5.\nGitt dës Donnéeë w.e.g bei allen Ufroen zu dëser Spär un.",
        "blockednoreason": "Kee Grond uginn",
        "whitelistedittext": "Dir musst Iech $1, fir Säiten änneren ze kënnen.",
        "userpage-userdoesnotexist": "De Benotzerkont \"<nowiki>$1</nowiki>\" ass net registréiert.\nIwwerpréift w.e.g. op Dir dës Säit uleeën/ännere wëllt.",
        "userpage-userdoesnotexist-view": "De Benotzerkont \"$1\" ass net registréiert.",
        "blocked-notice-logextract": "Dëse Benotzer ass elo gespaart.\nDéi lescht Entrée am Logbuch vun de Späre steet als Referenz hei drënner:",
-       "clearyourcache": "<strong>Opgepasst - Nom Späichere muss der Ärem Browser seng Cache eidel maachen, fir d'Ännerungen ze gesinn.</strong>\n* <strong>Firefox / Safari:</strong> Halt <em>Shift</em> während Dir <em>Reload</em> klickt oder dréckt entweder <em>Ctrl-F5</em> oder <em>Ctrl-R</em> (<em>⌘-R</em> op engem Mac);\n* <strong>Google Chrome:</strong> Dréckt <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> op engem Mac)\n* <strong>Internet Explorer:</strong> dréckt <em>Ctrl</em> während Dir op <em>Refresh</em> klickt oder dréckt <em>Ctrl-F5.</em>\n* <strong>Opera:</strong> Gitt op de <em>Menu → Settings</em> (<em>Opera → Preferences</em> op engem  Mac) an dann op <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
+       "clearyourcache": "<strong>Opgepasst - Nom Späichere musst Dir Ärem Browser seng Cache eidel maachen, fir d'Ännerungen ze gesinn.</strong>\n* <strong>Firefox / Safari:</strong> Halt <em>Shift</em> während Dir <em>Reload</em> klickt oder dréckt entweder <em>Ctrl-F5</em> oder <em>Ctrl-R</em> (<em>⌘-R</em> op engem Mac);\n* <strong>Google Chrome:</strong> Dréckt <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> op engem Mac)\n* <strong>Internet Explorer:</strong> dréckt <em>Ctrl</em> während Dir op <em>Refresh</em> klickt oder dréckt <em>Ctrl-F5.</em>\n* <strong>Opera:</strong> Gitt op de <em>Menu → Settings</em> (<em>Opera → Preferences</em> op engem  Mac) an dann op <em>Privacy & security → Clear browsing data → Cached images and files</em>.",
        "usercssyoucanpreview": "'''Tipp:''' Benotzt de \"{{int:showpreview}}\"-Knäppchen, fir Ären neien CSS virum Späicheren ze testen.",
        "userjsyoucanpreview": "'''Tipp:''' Benotzt de ''{{int:showpreview}}''-Knäppchen, fir Ären neie JavaScript virum Späicheren ze testen.",
        "usercsspreview": "'''Bedenkt: Dir kuckt just är Benotzer CSS.\nSi gouf nach net gespäichert!'''",
        "rcfilters-savedqueries-apply-and-setdefault-label": "Standardfilter uleeën",
        "rcfilters-savedqueries-cancel-label": "Ofbriechen",
        "rcfilters-savedqueries-add-new-title": "Aktuell Filter-Astellunge späicheren",
+       "rcfilters-savedqueries-already-saved": "Dës Filtere si scho gespäichert",
        "rcfilters-restore-default-filters": "Standardfiltere restauréieren",
        "rcfilters-clear-all-filters": "All Filteren eidelmaachen",
        "rcfilters-show-new-changes": "Rezentst Ännerunge weisen",
        "log": "Logbicher",
        "logeventslist-submit": "Weisen",
        "all-logs-page": "All ëffentlech Logbicher",
-       "alllogstext": "Dëst ass eng kombinéiert Lëscht vu Logbicher op {{SITENAME}}.\nDir kënnt d'Siche limitéieren wann Dir e Log-Typ, e Benotzernumm (case-senisitive) oder déi gefrote Säit (och case-senisitive) agitt.",
+       "alllogstext": "Dëst ass eng kombinéiert Lëscht vu Logbicher op {{SITENAME}}.\nDir kënnt d'Siche limitéiere wann Dir e Log-Typ, e Benotzernumm (case-senisitive) oder déi gefrot Säit (och case-senisitive) agitt.",
        "logempty": "Näischt fonnt.",
        "log-title-wildcard": "Titel fänkt mat dësem Text un",
        "showhideselectedlogentries": "Déi erausgesicht Entréeën am Logbuch weisen/verstoppen",
        "pageinfo-recent-edits": "Zuel vun de rezenten Ännerungen (an de leschten $1)",
        "pageinfo-recent-authors": "Zuel vun de verschiddenen Auteuren",
        "pageinfo-magic-words": "{{PLURAL:$1|Magescht Wuert|Magesch Wierder}} ($1)",
-       "pageinfo-hidden-categories": "Verstoppte {{PLURAL:$1|Kategorie|Kategorien}} ($1)",
-       "pageinfo-templates": "Agebonne {{PLURAL:$1|Schabloun|Schabloune}} ($1)",
+       "pageinfo-hidden-categories": "Verstoppt {{PLURAL:$1|Kategorie|Kategorien}} ($1)",
+       "pageinfo-templates": "Agebonn {{PLURAL:$1|Schabloun|Schablounen}} ($1)",
        "pageinfo-transclusions": "Agebonnen {{PLURAL:$1|an eng Säit|a(n) $1 Säiten}}",
        "pageinfo-toolboxlink": "Informatiounen iwwer d'Säit",
        "pageinfo-redirectsto": "Viruleedung op",
index 581e409..951a73c 100644 (file)
@@ -15,7 +15,7 @@
        },
        "tog-underline": "خط کیشائن ژێر پیوندەل:",
        "tog-hideminor": "آشاردن دەسکاریەل گؤجەر  إژ گؤەڕیال(تغییرات) ایسە(اخیر)",
-       "tog-hidepatrolled": "دسکاریۀل گه دیار بینۀ ئژ فئرست-رزگ تغییرات اخیر بشارا",
+       "tog-hidepatrolled": "ویرایش‌های گشت‌خورده از فهرست تغییرات اخیر پنهان شود",
        "tog-newpageshidepatrolled": "وڵگۀل گه دیار بینۀ ئژ فئرست-رزگ ولگۀل تازۀ بشارا",
        "tog-hidecategorization": "فهرست بالا سی ئی صفحه",
        "tog-extendwatchlist": " کؤل رزگ-فئرست الؤن(آلشت)کریال-تغیرات نیشان دۀ،نۀ هر تنیا دؤمائنۀل",
        "tog-minordefault": "کؤڵ دسکاری بیۀل به عنؤان پئش فرض عڵامت بۀرن",
        "tog-previewontop": "پیش نمایش وهِ رئ جعبۀ نمایش نیشؤن به",
        "tog-previewonfirst": "پێش دئین وە اوەڵێن دەسکاری نیشۆن دە",
-       "tog-enotifwatchlistpages": "ئÛ\80ر Ù\88ÚµÚ¯Û\80 Û\8cا Ù¾Ø±Ø¤Ù\86دئÙ\87 Ø¦Ú\98 Ù\81ئرست-رزگ Ù¾Û\8câ\80\8cÚ¯Û\8cرÛ\8câ\80\8cÛ\80Ù\84Ù\85 Ø¯Ø³Ú©Ø§Ø±Û\8c Ø¨Û\8c Ù\86اÙ\85Ù\87 Ø¦Û\80را Ù\85Ù\87 Ú©Ù\90Ù\84Ù\91 Ú©Û\80",
-       "tog-enotifusertalkpages": "Ù\87Û\80Ù\86ئگÙ\87\88ختئ Ú¯Ù\87 Ø¦Û\80 Ù\88ÚµÚ¯Û\80 Ú¯Ù¾ Ú©Ø§Ø¨Ø±Û\8cÙ\85 ØªØºÛ\8cÛ\8cر Ú©Ø±Û\8cا Ù\86اÙ\85Ù\87 Ø¦Û\80را Ù\85Ù\87 Ú©Ù\90Ù\84 Ú©Û\80",
-       "tog-enotifminoredits": "ئÛ\80ر ØªØºÛ\8cÛ\8cرÛ\80Ù\84-آڵؤÙ\86Û\80Ù\84(Ø¢Ù\84شتÛ\80Ù\84)گؤجÛ\80رÛ\8cجÛ\8c Ø¦Û\80ر Ù\88ÚµÚ¯Û\80Ù\84 Ø¤ Ù¾Ø±Ø¤Ù\86دÛ\80Ù\84Ù\85 Ú©Ø±Û\8cا Ù\86اÙ\85Ù\87 Ø¦Û\80را Ù\85Ù\87 Ú©Ù\90Ù\84 Ú©Û\80",
+       "tog-enotifwatchlistpages": "ئÛ\95Ú¯Û\95ر Ù¾Û\95Ú\95Û\95Û\8e Û\8cا Ú¤Û\95ÚµÚ¯Û\95Û\8e Ø¦Û\95Ú\98 Ù¾Û\95Û\8eÚ¯Û\8cرÛ\8cÛ\95Ù\84Ù\85 Ú¯Ù\88Ù\88Û\95Ú\95Û\8cا(تغÛ\8cرÛ\8cاÙ\81ت)ئÛ\8cÙ\85Û\95Û\8cÙ\84Û\8e Ø¦Û\95Ú\95اÙ\86Ù\85 Ú©Ù\84 Ú©Û\95",
+       "tog-enotifusertalkpages": "Ù\87Û\95Ù\86Û\8e(Ú¤Û\95Ù\82تÛ\8e)Ù¾Û\95Ú\95Û\95Û\8e Ø¦Û\95Ú\98 Ú¤Û\95ÚµÚ¯Û\95 Ú¯Û\95Ù¾(Ù\82سÛ\95)Ú¯Ù\88Ù\88Û\95Ú\95Û\8cا Ø¦Û\8cÙ\85Û\95Ù\84Û\8e Ø¦Û\95Ú\95اÙ\86Ù\85 Ú©Ù\84 Ú©Û\95",
+       "tog-enotifminoredits": "ئÛ\95Ú\95ا Ú¯Ù\88Ù\88Û\95Ú\95اÙ\86Ù\86Û\95Ù\84(تغÛ\8cرات)Ú¯Ù\88Ù\88جÛ\95ر Ø¦Û\95 Ú¤Û\95ÚµÚ¯Û\95Ù\84/Ù¾Û\95Ú\95Û\95Ù\84 Ø¦Û\8cÙ\85Û\95Û\8cÙ\84Û\8e Ø¦Û\95Ú\95اÙ\86Ù\85 Ú©Ù\84 Ú©Û\95",
        "tog-enotifrevealaddr": "نیشانی ایمیل مه ئۀر ایمیل‌ل حاوواڵ رۀسن نیشؤن دۀ",
        "tog-shownumberswatching": "گلۀ شؤماری-شؤمار کاربۀل پی‌گیر نیشان دۀ",
        "tog-oldsig": ":امضاێ موجود ایوه",
        "tog-fancysig": "(امضا چؤی ویکی‌متن بوو(بدون پئؤن خودکار نیائن",
-       "tog-uselivepreview": "استفاده از پیش‌نمایش زنده",
+       "tog-uselivepreview": "پێش سەیرکەر بدون گرەک(نیاز)ڤە بروز رسانی ڤەڵگە",
        "tog-forceeditsummary": "هۀنئ گه-وختئ که خؤلاصۀ دسکاریم نَنیؤیسائۀ خۀؤۀ رم کۀ",
        "tog-watchlisthideown": "دسکاریۀل ووژم ئژ فئرست سئرکردن بشارآ",
        "tog-watchlisthidebots": "دسکاریۀل ربات ئژ فئرست سئرکردن بشآرا",
        "tog-watchlisthideminor": "دسکاریۀل گؤجۀر ئژ فئرست سئرکردن بشارآ",
        "tog-watchlisthideliu": "دەسکاری کاربرەل إنۆم هەتێ سیستم وە لیست پیگیریەل بشارآ",
        "tog-watchlistreloadautomatically": "Reload the watchlist automatically whenever a filter is changed (JavaScript required)",
+       "tog-watchlistunwatchlinks": "افزودن پیوندهای مستقیم خروج از پی‌گیری به فهرست پی‌گیری (جاواسکریپت ممکن است نیاز شود)",
        "tog-watchlisthideanons": "دةسکاری کاربرةل ناشنا ئة لیست نمائش بشارآ",
        "tog-watchlisthidepatrolled": "دسکاریۀل گشت خورده-سئرکریا ئژ فئرست سئرکردن بشآرا",
        "tog-watchlisthidecategorization": "نهفتن رده‌بندی صفحه‌ها",
@@ -60,7 +61,6 @@
        "underline-never": "هؤیچ وخت",
        "underline-default": "پوسته یا مِنِی کەر پیش‌فرض",
        "editfont-style": ":شئؤۀ قلم جعبهٔ دسکاری",
-       "editfont-default": "پیشفرض مِنِی کەر",
        "editfont-monospace": "قلم وە فاصلۀ ثابت",
        "editfont-sansserif": "قلم بئ گوشۀ",
        "editfont-serif": "قلم گوشۀ دار",
        "index-category": "صفحه‌های نمایه‌شده",
        "noindex-category": "صفحه‌های نمایه‌نشده",
        "broken-file-category": "صفحه‌های دارای پیوند خراب به پرونده",
+       "categoryviewer-pagedlinks": "($1) ($2)",
        "about": "دۀربارۀ",
        "article": "وەڵگە نۆم چێنە",
        "newwindow": "(واز کردن ئۀر دۀروۀچۀ جدید)",
        "faq": "پرسش‌های متداول",
        "actions": "کارۀل",
        "namespaces": "فضای نامۀل",
-       "variants": "قصۀ کِرۀل",
+       "variants": "گەپ دێەل(قسەکرەل)",
        "navigation-heading": "منوی ناوبری",
        "errorpagetitle": "خطا",
        "returnto": "بازگشت به $1",
        "redirectedfrom": "(تغییرمسیر إژ $1)",
        "redirectpagesub": "وةڵگة تغییرمسیر",
        "redirectto": ":تغییر مسیر به",
-       "lastmodifiedat": ".اێ وەڵگەآخرین گِل وە $1 سات $2 گؤەڕیائە(تغییریافته)",
+       "lastmodifiedat": "ئێ ڤەڵگەئاخرێن گِل ڤە $1 سات $2 گووەڕیائە(تغییریافته)",
        "viewcount": "إژ ئئ وةڵگة  {{PLURAL:$1|یإ گِل|$1$1چةن گِل}} بازدید بیة.",
        "protectedpage": "وەڵگە پڵۆم بیە",
        "jumpto": ":وازآ کردن/پریدن وۀ",
        "versionrequired": "نسخهٔ $1 از نرم‌افزار مدیاویکی لازم است",
        "versionrequiredtext": "برای دیدن این صفحه به نسخهٔ $1 از نرم‌افزار مدیاویکی نیاز دارید.\nبه [[Special:Version|این صفحه]] مراجعه کنید.",
        "ok": "خوو/ باشد",
+       "pagetitle": "$1 - {{SITENAME}}",
+       "pagetitle-view-mainpage": "{{SITENAME}}",
        "retrievedfrom": "إژ \"$1\" گیریائۀ",
        "youhavenewmessages": "{{PLURAL:$3|درین}}$1$2",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|هؤمة}} $1 د {{PLURAL:$3|کاربةرێ تِر|$3 کاربةر}}دِرین($2).",
        "youhavenewmessagesmulti": ".پیغامةل جدیدی ئة $1 درین",
        "editsection": "دةسکاری",
        "editold": "دةسکاری",
-       "viewsourceold": "سئرکردÙ\86 Ø¨Ù\90Ù\86Ú\86Û\80Ú©/Ù\85Û\80Ù\86بÛ\80ع",
+       "viewsourceold": "بÙ\86Ú\86Û\95Ú©(Ù\85Ù\86بع) Ø¨Û\8aÙ\86(سÛ\95Û\8cرکÛ\95)",
        "editlink": "دەسکاری",
-       "viewsourcelink": "سئرکردÙ\86 Ø¨Ù\90Ù\86Ú\86Û\80Ú©/Ù\85Û\80Ù\86بÛ\80ع",
+       "viewsourcelink": "بÙ\86Ú\86Û\95Ú©(Ù\85Ù\86بع) Ø¨Û\8aÙ\86(سÛ\95Û\8cرکÛ\95)",
        "editsectionhint": "دۀسکاری بۀخش: $1",
        "toc": "محتویات",
        "showtoc": "نیشان دائن",
        "perfcached": "داده‌های زیر از حافظهٔ نهانی فراخوانی شده‌اند و ممکن است کاملاً به‌روز نباشند. حداکثر {{PLURAL:$1|یک نتیجه| $1 نتیجه}} در حافظهٔ نهانی قابل دسترس است.",
        "perfcachedts": "داده‌های زیر از حافظهٔ نهانی فراخوانی شده‌اند و آخرین بار در $1 به‌روزرسانی شدند. حداکثر {{PLURAL:$4|یک نتیجه|$4 نتیجه}} در حافظهٔ نهانی قابل دسترس است.",
        "querypage-no-updates": "امکان به‌روزرسانی این صفحه فعلاً غیرفعال شده‌است.\nاطلاعات این صفحه ممکن است به‌روز نباشد.",
-       "viewsource": "سئرکردÙ\86 Ø¨Ù\90Ù\86Ú\86Û\80Ú©/Ù\85Û\80Ù\86بÛ\80ع",
+       "viewsource": "بÙ\86Ú\86Û\95Ú©(Ù\85Ù\86بع) Ø¨Û\8aÙ\86(سÛ\95Û\8cرکÛ\95)",
        "viewsource-title": "نمایش بِنچةک ئةرا $1",
        "actionthrottled": "جلوی عمل شما گرفته شد",
        "actionthrottledtext": "به منظور جلوگیری از انتشار خرابکاری، اجازه ندارید که چنین عملی را بیش از چند بار در یک مدت زمان کوتاه انجام بدهید.\nلطفاً پس از چند دقیقه دوباره تلاش کنید.",
        "yourdomainname": ":دامنهٔ شما",
        "password-change-forbidden": ".شما نمی‌توانید گذرواژه‌ها را در این ویکی تغییر دهید",
        "externaldberror": "خطایی در ارتباط با پایگاه داده رخ داده است یا اینکه شما اجازهٔ به‌روزرسانی حساب خارجی خود را ندارید.",
-       "login": "إ نۆم هەتن سیستم",
+       "login": "ڤە نۆم هەتن",
        "login-security": "وژت معرفی‌که",
        "nav-login-createaccount": " إ نؤم هةتن سیستم/ حساوو کاربةری سازین",
        "logout": "دەرچێن|خروج",
        "badretype": "گذرواژةلێ گإ نۆیساتة چؤِی یةک نیِن",
        "usernameinprogress": ". دِرێ حساوو دؤرسة مةکإ . خواهشا صبر کةن",
        "userexists": ".نام کاربةری‌ گإ واردت کردئة قبلاً استفاده بیة\n.خواهشا نامێ تر استفادة کةن",
-       "loginerror": "خطای إ نام هةتن سیستم",
+       "loginerror": "نادوەرستی ڤە نۆم هەتن",
        "createacct-error": "خطای  حساوو کاربةری سازین",
        "createaccounterror": "نمآوو ئئ حساووة بِسازین: $1",
        "nocookiesnew": "حساوو کاربةری سازیا، اما هؤمة أ سیستم نهةتینة/نهاتینة.\n{{SITENAME}} برای ورود کاربران به سامانه از کوکی استفاده می‌کند.\nشما کوکی‌ها را از کار انداخته‌اید.\nلطفاً کوکی‌ها را به کار بیندازید، و سپس با نام کاربری و گذرواژهٔ جدیدتان به سامانه وارد شوید.",
        "suspicious-userlogout": "درخواست هؤمة ئةرا  دةرچئن إژ سیستم  رد بیة زیرا به نظر می‌رسد که این  .درخواست توسط یک مرورگر معیوب یا پروکسی میانگیر کل/ارسال بیة",
        "createacct-another-realname-tip": "نام راسکانی/واقعی دڵ بخواهیة.\nاگر آن را وارد کنید هنگام ارجاع به آثارتان و انتساب آن‌ها به شما از نام واقعی‌تان استفاده خواهد شد.",
        "pt-login": "إنۆم هەتِن.",
-       "pt-login-button": "إ نۆم هەتن سیستم",
+       "pt-login-button": "ڤە نۆم هەتن",
        "pt-login-continue-button": "ادامه سی ورود سیستم",
        "pt-createaccount": "حساووئ أرا ووژتان بِسازِن",
        "pt-userlogout": "دەرچێن|خروج",
        "resetpass-no-info": "برای دسترسی مستقیم به این صفحه شما باید به سامانه وارد شده باشید.",
        "resetpass-submit-loggedin": "تغییردائن رمز",
        "resetpass-submit-cancel": "ئآهووسانن/لغو",
-       "resetpass-wrong-oldpass": "گذرÙ\88اÚ\98Ù\87Ù\94 Ù\85Ù\88Ù\82ت Û\8cا Ø§Ø®Û\8cر Ù\86اÙ\85عتبر.\nÙ\85Ù\85Ú©Ù\86 Ø§Ø³Øª Ú©Ù\87 Ø´Ù\85ا Ù\87Ù\85Û\8cÙ\86Ú© Ú¯Ø°Ø±Ù\88اÚ\98Ù\87â\80\8cتاÙ\86 Ø±Ø§ Ø¨Ø§ Ù\85Ù\88Ù\81Ù\82Û\8cت ØªØºÛ\8cÛ\8cر Ø¯Ø§Ø¯Ù\87 Ø¨Ø§Ø´Û\8cد Û\8cا Ø¯Ø±Ø®Ù\88است Û\8cÚ© Ú¯Ø°Ø±Ù\88اÚ\98Ù\87Ù\94 Ù\85Ù\88Ù\82ت ØªØ§Ø²Ù\87 Ú©Ø±Ø¯Ù\87 Ø¨Ø§Ø´Û\8cد.",
+       "resetpass-wrong-oldpass": "گذرواژهٔ موقت یا اخیر نامعتبر.\nممکن است که شما همینک گذرواژه‌تان را تغییر داده باشید یا درخواست یک گذرواژهٔ موقت تازه کرده باشید.",
        "resetpass-recycled": "لطفاً رمز عبور خود را به چیز دیگری غیر از رمز عبور فعلی تنظیم کنید.",
        "resetpass-temp-emailed": "شما با یک کد ایمیل شدهٔ موقت وارد شده‌اید.\nبرای پایان ورود، شما باید رمز عبور جدیدی اینجا وارد کنید:",
        "resetpass-temp-password": ":رمز عبور موقت",
        "passwordreset-emailsentusername": "اگر نشانی پست الکترونیکی مرتبطی موجود باشد، یک نامه برای بازنشانی گذرواژه به آن ارسال خواهد شد.",
        "passwordreset-nocaller": "زنگ مجبور نییه به تأمین کردن",
        "passwordreset-nosuchcaller": "زنگ موجود نییه: $1",
+       "passwordreset-ignored": "به بازنشانی گذرواژه پرداخته نشد. آیا ممکن است که هيچ مهياکننده‌ای برای این کار تنظيم نشده باشد؟",
        "passwordreset-invalidemail": "آدرس ایمیل نامعتبره",
+       "passwordreset-nodata": "یک نام کاربری و یا یک آدرس ايميل، هيچکدام ارائه نشده",
        "changeemail": "تغییر یا حذف نشانی ایمیل",
        "changeemail-header": "برای تغییر ایمیلتان این فرم را کامل کنید. برای حذف ایملیتان کافی است بخش ایمیل را خالی رها کنید و فرم را ارسال کنید.",
        "changeemail-no-info": ".برای دسترسی مستقیم به این صفحه شما باید به سیستم وارد شده باشید",
        "headline_tip": "عنوان سطح ۲",
        "nowiki_sample": "متن قالب‌بندی‌نشده اینجا وارد شود",
        "nowiki_tip": "نادیده‌گرفتن قالب‌بندی ویکی",
+       "image_sample": "نموونە.jpg",
        "image_tip": "تصویر داخل متن",
+       "media_sample": "نموونە.ogg",
        "media_tip": "پیوند پرونده",
        "sig_tip": "امضای هومۀ و برچسب زۀمان",
        "hr_tip": " )خط افقی(از آن کم استفاده کنید",
        "preview": "پیش‌نمایش",
        "showpreview": "پیش‌نمایش",
        "showdiff": "گؤەڕیال(تغییرات) بۆین",
-       "blankarticle": "<strong>هوشدار:</strong> هۆمە وەڵگەتۆن سازیە پەتیە(حالیە).\nأڕ «$1» دۆِ گِل کلیک کِین ، وەڵگە بێ  نۆم جِک(محتوا) مەسازێ.",
+       "blankarticle": "<strong>ئاگاتۆ داشتوو:</strong> هۆمە ڤەڵگەتۆن سازیە پەتیە(خالیە).\nئەڕ «$1» دۆِ گِل کلیک کِین ، ڤەڵگە بێ  نۆمجِک(محتوا) مەسازێ.",
        "anoneditwarning": "<strong>هشدار:</strong> شما وارد نشده‌اید. نشانی آی‌پی شما برای عموم قابل مشاهده خواهد بود اگر هر تغییری ایجاد کنید. اگر <strong>[$1 وارد شوید]</strong> یا <strong>[$2 یک حساب کاربری بسازید]</strong>، ویرایش‌هایتان به نام کاربری‌تان نسبت داده خواهد شد، همراه با مزایای دیگر.",
        "anonpreviewwarning": "''شما به سامانه وارد نشده‌اید. ذخیره کردن باعث می‌شود که نشانی آی‌پی شما در تاریخچهٔ این صفحه ثبت گردد.''",
        "missingsummary": "'''یادآوری:''' شما خلاصهٔ ویرایش ننوشته‌اید.\nاگر دوباره دکمهٔ «$1» را فشار دهید ویرایش شما بدون آن ذخیره خواهد شد.",
        "updated": "(تازة سازی بیة)",
        "note": "'''نکته:'''",
        "previewnote": "'''به یاد داشته باشید که این فقط پیش‌نمایش است.'''\nتغییرات شما هنوز ذخیره نشده‌است!",
-       "continue-editing": "بچۆإ بةخش دةکاری",
+       "continue-editing": "بچۆ ئەڕا بەش دەسکاریکردن",
        "previewconflict": "این پیش‌نمایش منعکس‌کنندهٔ متن ناحیهٔ ویرایش متن بالایی است، به شکلی که اگر متن را ذخیره کنید نمایش خواهد یافت.",
        "session_fail_preview": "'''شرمنده! به علت از دست رفتن اطلاعات نشست کاربری نمی‌توانیم ویرایش شما را پردازش کنیم.'''\nلطفاً دوباره سعی کنید.\nاگر دوباره به همین پیام برخوردید از سامانه [[Special:UserLogout|خارج شوید]] و دوباره وارد شوید.",
        "session_fail_preview_html": "'''متأسفانه امکان ثبت ویرایش شما به خاطر از دست رفتن اطلاعات نشست کاربری وجود ندارد.'''\n\n''با توجه به این که در {{SITENAME}} امکان درج اچ‌تی‌ام‌ال خام فعال است، پیش‌نمایش صفحه پنهان شده تا امکان حملات مبتنی بر جاوااسکریپت وجود نداشته باشد.''\n\n'''اگر مطمئن هستید که این پیش‌نمایش یک ویرایش مجاز است، آن را تکرار کنید.'''\nاگر تکرار پیش‌نمایش نتیجه نداد، از سامانه [[Special:UserLogout|خارج شوید]] و دوباره وارد شوید.",
        "explainconflict": "از وقتی ویرایش این صفحه را آغاز کرده‌اید شخص دیگری آن را تغییر داده است.\nناحیهٔ متنی بالایی شامل متن صفحه به شکل کنونی آن است.\nتغییرات شما در ناحیهٔ متنی پایینی نشان داده شده‌است.\nشما باید تغییراتتان را با متن کنونی ترکیب کنید.\nبا فشردن دکمهٔ «$1» <strong>فقط</strong> متن ناحیهٔ متنی بالایی ذخیره خواهد شد.",
        "yourtext": "متن شما",
        "storedversion": "نسخهٔ ذخیره شده",
-       "nonunicodebrowser": "'''هشدار: مرورگر شما با استانداردهای یونیکد سازگار نیست.'''\nراه حلی به کار گرفته شده تا شما بتوانید صفحات را با امنیت ویرایش کنید: کاراکترهای غیر ASCII به صورت کدهایی در مبنای شانزده به شما نشان داده می‌شوند.",
        "editingold": "'''هشدار: شما در حال ویرایش نسخه‌ای قدیمی از این صفحه هستید.'''\nاگر ذخیره‌اش کنید، هر تغییری که پس از این نسخه انجام شده‌است از بین خواهد رفت.",
        "yourdiff": "تفاوت‌ها",
        "copyrightwarning": "لطفاً توجه داشته‌باشید که همهٔ مشارکت‌ها در {{SITENAME}} منتشرشده تحت $2 در نظر گرفته‌می‌شوند (برای جزئیات بیش‌تر $1 را ببینید).\nاگر نمی‌خواهید نوشته‌هایتان بی‌رحمانه ویرایش و توزیع شوند؛ بنابراین، آنها را اینجا ارائه نکنید.<br />\nشما همچنین به ما تعهد می‌کنید که خودتان این را نوشته‌اید یا آن را از یک منبع با مالکیت عمومی یا مشابه آزاد آن برداشته‌اید (برای جزئیات بیش‌تر $1 را ببینید).\n<strong>کارهای دارای حق تکثیر را بدون اجازه ارائه نکنید!</strong>",
        "yourgender": "ترجیح می‌دهید چگونه توصیف شوید؟",
        "gender-unknown": "هنگام ذکر شما، نرم‌افزار تا جای ممکن از کلمات خنثی از نظر جنسیت استفاده خواهد",
        "gender-male": "پیا",
-       "gender-female": "ژن",
+       "gender-female": "ئافرەت(ژەن)",
        "prefs-help-gender": "انجام این تنظیم اختیاری است.\nنرم‌افزار از این مقدار برای اشارهٔ صحیح به جنسیت و ذکر شما برای دیگران با استفاده از دستور زبان درست استفاده می‌کند.\nاین اطلاعات عمومی خواهند بود.",
        "email": "ایمیل",
        "prefs-help-realname": "نام واقعی اختیاری است.\nاگر وارد شده است هنگام ارجاع به آثارتان و انتساب آن‌ها به شما ممکن است از نام واقعی‌تان استفاده شود.",
        "userrights-changeable-col": "گروه‌هایی که می‌توانید تغییر دهید",
        "userrights-unchangeable-col": "گروه‌هایی که نمی‌توانید تغییر دهید",
        "userrights-conflict": "تعارض دسترسی‌های کاربری! لطفاً بررسی کنید و تغییرات را تأیید کنید.",
-       "group": "گروه:",
+       "group": "داکووکە(گروو):",
        "group-user": "کاربۀر",
        "group-autoconfirmed": "کاربران تأییدشدهٔ خودکار",
        "group-bot": "ربات‌ها",
        "rc_categories": "محدود به این رده‌ها (رده‌ها را با «|» جدا کنید):",
        "rc_categories_any": "هر کدام از منتخب‌ها",
        "rc-change-size-new": " $1دؤما تۀقیر دائن{{PLURAL:$1|بایت|بایتل}}",
-       "newsectionsummary": "/* $1 */ بةخش جدید",
+       "newsectionsummary": "/* $1 */ بەخش نوو",
        "rc-enhanced-expand": "نمایش جزئیات",
        "rc-enhanced-hide": "نهفتن جزئیات",
        "rc-old-title": "ایجادشده با عنوان اصلی «$1»",
        "fileuploadsummary": "خلاصه:",
        "filereuploadsummary": "تغییرات پرونده:",
        "filestatus": "وضعیت حق تکثیر:",
-       "filesource": ":بِنچۀک/مۀنبۀع",
+       "filesource": "بنچەک(منبع)",
        "ignorewarning": "چشم‌پوشی از هشدار و ذخیرهٔ پرونده.",
        "ignorewarnings": "چشم‌پوشی از همهٔ هشدارها",
        "minlength1": "نام پرونده دست کم باید یک حرف باشد.",
        "listgrouprights": "اختیارات گروه‌های کاربری",
        "listgrouprights-summary": "فهرست زیر شامل گروه‌های کاربری تعریف شده در این ویکی و اختیارات داده شده به آن‌ها است.\nاطلاعات بیشتر در مورد هر یک از اختیارات را در [[{{MediaWiki:Listgrouprights-helppage}}]] بیابید.",
        "listgrouprights-key": "* <span class=\"listgrouprights-granted\">اختیارات داده‌شده</span>\n* <span class=\"listgrouprights-revoked\">اختیارات گرفته‌شده</span>",
-       "listgrouprights-group": "گروه",
+       "listgrouprights-group": "داکووکە(گروو)",
        "listgrouprights-rights": "دسترسی‌ها",
        "listgrouprights-helppage": "Help:دسترسی‌های گروهی",
        "listgrouprights-members": "(فهرست اعضا)",
        "blanknamespace": "(سەر/اصلی)",
        "contributions": "هؤمکاریۀل{{GENDER:$1|کاربۀر}}",
        "contributions-title": "مشارکت‌های کاربری $1",
-       "mycontris": "هؤمکاری کِرۀل",
-       "anoncontribs": "هؤمکاری کِرۀل",
+       "mycontris": "بەشاکرەل(هام بێرەل)",
+       "anoncontribs": "بەشاکرەل(هام بێرەل)",
        "contribsub2": "برای {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "حساب کاربری «$1» ثبت نشده‌است.",
        "nocontribs": "هیچ تغییری با این مشخصات یافت نشد.",
        "block": "بستن کاربر.",
        "unblock": "بازکردن کاربر",
        "blockip": "بستن {{GENDER:$1|کاربر}}",
-       "blockip-legend": "بستن کاربر",
        "blockiptext": "از فرم زیر برای بستن دسترسی ویرایش یک نشانی آی‌پی یا نام کاربری مشخص استفاده کنید.\nاین کار فقط فقط باید برای جلوگیری از خرابکاری و بر اساس [[{{MediaWiki:Policy-url}}|سیاست قطع دسترسی]] انجام شود.\nدلیل مشخص این کار را در زیر ذکر کنید (مثلاً با ذکر صفحه‌های به‌خصوصی که مورد خرابکاری واقع شده‌اند).",
        "ipaddressorusername": "نشانی آی‌پی یا نام کاربری:",
        "ipbexpiry": "زمان سرآمدن:",
        "exif-specialinstructions": "دستورالعمل‌های ویژه",
        "exif-headline": "سةر وةڵگة",
        "exif-credit": "صاحب امتیاز/ارائه کننده",
-       "exif-source": "بÙ\90Ù\86Ú\86Û\80Ú©/Ù\85Û\80Ù\86بÛ\80ع",
+       "exif-source": "بÙ\86Ú\86Û\95Ú©(Ù\85Ù\86بع)",
        "exif-editstatus": "وضعیت تحریریه تصویر",
        "exif-urgency": "فوریت/هڵةپڵة",
        "exif-fixtureidentifier": "نام ستون نشریه",
        "exif-gpsdirection-m": "جهت مغناطیسی",
        "exif-ycbcrpositioning-1": "وسط‌چین‌شده",
        "exif-ycbcrpositioning-2": "اشتراکی/هام بةشی",
-       "exif-dc-contributor": "هؤمکاری کِرۀل",
+       "exif-dc-contributor": "بەشاکرەل(هام بێرەل)",
        "exif-dc-coverage": "محدوده مکانی و یا زمانی رسانه",
        "exif-dc-date": "تاریخ(ها)",
        "exif-dc-publisher": "بۀشا کۀر-ناشر",
        "tags-tag": "نام برچسب",
        "tags-display-header": "نمایش در فهرست‌های تغییرات",
        "tags-description-header": "توضیح کامل معنی",
-       "tags-source-header": "بÙ\90Ù\86Ú\86Û\80Ú©/Ù\85Û\80Ù\86بÛ\80ع",
+       "tags-source-header": "بÙ\86Ú\86Û\95Ú©(Ù\85Ù\86بع)",
        "tags-active-header": "فعال(کارکةر)؟",
        "tags-hitcount-header": "تغییرهای برچسب‌دار",
        "tags-actions-header": "کارۀل",
index 48cf1d5..5e3778e 100644 (file)
        "accmailtext": "Nejauši ģenerēta parole lietotājam [[User talk:$1|$1]] tika nosūtīta uz $2.\n\nŠī konta paroli pēc ielogošanās varēs nomainīt ''[[Special:ChangePassword|šeit]]''.",
        "newarticle": "(Jauns raksts)",
        "newarticletext": "Šajā projektā vēl nav lapas ar šādu nosaukumu.\nLai izveidotu lapu, sāc rakstīt teksta logā apakšā (par teksta formatēšanu un sīkākai informācija skatīt [$1 palīdzības lapu]).\nJa tu šeit nonāci kļūdas pēc, vienkārši uzspied <strong>back</strong> pogu pārlūkprogrammā.",
-       "anontalkpagetext": "----''Šī ir diskusiju lapa anonīmam dalībniekam, kurš vēl nav kļuvis par reģistrētu dalībnieku vai arī neizmanto savu dalībnieka vārdu. Tādēļ mums ir jāizmanto skaitliskā IP adrese, lai viņu identificētu.\nŠāda IP adrese var būt vairākiem dalībniekiem.\nJa tu esi anonīms dalībnieks un uzskati, ka tev ir adresēti neatbilstoši komentāri, lūdzu, [[Special:CreateAccount|kļūsti par dalībnieku]] vai arī [[Special:UserLogin|izmanto jau izveidotu dalībnieka vārdu]], lai izvairītos no turpmākām neskaidrībām un tu netiktu sajaukts ar citiem anonīmiem dalībniekiem.''",
+       "anontalkpagetext": "----\n<em>Šī ir anonīma dalībnieka, kurš vēl nav izveidojis lietotāja kontu vai to nelieto, diskusiju lapa.</em>\nTādēļ mums ir jāizmanto IP adrese, lai viņu identificētu.\nŠāda IP adrese var būt vairākiem dalībniekiem.\nJa tu esi anonīms dalībnieks un uzskati, ka tev ir adresēti neatbilstoši komentāri, lūdzu, [[Special:CreateAccount|izveido kontu]] vai [[Special:UserLogin|pieslēdzies]], lai izvairītos no turpmākām neskaidrībām un tu netiktu sajaukts ar citiem anonīmiem dalībniekiem.",
        "noarticletext": "Šajā lapā šobrīd nav nekāda teksta, tu vari [[Special:Search/{{PAGENAME}}|meklēt citās lapās pēc šīs lapas nosaukuma]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} meklēt saistītos reģistru ierakstos] vai arī [{{fullurl:{{FULLPAGENAME}}|action=edit}} sākt rediģēt šo lapu]</span>.",
        "noarticletext-nopermission": "Šajā lapā pašlaik nav nekāda teksta.\nTu vari [[Special:Search/{{PAGENAME}}|meklēt šīs lapas nosaukumu]] citās lapās,\nvai <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} meklēt saistītus reģistru ierakstus]</span>, bet jums nav atļauja izveidot šo lapu.",
        "userpage-userdoesnotexist": "Lietotājs \"<nowiki>$1</nowiki>\" nav reģistrēts.\nLūdzu, pārliecinies vai vēlies izveidot/izmainīt šo lapu.",
        "prefs-editor": "Redaktors",
        "prefs-preview": "Priekšskatījums",
        "prefs-advancedrc": "Papildu iespējas",
+       "prefs-opt-out": "Atteikties no uzlabojumiem",
        "prefs-advancedrendering": "Papildu iespējas",
        "prefs-advancedsearchoptions": "Papildu iespējas",
        "prefs-advancedwatchlist": "Papildu iespējas",
        "action-userrights-interwiki": "mainīt dalībnieku tiesības citās Vikipēdijās",
        "action-siteadmin": "bloķēt vai atbloķēt datubāzi",
        "action-sendemail": "sūtīt e-pastus",
+       "action-editmyoptions": "labot savas izvēles",
        "action-deletechangetags": "dzēst iezīmes no datubāzes",
        "nchanges": "$1 {{PLURAL:$1|izmaiņas|izmaiņa|izmaiņas}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|kopš pēdējā apmeklējuma}}",
        "listfiles-delete": "dzēst",
        "listfiles-summary": "Šajā īpašajā lapā ir redzami visi augšupielādētie faili.",
        "listfiles_search_for": "Meklēt failu pēc vārda:",
+       "listfiles-userdoesnotexist": "Dalībnieks \"$1\" nav reģistrēts.",
        "imgfile": "fails",
        "listfiles": "Attēlu uzskaitījums",
        "listfiles_thumb": "Sīktēls",
        "apisandbox-dynamic-parameters-add-placeholder": "Parametra nosaukums",
        "apisandbox-deprecated-parameters": "Novecojuši parametri",
        "apisandbox-results": "Rezultāti",
+       "apisandbox-sending-request": "Sūta API pieprasījumu...",
+       "apisandbox-loading-results": "Saņem API rezultātus...",
+       "apisandbox-request-selectformat-label": "Rādīt pieprasījuma datus kā:",
        "apisandbox-request-format-url-label": "URL vaicājuma teksts",
        "apisandbox-request-url-label": "Pieprasījuma URL:",
        "apisandbox-request-json-label": "Pieprasījuma JSON:",
        "protectexpiry": "Beidzas:",
        "protect_expiry_invalid": "Beigu termiņš ir nederīgs.",
        "protect_expiry_old": "Beigu termiņs ir pagātnē.",
+       "protect-unchain-permissions": "Pieslēgt papildu aizsargāšanas iespējas",
        "protect-text": "Šeit var apskatīt un izmainīt lapas <strong>$1</strong> aizsardzības līmeni.",
        "protect-locked-access": "Jūsu kontam nav atļaujas mainīt lapas aizsardzības pakāpi.\nPašreizējie lapas '''$1''' iestatījumi ir:",
        "protect-cascadeon": "Šī lapa pašlaik ir aizsargāta, jo tā ir iekļauta {{PLURAL:$1|šajās lapās|šajā lapā|šajās lapās}} (mainot šīs lapas aizsardzības līmeni aizsardzība netiks noņemta):",
        "protect-default": "Atļaut visiem lietotājiem",
        "protect-fallback": "Atļaut tikai lietotājiem ar \"$1\" atļauju",
-       "protect-level-autoconfirmed": "Atļaut tikai autoapstiprinātiem lietotājiem",
+       "protect-level-autoconfirmed": "Atļaut tikai pašpārbaudītajiem",
        "protect-level-sysop": "Atļaut tikai administratoriem",
        "protect-summary-cascade": "kaskāde",
        "protect-expiring": "līdz $1 (UTC)",
        "protect-expiring-local": "beidzas $1",
        "protect-expiry-indefinite": "bezgalīgs",
-       "protect-cascade": "Aizsargāt šajā lapā iekļautās lapas (veidnes) ''(cascading protection)''",
+       "protect-cascade": "Aizsargāt šajā lapā iekļautās lapas un veidnes (kaskādes aizsardzība)",
        "protect-cantedit": "Tu nevari izmainīt šīs lapas aizsardzības līmeņus, tāpēc, ka tur nevari izmainīt šo lapu.",
        "protect-othertime": "Cits laiks:",
        "protect-othertime-op": "cits laiks",
        "pageinfo-article-id": "Lapas ID",
        "pageinfo-language": "Lappuses satura valoda",
        "pageinfo-content-model": "Lapas satura modelis",
+       "pageinfo-content-model-change": "mainīt",
        "pageinfo-robot-policy": "Indeksācija ar robotiem",
        "pageinfo-robot-index": "Atļauta",
        "pageinfo-robot-noindex": "Aizliegta",
        "pageinfo-watchers": "Lapas uzraudzītāju skaits",
+       "pageinfo-visiting-watchers": "Lapas uzraudzītāju skaits, kuri apskatījuši pēdējos labojumus",
        "pageinfo-few-watchers": "Mazāk kā $1 {{PLURAL:$1|uzraudzītāju|uzraudzītājs|uzraudzītāju}}",
        "pageinfo-redirects-name": "Pāradresāciju skaits uz šo lapu",
        "pageinfo-subpages-name": "Šīs lapas apakšlapas",
        "pageinfo-edits": "Kopējais izmaiņu skaits",
        "pageinfo-authors": "Kopējais atsevišķu autoru skaits",
        "pageinfo-recent-edits": "Izmaiņu skaits (pēdējās $1)",
+       "pageinfo-recent-authors": "Neseno lapas labotāju skaits",
        "pageinfo-magic-words": "{{PLURAL:$1|Maģiskie vārdi|Maģiskais vārds|Maģiskie vārdi}} ($1)",
        "pageinfo-hidden-categories": "{{PLURAL:$1|Slēptas kategorijas|Slēpta kategorija|Slēptas kategorijas}} ($1)",
        "pageinfo-templates": "{{PLURAL:$1|Iekļautās veidnes|Iekļautā veidne|Iekļautās veidnes}} ($1)",
index 507d04f..2186a3b 100644 (file)
@@ -8,7 +8,8 @@
                        "Bennylin",
                        "아라",
                        "Macofe",
-                       "Mbrt"
+                       "Mbrt",
+                       "Empu"
                ]
        },
        "tog-underline": "Garisen ngisoré pranala:",
@@ -36,9 +37,9 @@
        "tog-enotifminoredits": "Kirimna imel maring inyong uga nek ana suntingan cilik nang kaca lan berkas",
        "tog-enotifrevealaddr": "Tidokna alamat imel-e inyong nang imel notifikasi",
        "tog-shownumberswatching": "Tidhokna jumlah pangawas",
-       "tog-oldsig": "Tapak asma sekiye:",
+       "tog-oldsig": "Tapak asma:",
        "tog-fancysig": "Tapak asma dianggep dadi teks wiki (ora nganggo pranala otomatis)",
-       "tog-uselivepreview": "Gunakna pratayang langsung",
+       "tog-uselivepreview": "Tonton kaca sedurungé tapi aja dimuat ulang",
        "tog-forceeditsummary": "Emutna inyong anggere durung ngisi kotak ringkesan suntingan",
        "tog-watchlisthideown": "Umpetna suntingane inyong sekang daftar pangawasan",
        "tog-watchlisthidebots": "Umpetna suntingane bot sekang daftar pangawasan",
        "tog-showhiddencats": "Tidokna kategori sing diumpetna",
        "tog-norollbackdiff": "Aja ndeleng perbedaane seuwise nglakokna pambalikan",
        "tog-useeditwarning": "Elingna inyong angger ninggalna kaca panyuntingan sing durung disimpen owahane",
-       "tog-prefershttps": "Gunakna koneksi aman terus angger mlebu log",
+       "tog-prefershttps": "Kudu nganggo koneksi sing aman terus angger mlebu log",
        "underline-always": "Saben",
        "underline-never": "Ora tau",
-       "underline-default": "Gawane kulitutawa peramban",
+       "underline-default": "Kulit utawa gawan peramban",
        "editfont-style": "Modhèl aksara (font) nang kotak suntingan:",
-       "editfont-default": "Gawane peramban",
        "editfont-monospace": "Aksara (font) Monospace",
        "editfont-sansserif": "Aksara (font) Sans-serif",
        "editfont-serif": "Aksara (font) Serif",
        "newwindow": "(buka nang jendhéla anyar)",
        "cancel": "Ora Sida",
        "moredotdotdot": "Liyané...",
-       "morenotlisted": "Daftar kiye ora kumplit.",
+       "morenotlisted": "Daftar kiyé ora kumplit.",
        "mypage": "Kaca",
        "mytalk": "Dopokan",
        "anontalk": "Dhiskusi IP kiye",
        "navigation": "pandhu arah",
        "and": "&#32;lan",
-       "qbfind": "Goleti",
-       "qbbrowse": "Jelajahi",
-       "qbedit": "Sunting",
-       "qbpageoptions": "Kaca kiye",
-       "qbmyoptions": "Kaca-ne inyong",
        "faq": "FAQ (Pitakonan sing sering ditakokna)",
-       "faqpage": "Project:FAQ",
        "actions": "Tindakan",
        "namespaces": "Bilik jeneng",
        "variants": "Varian",
        "edit-local": "Sunting deskripsi lokal",
        "create": "Gawe",
        "create-local": "Tambahna pawedharan lokal",
-       "editthispage": "Sunting kaca kiye",
-       "create-this-page": "Gawe kaca kiye",
        "delete": "Busek",
-       "deletethispage": "Busak kaca kiye",
-       "undeletethispage": "Batalna pembusekan kaca kiye",
        "undelete_short": "Batalna pambusakan $1 {{PLURAL:$1|suntingan|suntingan}}",
        "viewdeleted_short": "Deleng {{PLURAL:$1|siji suntingan|$1 suntingan}} sing wis dibusak",
        "protect": "Direksa",
        "protect_change": "owahi",
-       "protectthispage": "Reksa kaca kiye",
        "unprotect": "Owahi pangreksan",
-       "unprotectthispage": "Owahi pangreksane kaca kiye",
        "newpage": "Kaca anyar",
-       "talkpage": "Dhiskusikna kaca kiye",
        "talkpagelinktext": "Dopokan",
        "specialpage": "Kaca khusus",
        "personaltools": "Piranti pribadi",
-       "articlepage": "Deleng isi tulisan",
        "talk": "bahas",
        "views": "Tampilan",
        "toolbox": "Pekakas",
-       "userpage": "Ndeleng kaca panganggo",
-       "projectpage": "Deleng kaca proyèk",
        "imagepage": "Deleng kaca berkas",
        "mediawikipage": "Ndeleng kaca pesen sistem",
        "templatepage": "Ndeleng kaca cithakan",
        "redirectedfrom": "(Dialihna sekang $1)",
        "redirectpagesub": "Kaca pangalihan",
        "redirectto": "Dialihna maring:",
-       "lastmodifiedat": "Kaca kiye nembe diowahi dong jam $2, tanggal $1.",
+       "lastmodifiedat": "Kaca kiyé nembé diowahi jam $2, tanggal $1.",
        "viewcount": "Kaca kiye uwis diakses ping {{PLURAL:$1|sepisan|$1}}",
        "protectedpage": "Kaca sing direksa",
        "jumpto": "Mlumpat maring:",
        "perfcached": "Data kiye dijikot sekang singgahan (''cache'') lan ndeyane dudu data pungkasan. Paling akeh {{PLURAL:$1|siji asil|$1 asil}} disediakna nang papan singgahan.",
        "perfcachedts": "Data kiye dijikot sekang singgahan (''cache''), lan dianyarna keri dhewek dong $1. Paling akeh ana  {{PLURAL:$4|siji asil|$4 asil}} disediakna nang papan singgahan.",
        "querypage-no-updates": "Update nggo kaca kiye lagi dipateni.\nData sing ana nang kene sekiye ora teyeng dibaleni unggah maning.",
-       "viewsource": "Deleng sumbere",
+       "viewsource": "Deleng sumberé",
        "viewsource-title": "Deleng sumbere nggo $1",
        "actionthrottled": "Tindakan diwatesi",
        "actionthrottledtext": "Kanggo ngukur anti-spam, Rika diwatesi gole nglakoni tikdakan kiye keseringen nang wektu sing cendhak, lan Rika uwis nglewati watese kuwe.\nMonggo dijajal maning nang sawetara menit.",
        "nocookieslogin": "{{SITENAME}} nggunakna ''cookies'' nggo log panganggone.\n''Cookies'' nang panjlajah web Rika dipateni.\nMonggo diaktfna lan jajal maning.",
        "nocookiesfornew": "Akun panganggo ora digawe, jalaran inyong ora teyeng mastikna sumbere.\nPastekna Rika uwis ngaktifna ''cookies'', trus baleni muat kaca kiye maning lan jajal sepisan maning.",
        "noname": "Jeneng panganggo sing Rika lebokna ora sah.",
-       "loginsuccesstitle": "Sukses mlebu log",
+       "loginsuccesstitle": "Mlebu log",
        "loginsuccess": "'''Rika sekiye mlebu log nang {{SITENAME}} nganggo jeneng \"$1\".'''",
        "nosuchuser": "Ora ana panganggo sing jenenge \"$1\".\nJeneng panganggo kuwe dibedakna nang kapitalisasi.\nPriksa maning ejaane Rika, utawa [[Special:CreateAccount|gawe akun anyar]]",
        "nosuchusershort": "Ora ana panganggo sing jenenge \"$1\".\nJajal dipriksa maning ejaane Rika.",
        "createaccount-title": "Gawe akun kanggo {{SITENAME}}",
        "createaccount-text": "Ana wong sing gawe akun nggo alamat imel-e Rika nang {{SITENAME}} ($4) nganggo jeneng \"$2\", lan tembung sandhi \"$3\".\nRika mendingan mlebu log disit lan ganti tembung sandine sekiye.\n\nRika teyeng nglirwakna pesen kiye anggere akun kiye kuwe jebule anu salah gawe.",
        "login-throttled": "Rika wis kakehan gole njajal mlebu log.\nTulung ngenteni $1 sedurunge njajal maning.",
-       "login-abort-generic": "Proses mlebu log Rika ora gagal - Dibatalna",
+       "login-abort-generic": "Rika gagal mlebu log - Dibatalna",
        "login-migrated-generic": "Akune rika uwis dipindahna, lan jeneng panganggone rika wis ora ana maning nang wiki kiye.",
        "loginlanguagelabel": "Basa: $1",
        "suspicious-userlogout": "Panjalukan Rika nggo metu log ditolak jalarak ketone dikirim nang panjlajah sing rusak utawa proksi panyinggah (''caching proxy'').",
        "newpassword": "Tembung sandi anyar:",
        "retypenew": "Ketik maning tembung sandhi:",
        "resetpass_submit": "Nata tembung sandhi lan mlebu log",
-       "changepassword-success": "Tembung sandhi Rika wis sukses diowahi!",
+       "changepassword-success": "Sandhiné Rika uwis diganti!",
        "changepassword-throttled": "Rika wis kakehan gole njajal mlebu log.\nTulung ngenteni $1 sedurunge njajal maning.",
        "resetpass_forbidden": "Tembung sandhi ora teyeng diganti",
        "resetpass-no-info": "Rika kudu mlebu log kanggo ngakses kaca kiye sacara langsung.",
        "resetpass-submit-loggedin": "Ganti tembung sandhi",
        "resetpass-submit-cancel": "Batal",
-       "resetpass-wrong-oldpass": "Tembung sandhi ora sah.\nRika ndeyan  uwis kasil ngganti tembung sandhine Rika utawa wis njaluk tembung sandhi sauntara sing anyar.",
+       "resetpass-wrong-oldpass": "Sandhi siki utawa sementara ora sah.\nRika ndeyan  uwis kasil ngganti tembung sandhiné Rika utawa wis njaluk tembung sandhi sementara sing anyar.",
        "resetpass-recycled": "Monggo diganti tembung sandhine rika nganggo sing sejen sekang tembung sandhi sekiye.",
        "resetpass-temp-emailed": "Rika mlebu long nganggo kode sawetara sing ana nang surel.\nKanggo ngrampungna gole mlebu log, rika kudu ngatur tembung sandhi anyar nang kene:",
        "resetpass-temp-password": "Tembung sandhi sauntara:",
        "changeemail": "Ganti alamat imel",
        "changeemail-header": "Ganti alamat imel-e akun",
        "changeemail-no-info": "Rika kudu mlebu log kanggo ngakses kaca kiye sacara langsung.",
-       "changeemail-oldemail": "Alamat imel sekiye:",
+       "changeemail-oldemail": "Alamat imel sekiyé:",
        "changeemail-newemail": "Alamat imel anyar:",
        "changeemail-none": "(ora ana)",
        "changeemail-password": "Tembung sandhi {{SITENAME}} Rika:",
        "changeemail-submit": "Ganti imel",
        "resettokens-no-tokens": "Ora ana token sing arep disetel maning.",
-       "resettokens-token-label": "$1 (biji sekiye:$2)",
+       "resettokens-token-label": "$1 (siki bijiné:$2)",
        "resettokens-done": "Token wis disetel maning.",
        "resettokens-resetbutton": "Nyetel maning token sing dipilih",
        "bold_sample": "Tèks kiye bakal dicithak kandel",
        "sig_tip": "Tapak astane Rika nganggo tandha wektu",
        "hr_tip": "Garis horisontal",
        "summary": "Ringkesan:",
-       "subject": "Subyek/judhul:",
+       "subject": "Subyèk:",
        "minoredit": "Kiye suntingan cilik",
        "watchthis": "Awasi kaca kiyé",
        "savearticle": "Terbitna Kaca",
        "cantcreateaccount-text": "Ngawe akun sekang alamat IP kiye ('''$1''') wis diblokir nang [[User:$3|$3]].\n\nAlesane miturut $3 yakuwe ''$2''",
        "viewpagelogs": "Deleng log-e kaca kiye",
        "nohistory": "Ora ana sajarah panyuntingan kanggo kaca kiye.",
-       "currentrev": "Revisi sekiye",
+       "currentrev": "Revisi sekiyé",
        "currentrev-asof": "Revisi paling anyar nang tanggal $1",
        "revisionasof": "Revisi per $1",
        "revision-info": "Revisi per $1; $2",
        "previousrevision": "Revisi sedurunge",
        "nextrevision": "Revisi lewih anyar",
-       "currentrevisionlink": "Revisi sekiye",
-       "cur": "sekiye",
+       "currentrevisionlink": "Revisi sekiyé",
+       "cur": "siki",
        "next": "Lanjutane",
        "last": "sedurunge",
        "page_first": "kapisan",
        "searchprofile-images": "Multimedia",
        "searchprofile-everything": "Kabèh",
        "searchprofile-advanced": "Lanjutan",
-       "searchprofile-articles-tooltip": "Panggolèkan nang $1",
+       "searchprofile-articles-tooltip": "Nggoléti neng $1",
        "searchprofile-images-tooltip": "Panggolèkan berkas",
        "searchprofile-everything-tooltip": "Goleti kabeh isi (termasuke kaca dhiskusi)",
        "searchprofile-advanced-tooltip": "Goleti nang bilik jeneng biasa",
        "rightslogtext": "Kiye log pangowahan maring hak-hak panganggo.",
        "action-read": "maca kaca kiye",
        "action-edit": "nyunting kaca kiye",
-       "action-createpage": "gawe kaca",
-       "action-createtalk": "nggawé kaca dhiskusi",
+       "action-createpage": "gawé kaca kiyé",
+       "action-createtalk": "gawé kaca dhiskusiné",
        "action-createaccount": "nggawé akun panganggo kiye",
        "action-minoredit": "nandani suntingan minangka suntingan cilik",
        "action-move": "mindahna kaca kiye",
        "filehist-deleteall": "busek kabeh",
        "filehist-deleteone": "busek",
        "filehist-revert": "balekna",
-       "filehist-current": "Sekiye",
+       "filehist-current": "siki",
        "filehist-datetime": "Tanggal/Wektu",
        "filehist-thumb": "Miniatur (''thumbnail'')",
        "filehist-thumbtext": "Miniatur nggo versi dong $1",
        "emailsenttext": "Pesen imele Rika wis dikirim.",
        "emailuserfooter": "Layang kiye dikirimna sekang $1 ming $2 nggunakna fungsi \"Layangpanganggo\" nang {{SITENAME}}.",
        "watchlist": "Daftar pangawasan",
-       "mywatchlist": "Daftar sawangané inyong",
+       "mywatchlist": "Daftar sawangan",
        "watchlistfor2": "Kanggo $1 $2",
        "watch": "Pantau",
        "unwatch": "Batalna pantauan",
        "contributions-title": "Kontribusi panganggo kanggo $1",
        "mycontris": "Kontribusi",
        "contribsub2": "Kanggo $1 ($2)",
-       "uctop": "(sekiye)",
+       "uctop": "(siki)",
        "month": "Sekang sasi (lan sadurungé):",
        "year": "Sekang taun (lan sadurunge):",
        "sp-contributions-newbies": "Tidokna kontribusine panganggo anyar thok",
index 257ad66..bb0bed3 100644 (file)
        "showdiff": "बदल दाखवा",
        "blankarticle": "<strong>ईशारा:</strong>आपण तयार करीत असलेले पान कोरे आहे.जर आपण पुन्हा \"$1\" टिचकले तर,कोणताही आशय/मजकूर नसलेले पान तयार होईल.",
        "anoneditwarning": "<strong>इशारा:</strong> तुम्ही विकिपीडियाचे सदस्य म्हणून सनोंद-प्रवेश (लॉग-इन) केलेले नाही.आपण काही संपादन केले तर, तुमचा अंकपत्ता (आयपी) सार्वजनिक रित्या दृष्य होईल. जर आपण <strong>[$1 सनोंद प्रवेश केला]</strong> किंवा <strong>[$2 खाते उघडले]</strong>,तर आपण केलेली संपादने ही आपल्या नांवाशी संलग्न होतील, त्याशिवाय याचे इतरही फायदे आहेत.",
-       "anonpreviewwarning": "\"'''सावधान:''' à¤¤à¥\81मà¥\8dहà¥\80 à¤µà¤¿à¤\95िपà¥\80डियाà¤\9aà¥\87 à¤¸à¤¦à¤¸à¥\8dय à¤®à¥\8dहणà¥\82न à¤¸à¤¨à¥\8bà¤\82द-पà¥\8dरवà¥\87श (लà¥\89à¤\97-à¤\87न) à¤\95à¥\87लà¥\87ला à¤¨à¤¾à¤¹à¥\80. à¤¯à¤¾ à¤ªà¤¾à¤¨à¤¾à¤\9aà¥\8dया à¤¸à¤\82पादन à¤\87तिहासात à¤¤à¥\81मà¤\9aा à¤\85à¤\82à¤\95पतà¥\8dता (à¤\86य.पà¥\80. à¥²ड्रेस) नोंदला जाईल.\"",
+       "anonpreviewwarning": "\"'''सावधान:''' à¤¤à¥\81मà¥\8dहà¥\80 à¤µà¤¿à¤\95िपà¥\80डियाà¤\9aà¥\87 à¤¸à¤¦à¤¸à¥\8dय à¤®à¥\8dहणà¥\82न à¤¸à¤¨à¥\8bà¤\82द-पà¥\8dरवà¥\87श (लà¥\89à¤\97-à¤\87न) à¤\95à¥\87लà¥\87ला à¤¨à¤¾à¤¹à¥\80. à¤¯à¤¾ à¤ªà¤¾à¤¨à¤¾à¤\9aà¥\8dया à¤¸à¤\82पादन à¤\87तिहासात à¤¤à¥\81मà¤\9aा à¤\85à¤\82à¤\95पतà¥\8dता (à¤\86य.पà¥\80. à¤\85à¥\85ड्रेस) नोंदला जाईल.\"",
        "missingsummary": "'''आठवण:''' आपण संपादन सारांश पुरवलेला नाही.आपण 'जतन करा' वर पुन्हा टिचकी मारली तर, ते त्याशिवायच जतन होईल.",
        "selfredirect": "<strong>ईशारा:</strong>आपण या पानास, त्याच पानावर पुनर्निर्देशित करीता आहात.\nआपण पुनर्निर्देशनासाठी चूकिचे लक्ष्य नमूद केले आहे किंवा आपण चूकिच्या पानाचे संपादन करीत आहात.\nजर आपण पुन्हा \"$1\" टिचकले तर, कसेहीकरुन ते पुनर्निर्देशन तयार होईल.",
        "missingcommenttext": "कृपया खाली प्रतिक्रिया भरा.",
        "action-rollback": "या आधीच्या सदस्याने नुकतेच संपादन केलेले एखादे विशिष्ट पानाचे बदल लवकर पूर्वस्थितीत न्या",
        "action-import": "दुसऱ्या विकीवरुन पाने आयात करा",
        "action-importupload": "अपभारीत संचिकेतून पाने आयात करा",
-       "action-patrol": "à¤\87तराà¤\82à¤\9aà¥\80 संपादनांवर 'पहारा दिला' म्हणून खूण करा",
+       "action-patrol": "à¤\87तराà¤\82à¤\9aà¥\8dया संपादनांवर 'पहारा दिला' म्हणून खूण करा",
        "action-autopatrol": "आपल्या संपादनांवर पहारा दिल्याची खूण करा",
        "action-unwatchedpages": "पहारा न दिलेल्या पानांची यादी पहा",
        "action-mergehistory": "पानाचा इतिहास विलीन करा",
        "timezone-local": "स्थानिक",
        "duplicate-defaultsort": "'''ताकिद:''' डिफॉल्ट सॉर्ट की \"$2\" ओवर्राइड्स अर्लीयर डिफॉल्ट सॉर्ट की \"$1\".",
        "version": "आवृत्ती",
-       "version-extensions": "सà¥\8dथापित à¤µà¤¿à¤¸à¥\8dतार",
+       "version-extensions": "यà¥\87थà¥\87 à¤¸à¥\8dथापलà¥\87लà¥\80 à¤µà¤¿à¤¸à¥\8dतारà¤\95à¥\87",
        "version-skins": "इंस्टॉल केल्या गेलेल्या त्वचा",
        "version-specialpages": "विशेष पाने",
        "version-parserhooks": "पृथकक अंकुश",
index b037fa6..7687415 100644 (file)
        "rcfilters-savedqueries-apply-and-setdefault-label": "Opprett standardfilter",
        "rcfilters-savedqueries-cancel-label": "Avbryt",
        "rcfilters-savedqueries-add-new-title": "Lagre de gjeldende filterinnstillingene",
+       "rcfilters-savedqueries-already-saved": "Disse filtrene er allerede lagret",
        "rcfilters-restore-default-filters": "Gjenopprett standardfiltre",
        "rcfilters-clear-all-filters": "Nullstill alle filtre",
        "rcfilters-show-new-changes": "Vis de nyeste endringene",
index a7cb8f8..1d155bc 100644 (file)
        "rcfilters-savedqueries-apply-and-setdefault-label": "Standaard filter aanmaken",
        "rcfilters-savedqueries-cancel-label": "Annuleren",
        "rcfilters-savedqueries-add-new-title": "Huidige filter instellingen opslaan",
+       "rcfilters-savedqueries-already-saved": "Deze filters zijn al opgeslagen",
        "rcfilters-restore-default-filters": "Standaard filters terugzetten",
        "rcfilters-clear-all-filters": "Alle filters verwijderen",
        "rcfilters-show-new-changes": "Toon nieuwste wijzigingen",
index 1e13db1..15d0f33 100644 (file)
        "changepassword-success": "ستاسې پټنوم بدل شو!",
        "changepassword-throttled": "تاسې څو واره هڅه کړې چې غونډال ته ورننوځۍ.\nلطفاً د بيا هڅې نه مخکې $1 شېبې تم شۍ.",
        "botpasswords": "روباټ پټنومونه",
+       "botpasswords-summary": "<em>د بوټ پټنومونه</em> د اصلي پټنوم کارولو څخه پرته د ای پی ادرس سره ګڼون ته لاسرسي نه ورکول کيږی. د کاروونکي موجوده لاسرسی ممکن محدود وي کله چې د روباټ پاسورډ داخل شي.\nکه تاسو نه پوهیږئ چې څه شی کولی شئ له دې سره وکړئ، تاسو ممکن هیڅکله هم ونه کړئ. هیڅوک باید له تاسو څخه د دې د ورکولو لپاره نه وپوښتل شي.",
+       "botpasswords-disabled": "د بوټ پټنوم ناممکنه دي.",
+       "botpasswords-no-central-id": "د بوټ د پټنوم کارولو لپاره، تاسو باید په مرکزي حساب کې ننوتلي ياست.",
        "botpasswords-existing": "د بوټ موجود پټ نومونه",
        "botpasswords-createnew": "نوی پټنوم (پاسورډ) جوړ کړي",
        "botpasswords-editexisting": "د بوټ موجود پاسورډ جوړ کړئ",
        "botpasswords-label-delete": "ړنگول",
        "botpasswords-label-resetpassword": "پټوم بدل کړي",
        "botpasswords-label-grants": "تطبیق وړ ګرانټ:",
+       "botpasswords-help-grants": "هر اجازه روبوټ ته اجازه ورکوي چې هغه واک ته لاسرسۍ ومومي کوم چې ستاسو حساب ساتي. د اجازې فعالول دلته، نوې لاسرسی نشته چې ستاسو حساب اوس مهال نلري. د نورو معلوماتو لپاره [[Special:ListGrants|table of grants]] وګورئ.",
        "botpasswords-label-grants-column": "ورکړل شو",
        "botpasswords-bad-appid": "د بوټ نوم \"$1\" وجود نلري.",
        "botpasswords-insert-failed": "د بوټ \"$1\" نوم په ورګډولو کي پاتې راغلې دا نوم د پخوا څخه ورګډ سوي وو?",
+       "botpasswords-update-failed": "د بوټ نوم په نوي کولو کې ناکام شوې \"$1\".ایا دا ړنګ شوی دی؟",
        "botpasswords-created-title": "د بوټ پټنوم جوړ شو",
        "botpasswords-created-body": "د بوټ پټنوم د بوټ \"$1\" د کارن \"$2\" لپاره جوړ شو.",
        "botpasswords-updated-title": "د بوټ پټنوم آپډيټ سو",
        "botpasswords-updated-body": "د بوټ پټنوم د بوټ \"$1\" د کارن \"$2\" لپاره آپډيټ شو.",
        "botpasswords-deleted-title": "د بوټ پټنوم ړنګ شو",
        "botpasswords-deleted-body": "د بوټ پټنوم د بوټ \"$1\" د کارن \"$2\" لپاره ړنګ شو.",
+       "botpasswords-newpassword": "<strong>$2</strong> د ګڼون سره د ننوتلو لپاره نوی پټنوم <strong>$1</strong> دی. <em>مهرباني وکړئ دا د راتلونکی لپاره وساتئ.</em> <br> (د زړو روبوټونو لپاره چې یو کارنومینر ته اړتیا لري چې خپل ګڼون سره سمون لري، تاسو کولی شئ له <strong>$3</strong> لاندې يو کارننوم او <strong>$4</strong> د پټنوم په توګه کاروئ.)",
+       "botpasswords-no-provider": "د بوټ شفر د غونډو وړاندې کول شتون نلري.",
+       "botpasswords-restriction-failed": "د بوټ پاسورډ محدودیتونه د دې ننوتنې مخه نیسي",
+       "botpasswords-invalid-name": "په کارنۍ نومول شوی کې د بوټو د پاسورډ جلا کول شامل نه دی (\"$1\").",
+       "botpasswords-not-exist": "کارن \"$1\"  يو روباټ پټنوم نه لري نوم \"$2\".",
        "resetpass_forbidden": "پټنومونه مو نه شي بدلېدلای",
+       "resetpass_forbidden-reason": "پټنومونه مو نه شي بدلېدلای: $1",
        "resetpass-no-info": "دې مخ ته د لاسرسي لپاره بايد غونډال کې ورننوځۍ.",
        "resetpass-submit-loggedin": "پټنوم بدلول",
        "resetpass-submit-cancel": "ناگارل",
-       "resetpass-wrong-oldpass": "Ù\84Ù\86Ú\89Ù\85Ù\87اÙ\84 Ø§Ù\88 Ù\8aا Ù\87Ù\85 Ø§Ù\88سÙ\86Û\8c Ù¾Ù¼Ù\86Ù\88Ù\85 Ù\85Ù\88 Ù\86اسÙ\85 Ø¯Û\8c",
+       "resetpass-wrong-oldpass": "Ù\86اسÙ\85 Ù\84Ù\86Ú\89Ù\85Ù\87اÙ\84Ù\87 Û\8cا Ø§Ù\88سÙ\86Û\8c Ù¾Ù¼Ù\86Ù\88Ù\85.\nتاسÙ\88 Ù\85Ù\85Ú©Ù\86Ù\86 Ù\85خکÛ\90 Ø®Ù¾Ù\84 Ù¾Ù¼Ù\86Ù\88Ù\85 Ø¨Ø¯Ù\84 Ú©Ú\93Û\8c Ù\88Ù\8a Û\8cا Ø¯ Ù\86Ù\88Ù\8a Ù\84Ù\86Ú\89Ù\85Ù\87اÙ\84Ù\87 Ù¾Ù¼Ù\86Ù\88Ù\85 ØºÙ\88Ú\9aتÙ\86Ù\87 Ú©Ú\93Û\90 Ù\88Û\8c.",
        "resetpass-recycled": "لطفاً پټنوم مو داسې وټاکئ چې له اوسني پټنوم سره يې توپير وي.",
        "resetpass-temp-emailed": "تاسې د يو لنډمهاله کوډ په مرسته چې دربرېښليک شوی و، ننوتلي ياست. \nد ننوتلو د بشپړولو لپاره بايد ځانته يو نوی پټنوم دلته وټاکئ:",
        "resetpass-temp-password": "لنډمهالی پټنوم:",
        "passwordreset-domain": "شپول:",
        "passwordreset-email": "برېښليک پته:",
        "passwordreset-emailtitle": "د {{SITENAME}} د گڼون څرگندنې",
+       "passwordreset-emailtext-ip": "یک نفر (شاید تاسو، دآی‌پی پتی سره$1) د خپل پټنوم بیا سمولو لپاره غوښتنه{{SITENAME}} ($4) کړی ده. {{PLURAL:$3|ګڼون|ګڼونونه}} لاندې کارن د دې برېښنالیک سره تړلی دی:\n\n$2\n\n{{PLURAL:$3|دا یو لنډمهاله پاسورډ دی|دا شفرونه لنډمهاله دي}} وروسته تر {{PLURAL:$5|یوه ورځ|$5 ورځی}} به باطل شي.\nتاسو باید اوس ننوځئ او نوي شفرونه غوره کړئ. که تاسو فکر کوئ چې بل چا دا غوښتنه کړې ده یا که تاسو خپل اصلي پټنوم په یاد ولرئ او تاسو نور یې نه غواړئ بدلون ومومئ، تاسو کولی شئ دا پیغام غفلت کړئ او خپل پخوانی پاسورډ کارولو ته دوام ورکړئ.",
+       "passwordreset-emailtext-user": "یک نفر (شاید تاسو، دآی‌پی پتی سره$1) د خپل پټنوم بیا سمولو لپاره غوښتنه{{SITENAME}} ($4) کړی ده. {{PLURAL:$3|ګڼون|ګڼونونه}} لاندې کارن د دې برېښنالیک سره تړلی دی:\n\n$2\n\n{{PLURAL:$3|دا یو لنډمهاله پاسورډ دی|دا شفرونه لنډمهاله دي}} وروسته تر {{PLURAL:$5|یوه ورځ|$5 ورځی}} به باطل شي.\nتاسو باید اوس ننوځئ او نوي شفرونه غوره کړئ. که تاسو فکر کوئ چې بل چا دا غوښتنه کړې ده یا که تاسو خپل اصلي پټنوم په یاد ولرئ او تاسو نور یې نه غواړئ بدلون ومومئ، تاسو کولی شئ دا پیغام غفلت کړئ او خپل پخوانی پاسورډ کارولو ته دوام ورکړئ.",
        "passwordreset-emailelement": "کارن-نوم: \n$1\n\nلنډمهاله پټنوم: \n$2",
        "passwordreset-emailsentemail": "د پټنوم بيا پرځای کېدنې لپاره برېښليک درولېږل شو.",
+       "passwordreset-emailsentusername": "که د دې کارن-نوم سره یو بریښنالیک پته شتون ولري نو بیا به د پاسورډ ری سیټ ای میل ته واستول شي.",
+       "passwordreset-nocaller": "يو اواز باید ورکړل شي",
+       "passwordreset-nosuchcaller": "کالر شتون نلري: $1",
+       "passwordreset-ignored": "د شفر بیاچالان سم نه و. کیدای شي کوم برابرونکي ترتیب نه وي؟",
        "passwordreset-invalidemail": "ناسمه برېښليک پته",
+       "passwordreset-nodata": "نه هم یو کاروونکي نوم او نه بریښنالیک پته ورکړل شوی",
        "changeemail": "برېښليک پته بدلول يا ليرې کول",
-       "changeemail-header": "د Ú¯Ú¼Ù\88Ù\86 Ø¨Ø±Û\90Ú\9aÙ\84Ù\8aÚ© Ù¾ØªÙ\87 Ø¨Ø¯Ù\84Ù\88Ù\84",
+       "changeemail-header": "د Ú¯Ú¼Ù\88Ù\86 Ø¯ Ø¨Ø±Û\90Ú\9aÙ\86اÙ\84Ù\8aÚ© Ø¨Ø¯Ù\84Ù\88Ù\84Ù\88 Ù\84پارÙ\87 Ø¯Ø§ Ù¾Ù\88رÙ\85 Ù¾Ù\88رÙ\87 Ú©Ú\93Ù\8a. Ú©Ù\87 ØªØ§Ø³Ù\88 ØºÙ\88اÚ\93ئ Ø¯ Ø®Ù¾Ù\84 Ù\87ر Ú\89Ù\88Ù\84 Ø­Ø³Ø§Ø¨ Ú\85Ø®Ù\87 Ø¯ Ø¨Ø±Û\8cÚ\9aÙ\86اÙ\84Ù\8aÚ© Ù¾ØªÙ\87 Ù\84رÛ\90 Ú©Ú\93Ù\8aØ\8c Ù\86Ù\88 Ø¯ Ø¨Ø±Ù\8aÚ\9aÙ\86اÙ\84Ù\8aÚ© Ú\81اÙ\8a Ù\85Ù\88 Ø¯ Ù¾Ù\88رÙ\85 Ø³Ù¾Ø§Ø±Ù\86Û\90 Ù¾Ù\87 Ù\88خت Ú©Û\90 Ø®Ø§Ù\84Ù\8a Ù¾Ø±Ù\8aÚ\96دÙ\8a.",
        "changeemail-no-info": "دې مخ ته د لاسرسي لپاره بايد غونډال کې ورننوځۍ.",
        "changeemail-oldemail": "اوسنۍ برېښليک پته:",
        "changeemail-newemail": "نوې برېښليک پته:",
+       "changeemail-newemail-help": "که تاسو غواړئ خپل بریښنالیک لرې کړئ نو دا ساحه باید پریښودل شي. تاسو به د هیر شوي شفر بیاپټولو توان نه لرئ او د دې ويکي نه بریښنالیکونه به مو ترلاسه نکړئ که چیرې مو برېښناليک لرې کړای شو.",
        "changeemail-none": "(هېڅ)",
        "changeemail-password": "ستاسې د{{SITENAME}} پټنوم:",
        "changeemail-submit": "برېښليک بدلول",
        "changeemail-throttled": "تاسې څو واره هڅه کړې چې غونډال ته ورننوځۍ.\nلطفاً د بيا هڅې نه مخکې $1 شېبې تم شۍ.",
+       "changeemail-nochange": "مهرباني وکړئ یو بل نوی برېښناليک پته ولیکئ.",
+       "resettokens": "د ټوکنونو بیاکتنه",
+       "resettokens-text": "تاسو کولی شئ  ټوکنونه بیا ځای پرځای کړئ کوم چې دلته ستاسو د حساب سره تړلی ځینې مشخصو معلوماتو ته دلا سرسۍ اجازه ورکوي.\n\nتاسو باید دا کار وکړئ که چیرې تاسو په ناڅاپي توګه له چا سره شریک کړي یا ستاسو حساب ورسره موافق وي.",
        "resettokens-tokens": "ټوکنونه:",
        "resettokens-token-label": "$1 (اوسنی ارزښت: $2)",
        "resettokens-done": "د رایو بیا راګرځول.",
        "longpageerror": "'''تېروتنه: کوم متن چې مو ليکلی {{PLURAL:$1|يو کيلوبايټه|$1 کيلوبايټه}} اوږد دی، چې دا پخپله د حد اکثر نه {{PLURAL:$2|يو کيلوبايټه|$2 کيلوبايټه}} اوږد دی.'''\nستاسې متن نه شي خوندي کېدلای.",
        "protectedpagewarning": "'''گواښنه: همدا مخ تړل شوی او يوازې هغه کارنان په دې مخ کې بدلونونه راوستلای شي چې د پازوالۍ د آسانتياوو نه برخمن دي.'''\nستاسې د مالوماتو لپاره د وروستني يادښت متن دلته په دې توگه راوړل شوی:",
        "semiprotectedpagewarning": "'''پاملرنه:''' دا مخ تړل شوی او يواځې ثبت شوي کارنان کولای شي چې په دې مخ کې بدلونونه راولي.\nستاسې د مالوماتو لپاره د وروستني يادښت متن دلته په دې توگه راوړل شوی:",
-       "cascadeprotectedwarning": "'''گواښنه:''' همدا مخ تړل شوی دی او يوازې هغه کارنان په دې مخ کې بدلونونه راوستلای شي چې د پازوالۍ د آسانتياوو نه برخمن دي، دا په دې خاطر چې همدا مخ د {{PLURAL:$1|لانديني مخ|لاندينيو مخونو}} په ځوړاوبيزې ژغورنې کې ورگډ دی:",
+       "cascadeprotectedwarning": "'''گواښنه:''' همدا مخ تړل شوی دی او يوازې هغه کارنان په دې مخ کې بدلونونه راوستلای شي چې د [[Special:ListGroupRights|د پازوالۍ د آسانتياوو]] نه برخمن دي، دا په دې خاطر چې همدا مخ د {{PLURAL:$1|لانديني مخ|لاندينيو مخونو}} په ځوړاوبيزې ژغورنې کې ورگډ دی:",
        "titleprotectedwarning": "'''گواښنه: همدا مخ تړل شوی دی او د دې د جوړولو لپاره تاسې ته د [[Special:ListGroupRights|ځانگړو رښتو]] د ترلاسه کولو اړتيا ده.'''\nستاسې د مالوماتو لپاره د وروستني يادښت متن دلته په دې توگه راوړل شوی:",
        "templatesused": "په دې مخ کارېدلې {{PLURAL:$1|کينډۍ|کينډۍ}}:",
        "templatesusedpreview": "يه دې مخليدنه کارېدلې {{PLURAL:$1|کينډۍ|کينډۍ}}:",
        "history-feed-description": "ددي مخ د بياکتنې تاريخ په ويکي کي",
        "history-feed-item-nocomment": "$1 په $2",
        "history-feed-empty": "ستاسې غوښتلی مخ نه شته.\nکېدای شي چې دا له ويکي نه ړنگ شوی وي، او يا هم په بل نوم بدل شوی وي.\nتاسې په دې ويکي د اړوندو نوؤ مخونو لپاره [[Special:Search|د پلټنې هڅه وکړۍ]].",
+       "history-edit-tags": "د غوره بڼې سمول نښانونه",
        "rev-deleted-comment": "(د سمون لنډيز لرې شو)",
        "rev-deleted-user": "(کارن-نوم ليري شوی)",
+       "rev-deleted-event": "(د ننوتنې مالومات ړنګ شوي)",
+       "rev-deleted-user-contribs": "[د کارن-نوم یا ای پی پته لرې کړه - له مرستو څخه پټ شوی ترمیم]",
        "rev-deleted-text-permission": "د دې مخ بڼه <strong>ړنگه شوه</strong>.\nد دې مخ اړونده تفصيل په [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ړنگون يادښت] کې موندلی شی.",
+       "rev-suppressed-text-permission": "د دې مخ بڼه <strong>ړنگه شوه</strong>.\nد دې مخ اړونده تفصيل په [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ړنگون يادښت] کې موندلی شی.",
+       "rev-suppressed-text-unhide": "د دې مخ بیاکتنه روانه <strong>ماتول ده</strong>.\nتفصيلات په دې ځای کې موندل کيداى شي[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} د ماتولو يادښت].\nتاسو لا هم کولی شئ [$1 دا بیاکتنه وګورئ] که تاسو غواړئ چې پرمخ بوځي.",
+       "rev-deleted-text-view": "ددې مخ سمون ''' ړنګ شوی '''.\nتاسو کولی شئ دا وګورئ؛ دا کېدای شي اړوند معلومات [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}}ړنګ شوی] په کې شامل وي.",
+       "rev-suppressed-text-view": "د دې مخ بڼه <strong>ړنگه شوه</strong>.\nد دې مخ اړونده تفصيل په [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ړنگون يادښت] کې موندلی شی.",
+       "rev-deleted-no-diff": "د دې مخ بڼه <strong>ړنگه شوه</strong>.\nد دې مخ اړونده تفصيل په [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ړنگون يادښت] کې موندلی شی.",
+       "rev-suppressed-no-diff": "تاسو دا توپیر نه شو لیدلی ځکه چې د بیاکتنې څخه یو یې <strong>ړنګ شویدی</strong>.",
+       "rev-deleted-unhide-diff": "د دې مخ بیاکتنه روانه <strong>ماتول ده</strong>.\nتفصيلات په دې ځای کې موندل کيداى شي[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} د ماتولو يادښت].\nتاسو لا هم کولی شئ [$1 دا بیاکتنه وګورئ] که تاسو غواړئ چې پرمخ بوځي.",
+       "rev-suppressed-unhide-diff": "د دې مخ بیاکتنه روانه <strong>ماتول ده</strong>.\nتفصيلات په دې ځای کې موندل کيداى شي[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} د ماتولو يادښت].\nتاسو لا هم کولی شئ [$1 دا بیاکتنه وګورئ] که تاسو غواړئ چې پرمخ بوځي.",
+       "rev-deleted-diff-view": "ددې مخ سمون ''' ړنګ شوی '''.\nتاسو کولی شئ دا وګورئ؛ دا کېدای شي اړوند معلومات [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}}ړنګ شوی] په کې شامل وي.",
+       "rev-suppressed-diff-view": "د دې مخ بڼه <strong>ړنگه شوه</strong>.\nد دې مخ اړونده تفصيل په [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ړنگون يادښت] کې موندلی شی.",
        "rev-delundel": "ښکارېدنه بدلول",
        "rev-showdeleted": "ښکاره کول",
        "revisiondelete": "د ړنگولو/ناړنگولو مخکتنې",
        "revdelete-nooldid-title": "ناباوره پيښنليک ته اشاره",
+       "revdelete-nooldid-text": "تاسو یا د کوم هدف بیا کتنه نده مشخص کړې چې دا فعالیت ترسره کړي، یا مشخص بیاکتنه شتون نلري، یا تاسو د اوسني بیاکتنې پټولو هڅه کوۍ.",
        "revdelete-no-file": "ځانگړې شوې دوتنه نشته.",
+       "revdelete-show-file-confirm": "ایا ته باوري یې چې دا دوتنه د خراب شوي څخه بیاکتنې ته واړوی\"<nowiki>$1</nowiki>\" له$2 په $3؟",
        "revdelete-show-file-submit": "هو",
        "revdelete-selected-text": "د [[:$2]] {{PLURAL:$1|ټاکلې بڼه|ټاکلې بڼې}}:",
        "revdelete-selected-file": "د [[:$2]] {{PLURAL:$1|ټاکلې دوتنې بڼه|ټاکلې دوتنې بڼې}}",
        "logdelete-selected": "{{PLURAL:$1|ټاکلي يادښت پېښه|ټاکلي يادښت پېښې}}:",
        "revdelete-text-text": "ړنگې شوې بڼې به لا تر اوسه پورې د مخ پېښليک کې ښکاري، خو د هغو ځينو برخو ته به عام خلک لاسرسی و نه لري.",
+       "revdelete-text-file": "ړنگې شوې بڼې به لا تر اوسه پورې د مخ پېښليک کې ښکاري، خو د هغو ځينو برخو ته به عام خلک لاسرسی و نه لري.",
+       "logdelete-text": "ړنگې شوې بڼې به لا تر اوسه پورې د مخ پېښليک کې ښکاري، خو د هغو ځينو برخو ته به عام خلک لاسرسی و نه لري.",
+       "revdelete-text-others": "نور پازوالان به لا هم د پټ راز محتوياتو ته لاسرسی ومومي او دا یې له منځه یوسي، مګر که نه بل ډول مشخص شوی.",
+       "revdelete-confirm": "لطفا دا تایید کړئ چې تاسو دا کار کول غواړئ، دا چې تاسو پایلې په پام کې لرئ او تاسو یې سره مطابقت کوئ[[{{MediaWiki:Policy-url}}|پالیسۍ]].",
        "revdelete-legend": "د ښکارېدنې محدوديتونه ټاکل",
        "revdelete-hide-text": "د مخکتنې متن",
        "revdelete-hide-image": "د دوتنې مېنځپانگه پټول",
        "userrights-user-editname": "يو کارن نوم ورکړئ:",
        "editusergroup": "{{GENDER:$1|کارن}} ډلې سمول",
        "editinguser": "د <strong>[[User:$1|$1]]</strong> {{GENDER:$1|کارن}} رښتې بدلول $2",
-       "userrights-editusergroup": "کارن ډلې سمول",
+       "userrights-editusergroup": "{{GENDER:$1|کارن}} ډلې سمول",
        "userrights-viewusergroup": "د{{GENDER:$1|کارن}} ګروپونه ښکاره کړي",
        "saveusergroups": "{{GENDER:$1|کارن}} ډلې خوندي کول",
        "userrights-groupsmember": "غړی د:",
        "action-userrights-interwiki": "په نورو ويکي گانو د کارنانو رښتې سمول",
        "action-siteadmin": "توکبنسټ کولپول يا نه کولپول",
        "action-sendemail": "برېښليکونه لېږل",
+       "action-editmyoptions": "خپل غوره توبونه سمول",
        "action-editmywatchlist": "خپل کتنلړ سمول",
        "action-viewmywatchlist": "خپل کتنلړ کتل",
        "action-viewmyprivateinfo": "خپل شخصي مالومات کتل",
        "rcfilters-savedqueries-add-new-title": "د امستنې اوسنۍ فيلټر خوندي کړي",
        "rcfilters-filterlist-title": "چاڼگران",
        "rcfilters-highlightmenu-title": "يو رنګ وټاکۍ",
+       "rcfilters-filter-user-experience-level-unregistered-label": "ناثبت",
        "rcfilters-filter-user-experience-level-newcomer-label": "نوي راغلي",
        "rcfilters-filter-user-experience-level-learner-label": "زده کوونکي",
-       "rcnotefrom": "دلته لاندې د <strong>$2</strong> څخه راپدېخوا پېښ شوي بدلونونه راغلي (تر <strong>$1</strong> پورې ښکاري).",
+       "rcnotefrom": "دلته لاندې د <strong>$3, $4</strong> (څخه <strong>$1</strong> {{PLURAL:$5|راپدېخوا پېښ شوي بدلونونه|ښکاري}}).",
        "rclistfrom": "نوي بدلونونه چې له $3، $2 څخه پيلېږي ښکاره کول",
        "rcshowhideminor": "وړې سمونې $1",
        "rcshowhideminor-show": "ښکاره کول",
        "recentchangeslinked-page": "د مخ نوم:",
        "recentchangeslinked-to": "د ورکړل شوي مخ پر ځای د اړونده تړلي مخونو بدلونونه ښکاره کول",
        "recentchanges-page-added-to-category": "[[:$1]] وېشنيزې کې ورگډ شو",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] او {{PLURAL:$2|يو مخ|$2 مخونه}} وېشنيزې کې ورگډ شول",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] له وېشنيزې وغورځول شول، [[Special:WhatLinksHere/$1|په نورو مخونو کې دا مخ موجود دی.]]",
        "recentchanges-page-removed-from-category": "[[:$1]] له وېشنيزې وغورځول شو",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] او {{PLURAL:$2|يو مخ|$2 مخونه}} له وېشنيزې وغورځول شول",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] له وېشنيزې وغورځول شول، [[Special:WhatLinksHere/$1|په نورو مخونو کې دا مخ موجود دی.]]",
        "autochange-username": "د مېډياويکي خپلکاره بدلون",
        "upload": "دوتنه پورته کول",
        "uploadbtn": "دوتنه پورته کول",
        "reuploaddesc": "پورته کېدنه ناگارل او بېرته د پورته کېدنې فورمې ته ورگرځېدل",
        "upload-tryagain": "د بدلون موندلې دوتنې څرگندونې سپارل",
+       "upload-tryagain-nostash": "د بیا رالېږل شوې دوتنې وړاندې کول او تعدیل شوی بیان وړاندې کړئ",
        "uploadnologin": "غونډال کې نه ياست ننوتي",
        "uploadnologintext": "د دوتنې پورته کولو لپاره بايد $1",
        "uploaderror": "د پورته کولو ستونزه",
        "upload-form-label-infoform-categories": "وېشنيزې",
        "upload-form-label-infoform-date": "نېټه",
        "backend-fail-notexists": "د $1 په نوم دوتنه نشته.",
+       "backend-fail-invalidpath": "\"$1\" د اعتبار وړ لاره نه ده.",
        "backend-fail-delete": "د \"$1\" دوتنه ړنګه نه شوه.",
+       "backend-fail-describe": "د $1 دوتنې لپاره مېټاډاټا نشو بدلولی",
        "backend-fail-alreadyexists": "د $1 دوتنه له پخوا نه شته.",
        "backend-fail-store": "په \"$2\" باندې د \"$1\" دوتنه نه زېرمل کېږي.",
        "backend-fail-copy": "د \"$1\" دوتنه و \"$2\" ته نه لمېسل کېږي.",
        "sharedupload": "دا دوتنه د $1 لخوا څخه ده او کېدای شي چې نورې پروژې به يې هم کاروي.",
        "sharedupload-desc-there": "دا دوتنه د $1 څخه ده او کېدای شي چې په نورو پروژو به هم کارېږي.\nد نورو مالوماتو لپاره لطفاً [د $2 دوتنې د څرگندونو مخ] وگورئ.",
        "sharedupload-desc-here": "دا دوتنه د $1 لخوا خپرېږې او کېدای شي چې دا په نورو پروژو هم کارېدلې وي.\nد دوتنې د کارېدنې لا نور مالومات د [$2 دوتنې د څرگندنو په مخ] کې لاندې ښودل شوی.",
+       "sharedupload-desc-edit": "دا دوتنه د $1 لخوا خپرېږې او کېدای شي چې دا په نورو پروژو هم کارېدلې وي.\nکېدای شي تاسو به غواړئ چې څرگندونې يې د دې دوتنې [د $2 دوتنې د څرگندنو په مخ] کې سمې کړئ.",
        "sharedupload-desc-create": "دا دوتنه د $1 لخوا خپرېږې او کېدای شي چې دا په نورو پروژو هم کارېدلې وي.\nکېدای شي تاسو به غواړئ چې څرگندونې يې د دې دوتنې [د $2 دوتنې د څرگندنو په مخ] کې سمې کړئ.",
        "filepage-nofile": "په دې نوم کومه دوتنه نشته.",
        "filepage-nofile-link": "په دې نوم کومه دوتنه نشته، خو تاسې يې [$1 پورته کولی شی].",
        "fewestrevisions": "لږ مخليدل شوي مخونه",
        "nbytes": "$1 {{PLURAL:$1|بايټ|بايټونه}}",
        "ncategories": "$1 {{PLURAL:$1|وېشنيزه|وېشنيزې}}",
-       "ninterwikis": "$1 {{PLURAL:$1|ويکي خپلمنځي|ويکي خپلمنځي}}",
+       "ninterwikis": "$1 {{PLURAL:$1|انټرویکی|انټرویکی}}",
        "nlinks": "$1 {{PLURAL:$1|تړنه|تړنې}}",
        "nmembers": "$1 {{PLURAL:$1|غړی|غړي}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|غړی|غړي}}",
        "booksources-search": "پلټل",
        "booksources-text": "دا لاندې د هغه وېبځايونو د تړنو لړليک دی چېرته چې نوي او زاړه کتابونه پلورل کېږي، او يا هم کېدای شي چې د هغه کتاب په هکله مالومات ولري کوم چې تاسو ورپسې لټېږۍ:",
        "booksources-invalid-isbn": "دا ISBN چې تاسې ورکړی سم نه ښکاري؛ د تېروتنو لپاره د لمېسلو اصلي سرچينه وگورئ.",
+       "magiclink-tracking-isbn": "مخونه د اي اس بي ان جادوګر لينکونو سره",
        "specialloguserlabel": "ترسره کوونکی:",
-       "speciallogtitlelabel": "موخه (سرليک يا کارن):",
+       "speciallogtitlelabel": "موخه (سرليک يا {{ns:user}}:کارن نوم د کارن لپاره):",
        "log": "يادښتونه",
        "logeventslist-submit": "ښکاره کول",
        "all-logs-page": "ټول عام يادښتونه",
        "addedwatchtext-short": "د \"$1\" مخ ستاسې کتنلړ کې ورگډ شو.",
        "removewatch": "له کتنلړ نه غورځول",
        "removedwatchtext": "د \"[[:$1]]\" مخ [[Special:Watchlist|ستاسې کتنلړ]] نه لرې شو.",
+       "removedwatchtext-talk": "د \"[[:$1]]\" په نوم يو مخ ستاسې [[Special:Watchlist|کتنلړ]] کې ورگډ شو.\nپه راتلونکې کې چې په دغه مخ او د دې د خبرواترو مخ کې کوم بدلونونه راځي نو هغه به ستاسې کتنلړ کې ښکاري.",
        "removedwatchtext-short": "د \"$1\" مخ ستاسې له کتنلړ څخه لرې شو.",
        "watch": "کتل",
        "watchthispage": "همدا مخ کتل",
        "wlshowhideanons": "ورکنومي کارنان",
        "wlshowhidepatr": "څارل شوي سمونونه",
        "wlshowhidemine": "زما سمونونه",
+       "wlshowhidecategorization": "د مخ وېشنيزې",
        "watchlist-options": "د کتنلړ خوښنې",
        "watching": "د کتلو په حال کې...",
        "unwatching": "د نه کتلو په حال کې...",
        "version-libraries-license": "منښتليک",
        "version-libraries-description": "څرگندونه",
        "version-libraries-authors": "ليکوالان",
-       "redirect": "ورگرځېدنې د دوتنې، کارن، مخ يا بڼې پېژند له مخې",
+       "redirect": "د دوتنې ورگرځېدنې، کارن، مخ يا بڼې پېژند له مخې",
        "redirect-summary": "دا ځانګړی مخ د یوې دوتنې (د فیلمین لخوا ورکړ شوی)، یو مخ (د بیاکتنې پیژند یا د پاڼې پېژندل شوی اي ډي)، د کاروونکي پاڼه (د شمېره کاروونکي اي ډي ورکړه)، او یا د ننوتلو ننوتل (د ننوتنې اي ډي ورکړل شوی). کارول:[[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], or [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "ورځه",
        "redirect-lookup": "وګوري:",
index 31a07bd..bf4a9a8 100644 (file)
        "rcfilters-savedqueries-apply-and-setdefault-label": "Criar filtro padrão",
        "rcfilters-savedqueries-cancel-label": "Cancelar",
        "rcfilters-savedqueries-add-new-title": "Gravar configurações atuais de filtros",
+       "rcfilters-savedqueries-already-saved": "Esses filtros já foram salvos",
        "rcfilters-restore-default-filters": "Restaurar filtros padrão",
        "rcfilters-clear-all-filters": "Limpar todos os filtros",
        "rcfilters-show-new-changes": "Veja as novas mudanças",
index bdc02ec..41fe87e 100644 (file)
        "ok": "Ṭhik gea",
        "retrievedfrom": "\"$1\" khon ñam ạgui",
        "youhavenewmessages": "Amaḱ do $1 ($2) menaḱa",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|ᱟᱢ ᱫᱚ}} $1 ᱠᱷᱚᱱ {{PLURAL:$3|ᱟᱨᱢᱤᱫ ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹ|$3 ᱵᱷᱮᱵᱷᱟᱨᱩᱭᱟᱹ}} ($2) ᱾",
        "newmessageslinkplural": "{{PLURAL:$1|ᱢᱤᱫ ᱱᱟᱶᱟ ᱢᱮᱥᱮᱡᱽ|999=ᱱᱟᱶᱟ ᱢᱮᱥᱮᱡᱽᱠᱚ}}",
        "newmessagesdifflinkplural": "ᱢᱩᱪᱟᱹᱫ {{PLURAL:$1|ᱵᱚᱫᱚᱞ|999=ᱵᱚᱫᱚᱞᱠᱚ}}",
        "youhavenewmessagesmulti": "Amaḱ nãwã mesagko do $1 menaḱa",
        "editundo": "ruạṛ",
        "diff-empty": "(ᱵᱷᱮᱜᱮᱫ ᱵᱟᱹᱱᱩᱜ)",
        "diff-multi-sameuser": "({{PLURAL:$1|ᱢᱤᱫ ᱛᱟᱞᱟ-ᱢᱟᱞᱟ ᱫᱚᱦᱲᱟ|$1 ᱛᱟᱞᱟ-ᱢᱟᱞᱟ ᱫᱚᱦᱲᱟᱠᱚ}} ᱥᱚᱢᱟᱱ ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹ ᱫᱟᱨᱟᱭᱛᱮ ᱵᱟᱭ ᱧᱮᱞᱚᱜ-ᱟ)",
+       "diff-multi-otherusers": "({{PLURAL:$1|ᱢᱤᱫ ᱛᱟᱞᱟ-ᱢᱟᱞᱟ ᱫᱚᱦᱲᱟ|$1 ᱛᱟᱞᱟ-ᱢᱟᱞᱟ ᱫᱚᱦᱲᱟᱠᱚ}} {{PLURAL:$2|ᱢᱤᱫ ᱮᱴᱟᱜ ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹ|$2 ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹᱠᱚ}} ᱵᱟᱠᱚ ᱧᱮᱞᱚᱜ-ᱟ)",
        "searchresults": "Se̠ndra pho̠l",
        "searchresults-title": "\"$1\"  renaḱ Sẽndra  phol",
        "prevn": "Laha reaḱ {{PLURAL:$1|$1}}",
        "filehist-comment": "Roṛ",
        "imagelinks": "Phayel bebohar",
        "linkstoimage": "Latar reaḱ {{PLURAL:$1 sakam $1 sakam}} khon noa rẽtre joṛao menaḱa:",
+       "linkstoimage-more": "$1 ᱠᱷᱚᱱ ᱵᱟᱹᱲᱛᱤ {{PLURAL:$1|ᱥᱟᱦᱴᱟ ᱡᱚᱯᱲᱟᱣᱠᱚ|ᱥᱟᱦᱴᱟ ᱡᱚᱯᱲᱟᱣ}} ᱢᱮᱱᱟᱜ-ᱟ ᱱᱚᱣᱟ ᱨᱮᱫ ᱥᱟᱶ ᱾\nᱱᱚᱶᱟ ᱞᱤᱥᱴᱤ ᱩᱫᱩᱜᱮᱜ-ᱟᱭ {{PLURAL:$1|ᱮᱛᱚᱦᱚᱵ ᱥᱟᱦᱴᱟ ᱡᱚᱲᱟᱣ|ᱮᱛᱚᱦᱚᱵ $1 ᱥᱟᱦᱴᱟ ᱡᱚᱲᱟᱣᱠᱚ}} ᱥᱩᱢᱩᱝ ᱱᱚᱶᱟ ᱨᱮᱫ ᱥᱟᱶ ᱾\nᱢᱤᱫ [[Special:WhatLinksHere/$2|ᱡᱚᱛᱚ ᱞᱤᱥᱴᱤ]] ᱢᱮᱱᱟᱜ-ᱟ ᱾",
        "nolinkstoimage": "Nonḍe do noa são joṛao sakam banuka",
        "linkstoimage-redirect": "$1 (ᱨᱮᱫ ᱢᱚᱦᱰᱟᱜ-ᱟ) $2",
        "sharedupload-desc-here": "Noa rẽt do nonḍe khon-  $1 ar paseć eṭaḱaḱ porjekṭko beoharakana.\nNoa reaḱ pasnao katha [$2 rẽt pasnao sakam] latare emena",
        "speciallogtitlelabel": "ᱡᱚᱥ (ᱧᱩᱛᱩᱢ ᱟᱨᱵᱟᱝ {{ns:user}}:ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹ ᱞᱟᱹᱜᱩᱫ ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹ ᱧᱩᱛᱩᱢ):",
        "log": "Cạbiko",
        "all-logs-page": "ᱡᱚᱛᱚ ᱫᱤᱥᱣᱟᱹ ᱞᱚᱜᱽ ᱠᱚ",
+       "logempty": "ᱞᱚᱜᱽ ᱨᱮ ᱚᱱᱟᱞᱮᱠᱟᱱ ᱡᱤᱱᱤᱥ ᱵᱟᱹᱱᱩᱜ-ᱟ ᱾",
        "allpages": "joto sakam",
        "allarticles": "Sanam sakam",
        "allpagessubmit": "Calaḱme",
        "sp-contributions-search": "Kạmiko emoḱ lạgitte sendrayme",
        "sp-contributions-username": "IP ṭhikạna se laṛcaṛićaḱ n̕utum",
        "sp-contributions-toponly": "Khạli nahaḱ nãwã aroyen joṛao kamiko udukme",
+       "sp-contributions-newonly": "ᱥᱩᱢᱩᱝ ᱟᱹᱨᱩᱠᱚ ᱥᱚᱫᱚᱨᱢᱮ ᱡᱟᱦᱟᱸ ᱥᱟᱦᱟᱴᱟ ᱫᱚ ᱥᱤᱨᱡᱟᱹᱣᱟᱜ ᱠᱟᱱᱟ",
        "sp-contributions-submit": "Sendra",
        "whatlinkshere": "Cet́ link ko no̠nḍe do",
        "whatlinkshere-title": "Oka sakam ko do \"$1\"-re joṛao menaḱa",
        "tags-active-no": "ᱵᱟᱝ",
        "logentry-delete-delete": "$3 ᱥᱟᱦᱴᱟ $1 {{GENDER:$2|ᱜᱮᱫ ᱠᱮᱜ-ᱟᱭ}}",
        "logentry-delete-restore": "$1 {{GENDER:$2|ᱨᱟᱠᱷᱟ ᱫᱚᱲᱦᱟ}} ᱠᱮᱜ-ᱟ ᱥᱟᱦᱴᱟ $3 ($4)",
+       "logentry-delete-revision": "$1 {{GENDER:$2|ᱵᱚᱫᱚᱞᱠᱮᱜ-ᱟᱭ}} ᱧᱮᱞᱚᱜᱟᱜ {{PLURAL:$5|ᱫᱚᱦᱲᱟᱭᱮᱱᱟᱜ|$5 ᱫᱚᱦᱲᱟᱭᱮᱱᱟᱜ ᱠᱚ}} $3: $4 ᱥᱟᱦᱴᱟ ᱪᱮᱛᱟᱱᱨᱮ",
        "revdelete-content-hid": "ᱩᱱᱩᱫᱩᱜ ᱫᱟᱱᱟᱝ",
        "logentry-move-move": "$1 beoharić $3 sakam do $4 ńutumre {{GENDER:$2|ạcạr}} akada",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|ᱩᱪᱟᱹᱲᱠᱮᱜ-ᱟᱭ}} ᱥᱟᱦᱴᱟ $3 to $4 ᱢᱚᱦᱰᱟ ᱵᱤᱱ ᱵᱟᱹᱜᱤ ᱠᱟᱛᱮ",
index 2583c81..2d18707 100644 (file)
        "rcfilters-filter-newpages-label": "လွင်ႈၵေႃႇသၢင်ႈ ၼႃႈလိၵ်ႈ",
        "rcfilters-filter-newpages-description": "မႄးထတ်း ဢၼ်ႁဵတ်းပဵၼ် ၼႃႈလိၵ်ႈဢၼ်မႂ်ႇ",
        "rcfilters-filter-categorization-label": "လႅၵ်ႈလၢႆႈ တွၼ်ႈၵၼ်",
+       "rcfilters-filtergroup-lastRevision": "ၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
+       "rcfilters-filter-lastrevision-label": "ၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
+       "rcfilters-filter-lastrevision-description": "ၸိူဝ်းဢၼ်မီးလွင်ႈလႅၵ်ႈလၢႆႈၸူး ၼႃႈလိၵ်ႈ ဢၼ်ပႆႇႁိုင်ၼၼ်ႉၵူၺ်း",
+       "rcfilters-filter-previousrevision-label": "ဢမ်ႇၸႂ်ႈၵၢၼ်ၶူၼ်ႉၶႆႈ ၵမ်းလိုၼ်းသုတ်း",
+       "rcfilters-filter-previousrevision-description": "ၸိူဝ်းလႅၵ်ႈလၢႆႈတင်းသဵင်ႈ ဢၼ်ဢမ်ႇၸႂ်ႈ \"လွင်ႈၶူၼ်ႉၶႆႈၵမ်းလိုၼ်းသုတ်း\"။",
        "rcnotefrom": "ၽၢႆႇတႂ်ႈ {{PLURAL:$5|ၼႆႉ ပဵၼ်လွင်ႈလႅၵ်ႈလၢႆႈ|ၸိူဝ်းၼႆႉ ပဵၼ်လွင်ႈလႅၵ်ႈလၢႆႈ}} ဝႆႉ ၸဵမ်မိူဝ်ႈ <strong>$3, $4</strong> (တေႃႇထိုင် <strong>$1</strong> ဢၼ်ၼႄဝႆႉ).",
        "rclistfrom": "ၼႄ လွင်ႈ​လႅၵ်ႈလၢႆႈဢၼ်မႂ်ႇ တႄႇတီႈ $2, $3",
        "rcshowhideminor": "$1 လွင်ႈမူၼ်ႉမႄး ဢိတ်းဢီႈ",
index 975bb87..d89865b 100644 (file)
        "anonpreviewwarning": "<em>Нисте пријављени. Ако објавите страницу, Ваша IP адреса ће бити јавно видљива у њеној историји измена и другде.</em>",
        "missingsummary": "'''Подсетник:''' Нисте унели опис измене.\nАко поново кликнете на „$1”, Ваша измена ће бити сачувана без описа.",
        "selfredirect": "<strong>Упозорење:</strong> Преусмеравате ову страницу на њу саму.\nМожда вам је одредишна страница за преусмерење погрешна или уређујете погрешну страницу.\nАко још једном притиснете „$1”, преусмерење ће свеједно бити направљено.",
-       "missingcommenttext": "УнеÑ\81иÑ\82е ÐºÐ¾Ð¼ÐµÐ½Ñ\82аÑ\80 Ð¸Ñ\81под.",
+       "missingcommenttext": "Ð\9cолимо Ñ\83неÑ\81иÑ\82е ÐºÐ¾Ð¼ÐµÐ½Ñ\82аÑ\80.",
        "missingcommentheader": "<strong>Напомена:</strong> Нисте унели наслов теме овог коментара.\nАко поново кликнете на „$1”, измена ће бити сачувана без наслова.",
        "summary-preview": "Преглед описа измене:",
        "subject-preview": "Преглед теме:",
        "page_last": "последња",
        "histlegend": "Избор разлика: изаберите кутијице измена за упоређивање и притисните ентер или дугме на дну.<br />\nОбјашњење: <strong>({{int:cur}})</strong> = разлика с тренутном изменом, <strong>({{int:last}})</strong> = разлика с претходном изменом, <strong>{{int:minoreditletter}}</strong> = мала измена",
        "history-fieldset-title": "Преглед измена",
-       "history-show-deleted": "Само обрисане измјене",
+       "history-show-deleted": "Само обрисане измене",
        "histfirst": "најстарије",
        "histlast": "најновије",
        "historysize": "({{PLURAL:$1|1 бајт|$1 бајта|$1 бајтова}})",
        "timezoneregion-europe": "Европа",
        "timezoneregion-indian": "Индијски океан",
        "timezoneregion-pacific": "Тихи океан",
-       "allowemail": "Ð\9eмогÑ\83Ñ\9bи Ð¿Ñ\80имаÑ\9aе Ð¸Ð¼ÐµÑ\98ла Ð¾Ð´ Ð´Ñ\80Ñ\83гиÑ\85 ÐºÐ¾Ñ\80иÑ\81ника",
+       "allowemail": "Ð\94озволи Ð´Ñ\80Ñ\83гим ÐºÐ¾Ñ\80иÑ\81ниÑ\86има Ð´Ð° Ð¼Ð¸ Ñ\88аÑ\99Ñ\83 Ð¸-меÑ\98лове",
        "prefs-searchoptions": "Претрага",
        "prefs-namespaces": "Именски простори",
        "default": "подразумевано",
        "rcfilters-grouping-title": "Груписање",
        "rcfilters-activefilters": "Активни филтери",
        "rcfilters-advancedfilters": "Напредни филтери",
-       "rcfilters-limit-title": "Приказати измјена",
-       "rcfilters-limit-shownum": "Прикажи посљедњих $1 измјена",
+       "rcfilters-limit-title": "Приказати измена",
+       "rcfilters-limit-shownum": "Прикажи последњих $1 измена",
        "rcfilters-days-title": "Претходних неколико дана",
        "rcfilters-hours-title": "Претходних неколико сати",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|дан|дана}}",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|сат|сата}}",
        "rcfilters-highlighted-filters-list": "Истакнуто: $1",
        "rcfilters-quickfilters": "Сачувани филтери",
-       "rcfilters-quickfilters-placeholder-title": "Ð\92езе Ñ\98оÑ\88 Ñ\83век Ð½Ð¸Ñ\81Ñ\83 Ñ\83памÑ\9bене",
-       "rcfilters-quickfilters-placeholder-description": "Ð\94а Ð±Ð¸Ñ\81Ñ\82е Ñ\81аÑ\87Ñ\83вали Ñ\81воÑ\98а Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\84илÑ\82еÑ\80а Ð¸ Ñ\83поÑ\82Ñ\80ебÑ\99авали Ð¸Ñ\85 ÐºÐ°Ñ\81ниÑ\98е, ÐºÐ»Ð¸ÐºÐ½Ð¸Ñ\82е Ð½Ð° Ð±Ñ\83кмаÑ\80к Ð¸ÐºÐ¾Ð½Ñ\83 Ñ\83 Ð¿Ð¾Ð´Ñ\80Ñ\83Ñ\87Ñ\98Ñ\83 Ð\90кÑ\82ивни Ñ\84илÑ\82еÑ\80и, испод.",
+       "rcfilters-quickfilters-placeholder-title": "Ð\88оÑ\88 Ñ\83век Ð½ÐµÐ¼Ð° Ñ\83памÑ\9bениÑ\85 Ñ\84илÑ\82еÑ\80а",
+       "rcfilters-quickfilters-placeholder-description": "Ð\94а Ð±Ð¸Ñ\81Ñ\82е Ñ\81аÑ\87Ñ\83вали Ñ\81воÑ\98а Ð¿Ð¾Ð´ÐµÑ\88аваÑ\9aа Ñ\84илÑ\82еÑ\80а Ð¸ Ñ\83поÑ\82Ñ\80ебÑ\99авали Ð¸Ñ\85 ÐºÐ°Ñ\81ниÑ\98е, ÐºÐ»Ð¸ÐºÐ½Ð¸Ñ\82е Ð½Ð° Ð¸ÐºÐ¾Ð½Ñ\83 Ð·Ð° Ð¾Ð·Ð½Ð°ÐºÑ\83 Ñ\83 Ð¿Ð¾Ð´Ñ\80Ñ\83Ñ\87Ñ\98Ñ\83 Ð°ÐºÑ\82ивниÑ\85 Ñ\84илÑ\82еÑ\80а, испод.",
        "rcfilters-savedqueries-defaultlabel": "Сачувани филтери",
        "rcfilters-savedqueries-rename": "Преименуј",
        "rcfilters-savedqueries-setdefault": "Постави као подразумевано",
        "rcfilters-savedqueries-apply-and-setdefault-label": "Направи подразумевани филтер",
        "rcfilters-savedqueries-cancel-label": "Откажи",
        "rcfilters-savedqueries-add-new-title": "Сачувај тренутне поставке филтера",
+       "rcfilters-savedqueries-already-saved": "Ови филтери су већ упамћени",
        "rcfilters-restore-default-filters": "Враћање подразумеваних филтера",
        "rcfilters-clear-all-filters": "Уклони све филтере",
        "rcfilters-show-new-changes": "Погледајте најновије измене",
-       "rcfilters-search-placeholder": "Филтер скорашњих измјена (претражите или почните куцати)",
+       "rcfilters-search-placeholder": "Филтрирај скорашње измене (употребите мени или потражите име филтра)",
        "rcfilters-invalid-filter": "Невалидан филтер",
        "rcfilters-empty-filter": "Нема активних филтера. Сви доприноси су приказани.",
        "rcfilters-filterlist-title": "Филтери",
        "rcfilters-filterlist-whatsthis": "Како ово функционише?",
-       "rcfilters-filterlist-feedbacklink": "Дајте повратне информације о новим (бета) филтерима",
+       "rcfilters-filterlist-feedbacklink": "Дајте повратне информације о новим (бета) алатима за филтрирање",
        "rcfilters-highlightbutton-title": "Истакни резултате",
        "rcfilters-highlightmenu-title": "Одабери боју",
        "rcfilters-highlightmenu-help": "Изаберите боју да бисте истакнули ово својство",
        "rcfilters-state-message-subset": "Овај филтер нема ефекта јер су његови резултати укључени са онима {{PLURAL:$2|следећег, ширег филтера|следећих, ширих филтера}} (покушајте са означавањем да бисте их распознали): $1",
        "rcfilters-state-message-fullcoverage": "Одабир свих филтера у групи је исто као и одабир ниједног, тако да овај филтер нема ефекта. Група укључује: $1",
        "rcfilters-filtergroup-authorship": "Ауторство доприноса",
-       "rcfilters-filter-editsbyself-label": "Ваше измјене",
+       "rcfilters-filter-editsbyself-label": "Ваше измене",
        "rcfilters-filter-editsbyself-description": "Ваши доприноси.",
-       "rcfilters-filter-editsbyother-label": "Измјене других",
-       "rcfilters-filter-editsbyother-description": "Све измјене осим Ваших.",
+       "rcfilters-filter-editsbyother-label": "Измене других",
+       "rcfilters-filter-editsbyother-description": "Све измене осим Ваших.",
        "rcfilters-filtergroup-userExpLevel": "Корисничка регистрација и искуство",
        "rcfilters-filter-user-experience-level-registered-label": "Регистровани",
        "rcfilters-filter-user-experience-level-registered-description": "Пријављени уредници.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Нерегистровани",
        "rcfilters-filter-user-experience-level-unregistered-description": "Уредници који нису пријављени.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Новајлије",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Регистровани уредници са мање од 10 измјена и 4 дана активности.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Регистровани уредници са мање од 10 измена и 4 дана активности.",
        "rcfilters-filter-user-experience-level-learner-label": "Ученици",
        "rcfilters-filter-user-experience-level-learner-description": "Регистровани уредници са више искуства од „новајлија”, али мање од „искусних корисника”.",
        "rcfilters-filter-user-experience-level-experienced-label": "Искусни корисници",
-       "rcfilters-filter-user-experience-level-experienced-description": "Регистровани уредници са више од 500 измјена и 30 дана активности.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Регистровани уредници са више од 500 измена и 30 дана активности.",
        "rcfilters-filtergroup-automated": "Аутоматизовани доприноси",
        "rcfilters-filter-bots-label": "Бот",
-       "rcfilters-filter-bots-description": "Измјене направљене аутоматизованим алатима.",
-       "rcfilters-filter-humans-label": "Човјек (није бот)",
-       "rcfilters-filter-humans-description": "Измјене које су направили људи-уредници.",
+       "rcfilters-filter-bots-description": "Измене направљене аутоматизованим алатима.",
+       "rcfilters-filter-humans-label": "Човек (није бот)",
+       "rcfilters-filter-humans-description": "Измене које су направили људи-уредници.",
        "rcfilters-filtergroup-reviewstatus": "Патролираност",
        "rcfilters-filter-patrolled-label": "Патролирано",
-       "rcfilters-filter-patrolled-description": "Измјене означене као патролиране.",
+       "rcfilters-filter-patrolled-description": "Измене означене као патролиране.",
        "rcfilters-filter-unpatrolled-label": "Непатролирано",
-       "rcfilters-filter-unpatrolled-description": "Измјене које нису означене као патролиране.",
+       "rcfilters-filter-unpatrolled-description": "Измене које нису означене као патролиране.",
        "rcfilters-filtergroup-significance": "Значај",
-       "rcfilters-filter-minor-label": "Мање измјене",
-       "rcfilters-filter-minor-description": "Измјене које је аутор означио као мање.",
-       "rcfilters-filter-major-label": "Не-мање измјене",
-       "rcfilters-filter-major-description": "Измјене које нису означене као мање.",
+       "rcfilters-filter-minor-label": "Мање измене",
+       "rcfilters-filter-minor-description": "Измене које је аутор означио као мање.",
+       "rcfilters-filter-major-label": "Не-мање измене",
+       "rcfilters-filter-major-description": "Измене које нису означене као мање.",
        "rcfilters-filtergroup-watchlist": "Странице на списку надгледања",
        "rcfilters-filter-watchlist-watched-label": "На списку надгледања",
-       "rcfilters-filter-watchlist-watched-description": "Измјене страница на Вашем списку надгледања",
-       "rcfilters-filter-watchlist-watchednew-label": "Нове измјене на списку надгледања",
-       "rcfilters-filter-watchlist-watchednew-description": "Измјене страница на списку надгледања које нисте посјетили од када су направљене измјене.",
+       "rcfilters-filter-watchlist-watched-description": "Измене страница на Вашем списку надгледања.",
+       "rcfilters-filter-watchlist-watchednew-label": "Нове измене на списку надгледања",
+       "rcfilters-filter-watchlist-watchednew-description": "Измене страница на списку надгледања које нисте посетили од када су направљене измене.",
        "rcfilters-filter-watchlist-notwatched-label": "Није на списку надгледања",
-       "rcfilters-filter-watchlist-notwatched-description": "Све осим измјена страница на Вашем списку надгледања.",
-       "rcfilters-filtergroup-changetype": "Тип измјене",
-       "rcfilters-filter-pageedits-label": "Измјене страница",
-       "rcfilters-filter-pageedits-description": "Измјене вики садржаја, расправа, описа категорија…",
+       "rcfilters-filter-watchlist-notwatched-description": "Све осим измена страница на Вашем списку надгледања.",
+       "rcfilters-filtergroup-watchlistactivity": "Стање на списку надгледања",
+       "rcfilters-filter-watchlistactivity-unseen-label": "Непогледане измене",
+       "rcfilters-filter-watchlistactivity-unseen-description": "Измене страница које нисте посетили од када су направљене измене.",
+       "rcfilters-filter-watchlistactivity-seen-label": "Погледане измене",
+       "rcfilters-filter-watchlistactivity-seen-description": "Измене страница које сте посетили од када су направљене измене.",
+       "rcfilters-filtergroup-changetype": "Врста измене",
+       "rcfilters-filter-pageedits-label": "Измене страница",
+       "rcfilters-filter-pageedits-description": "Измене вики садржаја, расправа, описа категорија…",
        "rcfilters-filter-newpages-label": "Стварање страница",
-       "rcfilters-filter-newpages-description": "Измјене којима се стварају нове странице.",
-       "rcfilters-filter-categorization-label": "Измјене категорија",
+       "rcfilters-filter-newpages-description": "Измене којима се стварају нове странице.",
+       "rcfilters-filter-categorization-label": "Измене категорија",
        "rcfilters-filter-categorization-description": "Записи о страницама додатим или уклоњеним из категорија.",
-       "rcfilters-filter-logactions-label": "РадÑ\9aе Ð·Ð°Ð±Ð¸Ñ\99ежене у дневницима",
+       "rcfilters-filter-logactions-label": "РадÑ\9aе Ð·Ð°Ð±ÐµÐ»ежене у дневницима",
        "rcfilters-filter-logactions-description": "Административне акције, стварање налога, брисање страница, отпремања…",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Филтер за „мање” измене је у сукобу са једним или више филтера типа измена, зато што одређени типови измена не могу да се означе као „мање”. Сукобљени филтери су означени у подручју Активни филтери, изнад.",
        "rcfilters-hideminor-conflicts-typeofchange": "Одређени типови измена не могу да се означе као „мање”, тако да је овај филтер у сукобу са следећим филтерима типа измена: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Овај филтер типа измене је у сукобу са филтером за „мање” измене. Одређени типови измена не могу да се означе као „мање”.",
-       "rcfilters-filtergroup-lastRevision": "Посљедње измјене",
-       "rcfilters-filter-lastrevision-label": "Посљедња измјена",
+       "rcfilters-filtergroup-lastRevision": "Последње измене",
+       "rcfilters-filter-lastrevision-label": "Последња измена",
        "rcfilters-filter-lastrevision-description": "Само најновија измена на страници.",
-       "rcfilters-filter-previousrevision-label": "Није посљедња измјена",
-       "rcfilters-filter-previousrevision-description": "Све измјене које нису „посљедње измјене”.",
+       "rcfilters-filter-previousrevision-label": "Није последња измена",
+       "rcfilters-filter-previousrevision-description": "Све измене које нису „последње измене”.",
        "rcfilters-filter-excluded": "Изостављено",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:није</strong> $1",
        "rcfilters-exclude-button-off": "Изостави означено",
-       "rcfilters-view-tags": "Означене измјене",
+       "rcfilters-exclude-button-on": "Изостави одабрано",
+       "rcfilters-view-tags": "Означене измене",
        "rcfilters-view-namespaces-tooltip": "Филтер резултата према именском простору",
-       "rcfilters-view-tags-tooltip": "Филтер резултата према ознаци измјене",
-       "rcfilters-view-tags-help-icon-tooltip": "Сазнајте више о означеним измјенама",
+       "rcfilters-view-tags-tooltip": "Филтрирање резултата према ознаци измене",
+       "rcfilters-view-return-to-default-tooltip": "Повратак на главни мени",
+       "rcfilters-view-tags-help-icon-tooltip": "Сазнајте више о означеним изменама",
        "rcfilters-liveupdates-button": "Ажурирања уживо",
+       "rcfilters-liveupdates-button-title-on": "Искључи ажурирања уживо",
+       "rcfilters-liveupdates-button-title-off": "Прикажи нове измене уживо",
        "rcfilters-watchlist-markseen-button": "Означи све измене као виђене",
-       "rcfilters-watchlist-showupdated": "Промјене на страницама које нисте посјетили од када је измјена извршена су <strong>подебљане</strong>, са испуњеним ознакама.",
+       "rcfilters-watchlist-edit-watchlist-button": "Промените Вашу листу надгледаних страница",
+       "rcfilters-watchlist-showupdated": "Измене на страницама које нисте посетили од када је измена извршена су <strong>подебљане</strong>, са испуњеним ознакама.",
        "rcfilters-preference-label": "Сакриј побољшану верзију скорашњих измена",
        "rcfilters-preference-help": "Поништава редизајн интерфејса из 2017. и све алатке додате тада и после.",
        "rcnotefrom": "Испод {{PLURAL:$5|је измена|су измене}} од <strong>$3, $4</strong> (до <strong>$1</strong> приказано).",
        "undeleteviewlink": "погледај",
        "undeleteinvert": "Обрни избор",
        "undeletecomment": "Разлог:",
-       "cannotundelete": "Враћање једне или свих ставник није успјело:\n$1",
+       "cannotundelete": "Враћање једне или свих није успело:\n$1",
        "undeletedpage": "<strong>Страница $1 је враћена</strong>\n\nПогледајте [[Special:Log/delete|дневник брисања]] за записе о скорашњим брисањима и враћањима.",
        "undelete-header": "Погледајте [[Special:Log/delete|историјат брисања]] за недавно обрисане странице.",
        "undelete-search-title": "Претрага обрисаних страница",
        "pageinfo-robot-index": "Дозвољено",
        "pageinfo-robot-noindex": "Није дозвољено",
        "pageinfo-watchers": "Број надгледача странице",
-       "pageinfo-visiting-watchers": "Број надгледача странице који су посјетили скорашње измјене",
+       "pageinfo-visiting-watchers": "Број надгледача странице који су посетили скорашње измене",
        "pageinfo-few-watchers": "Мање од $1 {{PLURAL:$1|пратиоца|пратиоца|пратилаца}}",
        "pageinfo-redirects-name": "Број преусмерења на ову страницу",
        "pageinfo-subpages-name": "Подстранице ове странице",
        "tag-filter-submit": "Филтрирај",
        "tag-list-wrapper": "([[Special:Tags|$1 {{PLURAL:$1|ознака|ознаке|ознака}}]]: $2)",
        "tag-mw-contentmodelchange": "промена модела садржаја",
+       "tag-mw-contentmodelchange-description": "Измене које мењају модел садржаја странице",
        "tags-title": "Ознаке",
        "tags-intro": "На овој страници је наведен списак ознака с којима програм може да означи измене и његово значење.",
        "tags-tag": "Назив ознаке",
index c4e1368..a3fbe35 100644 (file)
@@ -26,7 +26,8 @@
                        "Mega Aleksandar",
                        "Asmen",
                        "Obsuser",
-                       "Zoranzoki21"
+                       "Zoranzoki21",
+                       "Prevodim"
                ]
        },
        "tog-underline": "Podvlačenje veza:",
        "page_last": "poslednja",
        "histlegend": "Izbor razlika: izaberite kutijice izmena za upoređivanje i pritisnite enter ili dugme na dnu.<br />\nObjašnjenje: <strong>({{int:cur}})</strong> = razlika s trenutnom izmenom, <strong>({{int:last}})</strong> = razlika s prethodnom izmenom, <strong>{{int:minoreditletter}}</strong> = mala izmena",
        "history-fieldset-title": "Pregled izmena",
-       "history-show-deleted": "Samo obrisane",
+       "history-show-deleted": "Samo obrisane izmene",
        "histfirst": "najstarije",
        "histlast": "najnovije",
        "historysize": "({{PLURAL:$1|1 bajt|$1 bajta|$1 bajtova}})",
        "rcfilters-other-review-tools": "Ostali alati za pregled:",
        "rcfilters-activefilters": "Aktivni filteri",
        "rcfilters-advancedfilters": "Napredni filteri",
-       "rcfilters-limit-title": "Prikazati izmjena",
+       "rcfilters-limit-title": "Prikazati izmena",
        "rcfilters-limit-shownum": "Prikaži posljednjih $1 izmjena",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|dana|dana}}",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|sat|sata}}",
+       "rcfilters-quickfilters-placeholder-description": "Da biste sačuvali svoja podešavanja filtera i upotrebljavali ih kasnije, kliknite na ikonu za oznaku u području aktivnih filtera, ispod.",
        "rcfilters-search-placeholder": "Filter skorašnjih izmjena (pretražite ili počnite kucati)",
        "rcfilters-filtergroup-authorship": "Autorstvo doprinosa",
+       "rcfilters-filter-editsbyself-label": "Vaše izmene",
+       "rcfilters-filter-editsbyother-label": "Izmene drugih",
+       "rcfilters-filter-editsbyother-description": "Sve izmene osim Vaših.",
        "rcfilters-filter-user-experience-level-registered-label": "Registrovani",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni urednici.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrovani",
        "rcfilters-filter-user-experience-level-learner-label": "Učenici",
        "rcfilters-filter-user-experience-level-learner-description": "Više dana aktivnosti i izmjena od „novajlija”, ali manje od „iskusnih korisnika”.",
        "rcfilters-filter-user-experience-level-experienced-label": "Iskusni korisnici",
-       "rcfilters-filter-user-experience-level-experienced-description": "Preko 30 dana aktivnosti i 500 izmjena.",
-       "rcfilters-filter-humans-label": "Čovjek (nije bot)",
+       "rcfilters-filter-user-experience-level-experienced-description": "Registrovani urednici sa više od 500 izmena i 30 dana aktivnosti.",
+       "rcfilters-filter-bots-description": "Izmene napravljene automatizovanim alatima.",
+       "rcfilters-filter-humans-label": "Čovek (nije bot)",
+       "rcfilters-filter-humans-description": "Izmene koje su napravili ljudi-urednici.",
        "rcfilters-filter-patrolled-label": "Patrolirano",
+       "rcfilters-filter-patrolled-description": "Izmene označene kao patrolirane.",
        "rcfilters-filter-unpatrolled-label": "Nepatrolirano",
-       "rcfilters-filter-minor-label": "Manje izmjene",
-       "rcfilters-filter-pageedits-label": "Izmjene stranica",
-       "rcfilters-filter-pageedits-description": "Izmjene viki sadržaja, rasprava, opisa kategorija...",
+       "rcfilters-filter-unpatrolled-description": "Izmene koje nisu označene kao patrolirane.",
+       "rcfilters-filter-minor-label": "Manje izmene",
+       "rcfilters-filter-minor-description": "Izmene koje je autor označio kao manje.",
+       "rcfilters-filter-major-label": "Ne-manje izmene",
+       "rcfilters-filter-major-description": "Izmene koje nisu označene kao manje.",
+       "rcfilters-filter-watchlist-watched-description": "Izmene stranica koje su na Vašem spisku nadgledanja.",
+       "rcfilters-filter-watchlist-watchednew-label": "Nove izmene na spisku nadgledanja",
+       "rcfilters-filter-watchlist-watchednew-description": "Izmene stranica na spisku nadgledanja koje niste posetili od kada su napravljene izmene.",
+       "rcfilters-filter-watchlist-notwatched-description": "Sve osim izmena stranica na Vašem spisku nadgledanja.",
+       "rcfilters-filtergroup-changetype": "Vrsta izmene",
+       "rcfilters-filter-pageedits-label": "Izmene stranica",
+       "rcfilters-filter-pageedits-description": "Izmene viki sadržaja, rasprava, opisa kategorija...",
        "rcfilters-filter-newpages-label": "Stvaranje stranica",
-       "rcfilters-filter-newpages-description": "Izmjene kojima se stvaraju nove stranice.",
-       "rcfilters-filter-logactions-label": "Radnje zabilježene u dnevnicima",
-       "rcfilters-view-advanced-filters-label": "Napredni filteri",
+       "rcfilters-filter-newpages-description": "Izmene kojima se stvaraju nove stranice.",
+       "rcfilters-filter-categorization-label": "Izmene kategorija",
+       "rcfilters-filter-logactions-label": "Radnje zabeležene u dnevnicima",
+       "rcfilters-filtergroup-lastRevision": "Poslednje izmene",
+       "rcfilters-filter-lastrevision-label": "Poslednja izmena",
+       "rcfilters-filter-previousrevision-label": "Nije poslednja izmena",
+       "rcfilters-filter-previousrevision-description": "Sve izmene koje nisu „poslednje izmene”.",
+       "rcfilters-view-tags": "Označene izmene",
        "rcfilters-view-namespaces-tooltip": "Filter rezultata prema imenskom prostoru",
-       "rcfilters-view-tags-tooltip": "Filter rezultata prema oznaci izmjene",
+       "rcfilters-view-tags-tooltip": "Filtriranje rezultata prema oznaci izmene",
+       "rcfilters-view-tags-help-icon-tooltip": "Saznajte više o označenim izmenama",
        "rcfilters-liveupdates-button": "Ažuriranja uživo",
        "rcfilters-watchlist-markseen-button": "Označi sve izmene kao viđene",
+       "rcfilters-watchlist-showupdated": "Izmene na stranicama koje niste posetili od kada je izmena izvršena su <strong>podebljane</strong>, sa ispunjenim oznakama.",
        "rcfilters-preference-label": "Sakrij poboljšanu verziju skorašnjih izmena",
        "rcfilters-preference-help": "Poništava redizajn interfejsa iz 2017. i sve alatke dodate tada i posle.",
        "rcnotefrom": "Ispod {{PLURAL:$5|je izmena|su izmene}} od <strong>$3, $4</strong> (do <strong>$1</strong> prikazano).",
        "undeleteviewlink": "pogledaj",
        "undeleteinvert": "Obrni izbor",
        "undeletecomment": "Razlog:",
-       "cannotundelete": "Vraćanje nije uspelo:\n$1",
+       "cannotundelete": "Vraćanje jedne ili svih nije uspelo:\n$1",
        "undeletedpage": "<strong>Stranica $1 je vraćena</strong>\n\nPogledajte [[Special:Log/delete|dnevnik brisanja]] za zapise o skorašnjim brisanjima i vraćanjima.",
        "undelete-header": "Pogledajte [[Special:Log/delete|istorijat brisanja]] za nedavno obrisane stranice.",
        "undelete-search-title": "Pretraga obrisanih stranica",
        "pageinfo-robot-index": "Dozvoljeno",
        "pageinfo-robot-noindex": "Nije dozvoljeno",
        "pageinfo-watchers": "Broj nadgledača stranicе",
-       "pageinfo-visiting-watchers": "Broj nadgledača stranice koji su posjetili skorašnje izmjene",
+       "pageinfo-visiting-watchers": "Broj nadgledača stranice koji su posetili skorašnje izmene",
        "pageinfo-few-watchers": "Manje od $1 {{PLURAL:$1|pratioca|pratilaca}}",
        "pageinfo-redirects-name": "Broj preusmerenja na ovu stranicu",
        "pageinfo-subpages-name": "Podstranice ove stranice",
        "tag-filter": "Filter za [[Special:Tags|oznake]]:",
        "tag-filter-submit": "Filtriraj",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Oznaka|Oznake}}]]: $2)",
+       "tag-mw-contentmodelchange-description": "Izmene koje menjaju model sadržaja stranice",
        "tags-title": "Oznake",
        "tags-intro": "Na ovoj stranici je naveden spisak oznaka s kojima program može da označi izmene i njegovo značenje.",
        "tags-tag": "Naziv oznake",
index e7d3c4e..0a647ad 100644 (file)
        "rcfilters-savedqueries-apply-and-setdefault-label": "Skapa standardfilter",
        "rcfilters-savedqueries-cancel-label": "Avbryt",
        "rcfilters-savedqueries-add-new-title": "Spara filterinställningar",
+       "rcfilters-savedqueries-already-saved": "Dessa filter har redan sparats",
        "rcfilters-restore-default-filters": "Återställ standardfilter",
        "rcfilters-clear-all-filters": "Rensa alla filter",
        "rcfilters-show-new-changes": "Visa de nyaste ändringarna",
        "uploadstash-refresh": "Uppdatera listan över filer",
        "uploadstash-thumbnail": "visa miniatyr",
        "uploadstash-exception": "Kunde inte lagra uppladdning i stash ($1): \"$2\".",
+       "uploadstash-bad-path": "Sökvägen finns inte",
+       "uploadstash-bad-path-invalid": "Sökvägen är ogiltig.",
+       "uploadstash-bad-path-unknown-type": "Okänd typ \"$1\".",
+       "uploadstash-bad-path-unrecognized-thumb-name": "Okänt miniatyrnamn.",
+       "uploadstash-bad-path-no-handler": "Ingen hantering hittades för MIME $1 till filen $2.",
+       "uploadstash-bad-path-bad-format": "Nyckeln \"$1\" är inte i korrekt format.",
+       "uploadstash-file-not-found": "Nyckeln \"$1\" hittades inte i stash.",
+       "uploadstash-file-not-found-no-thumb": "Kunde inte hämta miniatyrbild.",
+       "uploadstash-file-not-found-no-local-path": "Ingen lokal sökväg för nedskalat objekt.",
+       "uploadstash-file-not-found-no-object": "Kunde inte skapa lokalt filobjekt för miniatyr.",
+       "uploadstash-file-not-found-no-remote-thumb": "Misslyckades att hämta miniatyrbild: $1\nURL = $2",
+       "uploadstash-file-not-found-missing-content-type": "Header för content-type saknas.",
+       "uploadstash-file-not-found-not-exists": "Kan inte hitta sökvägen eller filen består inte av ren text.",
+       "uploadstash-file-too-large": "Kan inte behandla en fil som är större än $1 byte.",
+       "uploadstash-not-logged-in": "Ingen användare är inloggad, filer måste tillhöra användare.",
+       "uploadstash-wrong-owner": "Denna fil ($1) tillhör inte aktuell användare.",
+       "uploadstash-no-such-key": "Ingen sådan nyckel ($1), kan inte ta bort.",
+       "uploadstash-no-extension": "Tillägget är null.",
+       "uploadstash-zero-length": "Filens längd är noll.",
        "invalid-chunk-offset": "Ogiltig segmentsförskjutning",
        "img-auth-accessdenied": "Åtkomst nekad",
        "img-auth-nopathinfo": "PATH_INFO saknas.\nDin server är inte inställd för att ge denna information.\nDen kan vara CGI-baserad och stöder inte img_auth.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Se bildbehörighet.]",
index 0dcfe2d..89c6e9a 100644 (file)
@@ -7,6 +7,7 @@
  * @file
  *
  * @author Alchimista
+ * @author Athena
  * @author Cecílio
  * @author MCruz
  * @author Malafaya
@@ -20,8 +21,8 @@ $namespaceNames = [
        NS_MEDIA            => 'Media',
        NS_SPECIAL          => 'Special',
        NS_TALK             => 'Cumbersa',
-       NS_USER             => 'Outelizador',
-       NS_USER_TALK        => 'Cumbersa_outelizador',
+       NS_USER             => 'Outelizador(a)',
+       NS_USER_TALK        => 'Cumbersa_outelizador(a)',
        NS_PROJECT_TALK     => '$1_cumbersa',
        NS_FILE             => 'Fexeiro',
        NS_FILE_TALK        => 'Cumbersa_fexeiro',
@@ -53,11 +54,16 @@ $namespaceAliases = [
        'Categoria_Discussão' => NS_CATEGORY_TALK,
 ];
 
+$namespaceGenderAliases = [
+       NS_USER => [ 'male' => 'Outelizador', 'female' => 'Outelizadora' ],
+       NS_USER_TALK => [ 'male' => 'Cumbersa_outelizador', 'female' => 'Cumbersa_outelizadora' ],
+]; // T180052
+
 $specialPageAliases = [
-       'CreateAccount'             => [ 'Criar Cuonta' ],
-       'Lonelypages'               => [ 'Páiginas Uorfanas' ],
-       'Uncategorizedcategories'   => [ 'Catadories sien catadories' ],
-       'Uncategorizedimages'       => [ 'Eimaiges sien catadories' ],
+       'CreateAccount'             => [ 'Criar_Cuonta' ],
+       'Lonelypages'               => [ 'Páiginas_Uorfanas' ],
+       'Uncategorizedcategories'   => [ 'Catadories_sien_catadories' ],
+       'Uncategorizedimages'       => [ 'Eimaiges_sien_catadories' ],
        'Userlogin'                 => [ 'Antrar' ],
        'Userlogout'                => [ 'Salir' ],
 ];
index b504bde..e5b4c13 100644 (file)
@@ -25,7 +25,7 @@ class CheckComposerLockUpToDate extends Maintenance {
                        $lockLocation = "$IP/vendor/composer.lock";
                        if ( !file_exists( $lockLocation ) ) {
                                $this->error(
-                                       'Could not find composer.lock file. Have you run "composer install"?',
+                                       'Could not find composer.lock file. Have you run "composer install --no-dev"?',
                                        1
                                );
                        }
@@ -53,7 +53,7 @@ class CheckComposerLockUpToDate extends Maintenance {
                if ( $found ) {
                        $this->error(
                                'Error: your composer.lock file is not up to date. ' .
-                                       'Run "composer update" to install newer dependencies',
+                                       'Run "composer update --no-dev" to install newer dependencies',
                                1
                        );
                } else {
index eb9797f..04ad255 100644 (file)
@@ -60,8 +60,6 @@ class PopulateRecentChangesSource extends LoggedUpdateMaintenance {
                $updatedValues = $this->buildUpdateCondition( $dbw );
 
                while ( $blockEnd <= $end ) {
-                       $cond = "rc_id BETWEEN $blockStart AND $blockEnd";
-
                        $dbw->update(
                                'recentchanges',
                                [ $updatedValues ],
diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc
deleted file mode 100644 (file)
index 8ac7f91..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-<?php
-/**
- * Helper class for userOptions.php script.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-// Options we will use
-$options = [ 'list', 'nowarn', 'quiet', 'usage', 'dry' ];
-$optionsWithArgs = [ 'old', 'new' ];
-
-require_once __DIR__ . '/commandLine.inc';
-
-/**
- * @ingroup Maintenance
- */
-class UserOptions {
-       public $mQuick;
-       public $mQuiet;
-       public $mDry;
-       public $mAnOption;
-       public $mOldValue;
-       public $mNewValue;
-
-       private $mMode, $mReady;
-
-       /**
-        * Constructor. Will show usage and exit if script options are not correct
-        * @param array $opts
-        * @param array $args
-        */
-       function __construct( $opts, $args ) {
-               if ( !$this->checkOpts( $opts, $args ) ) {
-                       self::showUsageAndExit();
-               } else {
-                       $this->mReady = $this->initializeOpts( $opts, $args );
-               }
-       }
-
-       /**
-        * This is used to check options. Only needed on construction
-        *
-        * @param array $opts
-        * @param array $args
-        *
-        * @return bool
-        */
-       private function checkOpts( $opts, $args ) {
-               // The three possible ways to run the script:
-               $list = isset( $opts['list'] );
-               $usage = isset( $opts['usage'] ) && ( count( $args ) <= 1 );
-               $change = isset( $opts['old'] ) && isset( $opts['new'] ) && ( count( $args ) <= 1 );
-
-               // We want only one of them
-               $isValid = ( ( $list + $usage + $change ) == 1 );
-
-               return $isValid;
-       }
-
-       /**
-        * load script options in the object
-        *
-        * @param array $opts
-        * @param array $args
-        *
-        * @return bool
-        */
-       private function initializeOpts( $opts, $args ) {
-               $this->mQuick = isset( $opts['nowarn'] );
-               $this->mQuiet = isset( $opts['quiet'] );
-               $this->mDry = isset( $opts['dry'] );
-
-               // Set object properties, specially 'mMode' used by run()
-               if ( isset( $opts['list'] ) ) {
-                       $this->mMode = 'LISTER';
-               } elseif ( isset( $opts['usage'] ) ) {
-                       $this->mMode = 'USAGER';
-                       $this->mAnOption = isset( $args[0] ) ? $args[0] : false;
-               } elseif ( isset( $opts['old'] ) && isset( $opts['new'] ) ) {
-                       $this->mMode = 'CHANGER';
-                       $this->mOldValue = $opts['old'];
-                       $this->mNewValue = $opts['new'];
-                       $this->mAnOption = $args[0];
-               } else {
-                       die( "There is a bug in the software, this should never happen\n" );
-               }
-
-               return true;
-       }
-
-       /**
-        * Dumb stuff to run a mode.
-        * @return bool
-        */
-       public function run() {
-               if ( !$this->mReady ) {
-                       return false;
-               }
-
-               $this->{$this->mMode}();
-
-               return true;
-       }
-
-       /**
-        * List default options and their value
-        */
-       private function LISTER() {
-               $def = User::getDefaultOptions();
-               ksort( $def );
-               $maxOpt = 0;
-               foreach ( $def as $opt => $value ) {
-                       $maxOpt = max( $maxOpt, strlen( $opt ) );
-               }
-               foreach ( $def as $opt => $value ) {
-                       printf( "%-{$maxOpt}s: %s\n", $opt, $value );
-               }
-       }
-
-       /**
-        * List options usage
-        */
-       private function USAGER() {
-               $ret = [];
-               $defaultOptions = User::getDefaultOptions();
-
-               // We list user by user_id from one of the replica DBs
-               $dbr = wfGetDB( DB_REPLICA );
-               $result = $dbr->select( 'user',
-                       [ 'user_id' ],
-                       [],
-                       __METHOD__
-               );
-
-               foreach ( $result as $id ) {
-                       $user = User::newFromId( $id->user_id );
-
-                       // Get the options and update stats
-                       if ( $this->mAnOption ) {
-                               if ( !array_key_exists( $this->mAnOption, $defaultOptions ) ) {
-                                       print "Invalid user option. Use --list to see valid choices\n";
-                                       exit;
-                               }
-
-                               $userValue = $user->getOption( $this->mAnOption );
-                               if ( $userValue <> $defaultOptions[$this->mAnOption] ) {
-                                       // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
-                                       @$ret[$this->mAnOption][$userValue]++;
-                                       // @codingStandardsIgnoreEnd
-                               }
-                       } else {
-
-                               foreach ( $defaultOptions as $name => $defaultValue ) {
-                                       $userValue = $user->getOption( $name );
-                                       if ( $userValue <> $defaultValue ) {
-                                               // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
-                                               @$ret[$name][$userValue]++;
-                                               // @codingStandardsIgnoreEnd
-                                       }
-                               }
-                       }
-               }
-
-               foreach ( $ret as $optionName => $usageStats ) {
-                       print "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n";
-                       foreach ( $usageStats as $value => $count ) {
-                               print " $count user(s): '$value'\n";
-                       }
-                       print "\n";
-               }
-       }
-
-       /**
-        * Change our users options
-        */
-       private function CHANGER() {
-               $this->warn();
-
-               // We list user by user_id from one of the replica DBs
-               $dbr = wfGetDB( DB_REPLICA );
-               $result = $dbr->select( 'user',
-                       [ 'user_id' ],
-                       [],
-                       __METHOD__
-               );
-
-               foreach ( $result as $id ) {
-                       $user = User::newFromId( $id->user_id );
-
-                       $curValue = $user->getOption( $this->mAnOption );
-                       $username = $user->getName();
-
-                       if ( $curValue == $this->mOldValue ) {
-                               if ( !$this->mQuiet ) {
-                                       print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' " .
-                                               "to '{$this->mNewValue}'): ";
-                               }
-
-                               // Change value
-                               $user->setOption( $this->mAnOption, $this->mNewValue );
-
-                               // Will not save the settings if run with --dry
-                               if ( !$this->mDry ) {
-                                       $user->saveSettings();
-                               }
-                               if ( !$this->mQuiet ) {
-                                       print " OK\n";
-                               }
-                       } elseif ( !$this->mQuiet ) {
-                               print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n";
-                       }
-               }
-       }
-
-       /**
-        * Return an array of option names
-        * @return array
-        */
-       public static function getDefaultOptionsNames() {
-               $def = User::getDefaultOptions();
-               $ret = [];
-               foreach ( $def as $optname => $defaultValue ) {
-                       array_push( $ret, $optname );
-               }
-
-               return $ret;
-       }
-
-       public static function showUsageAndExit() {
-               print <<<USAGE
-
-This script pass through all users and change one of their options.
-The new option is NOT validated.
-
-Usage:
-       php userOptions.php --list
-       php userOptions.php [user option] --usage
-       php userOptions.php [options] <user option> --old <old value> --new <new value>
-
-Switchs:
-       --list : list available user options and their default value
-
-       --usage : report all options statistics or just one if you specify it.
-
-       --old <old value> : the value to look for
-       --new <new value> : new value to update users with
-
-Options:
-       --nowarn: hides the 5 seconds warning
-       --quiet : do not print what is happening
-       --dry   : do not save user settings back to database
-
-USAGE;
-               exit( 0 );
-       }
-
-       /**
-        * The warning message and countdown
-        * @return bool
-        */
-       public function warn() {
-               if ( $this->mQuick ) {
-                       return true;
-               }
-
-               print <<<WARN
-The script is about to change the skin for ALL USERS in the database.
-Users with option <$this->mAnOption> = '$this->mOldValue' will be made to use '$this->mNewValue'.
-
-Abort with control-c in the next five seconds....
-WARN;
-               wfCountDown( 5 );
-
-               return true;
-       }
-}
index 53db48c..7cf16b6 100644 (file)
  * @author Antoine Musso <hashar at free dot fr>
  */
 
-// This is a command line script, load tools and parse args
-require_once 'userOptions.inc';
+require_once __DIR__ . '/Maintenance.php';
 
-// Load up our tool system, exit with usage() if options are not fine
-$uo = new UserOptions( $options, $args );
+/**
+ * @ingroup Maintenance
+ */
+class UserOptionsMaintenance extends Maintenance {
+
+       function __construct() {
+               parent::__construct();
+
+               $this->addDescription( 'Pass through all users and change one of their options.
+The new option is NOT validated.' );
+
+               $this->addOption( 'list', 'List available user options and their default value' );
+               $this->addOption( 'usage', 'Report all options statistics or just one if you specify it' );
+               $this->addOption( 'old', 'The value to look for', false, true );
+               $this->addOption( 'new', 'Rew value to update users with', false, true );
+               $this->addOption( 'nowarn', 'Hides the 5 seconds warning' );
+               $this->addOption( 'dry', 'Do not save user settings back to database' );
+               $this->addArg( 'option name', 'Name of the option to change or provide statistics about', false );
+       }
+
+       /**
+        * Do the actual work
+        */
+       public function execute() {
+               if ( $this->hasOption( 'list' ) ) {
+                       $this->listAvailableOptions();
+               } elseif ( $this->hasOption( 'usage' ) ) {
+                       $this->showUsageStats();
+               } elseif ( $this->hasOption( 'old' )
+                       && $this->hasOption( 'new' )
+                       && $this->hasArg( 0 )
+               ) {
+                       $this->updateOptions();
+               } else {
+                       $this->maybeHelp( /* force = */ true );
+               }
+       }
+
+       /**
+        * List default options and their value
+        */
+       private function listAvailableOptions() {
+               $def = User::getDefaultOptions();
+               ksort( $def );
+               $maxOpt = 0;
+               foreach ( $def as $opt => $value ) {
+                       $maxOpt = max( $maxOpt, strlen( $opt ) );
+               }
+               foreach ( $def as $opt => $value ) {
+                       $this->output( sprintf( "%-{$maxOpt}s: %s\n", $opt, $value ) );
+               }
+       }
+
+       /**
+        * List options usage
+        */
+       private function showUsageStats() {
+               $option = $this->getArg( 0 );
+
+               $ret = [];
+               $defaultOptions = User::getDefaultOptions();
+
+               // We list user by user_id from one of the replica DBs
+               $dbr = wfGetDB( DB_REPLICA );
+               $result = $dbr->select( 'user',
+                       [ 'user_id' ],
+                       [],
+                       __METHOD__
+               );
+
+               foreach ( $result as $id ) {
+                       $user = User::newFromId( $id->user_id );
+
+                       // Get the options and update stats
+                       if ( $option ) {
+                               if ( !array_key_exists( $option, $defaultOptions ) ) {
+                                       $this->error( "Invalid user option. Use --list to see valid choices\n", 1 );
+                               }
+
+                               $userValue = $user->getOption( $option );
+                               if ( $userValue <> $defaultOptions[$option] ) {
+                                       // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
+                                       @$ret[$option][$userValue]++;
+                                       // @codingStandardsIgnoreEnd
+                               }
+                       } else {
+
+                               foreach ( $defaultOptions as $name => $defaultValue ) {
+                                       $userValue = $user->getOption( $name );
+                                       if ( $userValue != $defaultValue ) {
+                                               // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
+                                               @$ret[$name][$userValue]++;
+                                               // @codingStandardsIgnoreEnd
+                                       }
+                               }
+                       }
+               }
+
+               foreach ( $ret as $optionName => $usageStats ) {
+                       $this->output( "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n" );
+                       foreach ( $usageStats as $value => $count ) {
+                               $this->output( " $count user(s): '$value'\n" );
+                       }
+                       print "\n";
+               }
+       }
+
+       /**
+        * Change our users options
+        */
+       private function updateOptions() {
+               $dryRun = $this->hasOption( 'dry' );
+               $option = $this->getArg( 0 );
+               $from = $this->getOption( 'old' );
+               $to = $this->getOption( 'new' );
+
+               if ( !$dryRun ) {
+                       $this->warn( $option, $from, $to );
+               }
+
+               // We list user by user_id from one of the replica DBs
+               // @todo: getting all users in one query does not scale
+               $dbr = wfGetDB( DB_REPLICA );
+               $result = $dbr->select( 'user',
+                       [ 'user_id' ],
+                       [],
+                       __METHOD__
+               );
+
+               foreach ( $result as $id ) {
+                       $user = User::newFromId( $id->user_id );
+
+                       $curValue = $user->getOption( $option );
+                       $username = $user->getName();
+
+                       if ( $curValue == $from ) {
+                               $this->output( "Setting {$option} for $username from '{$from}' to '{$to}'): " );
+
+                               // Change value
+                               $user->setOption( $option, $to );
+
+                               // Will not save the settings if run with --dry
+                               if ( !$dryRun ) {
+                                       $user->saveSettings();
+                               }
+                               $this->output( " OK\n" );
+                       } else {
+                               $this->output( "Not changing '$username' using <{$option}> = '$curValue'\n" );
+                       }
+               }
+       }
+
+       /**
+        * The warning message and countdown
+        *
+        * @param string $option
+        * @param string $from
+        * @param string $to
+        */
+       private function warn( $option, $from, $to ) {
+               if ( $this->hasOption( 'nowarn' ) ) {
+                       return;
+               }
+
+               $this->output( <<<WARN
+The script is about to change the options for ALL USERS in the database.
+Users with option <$option> = '$from' will be made to use '$to'.
 
-$uo->run();
+Abort with control-c in the next five seconds....
+WARN
+               );
+               $this->countDown( 5 );
+       }
+}
 
-print "Done.\n";
+$maintClass = 'UserOptionsMaintenance';
+require RUN_MAINTENANCE_IF_MAIN;
index cad530b..73ec1a7 100644 (file)
@@ -11,6 +11,7 @@
 
 #pagehistory li.selected {
        background-color: #f8f9fa;
+       color: #252525;
        border: 1px dashed #a2a9b1;
 }
 
index 3e0d2b9..8cd25d8 100644 (file)
@@ -22,6 +22,7 @@ textarea {
 
 .editOptions {
        background-color: #eaecf0;
+       color: #252525;
        border: 1px solid #c8ccd1;
        border-top: 0;
        padding: 1em 1em 1.5em 1em;
index 47f8045..9750452 100644 (file)
        user-select: none;
 }
 
-@indicator-size: unit( 12 / 16 / 0.8, em );
+@size-indicator: unit( 12 / 16 / 0.8, em );
 
 .mw-widget-dateInputWidget {
        &-handle {
                .oo-ui-unselectable();
 
-               > .oo-ui-labelElement-label {
-                       padding: 0;
-               }
-
                > .oo-ui-indicatorElement-indicator {
                        display: none;
                }
                position: absolute;
                top: 0;
                right: 0;
-               width: @indicator-size;
+               width: @size-indicator;
                height: 100%;
                margin: 0 0.775em;
        }
 
        > .oo-ui-textInputWidget {
                z-index: 2;
-
-               & input {
-                       padding-left: 1em;
-               }
        }
 
        &-calendar {
                background-color: #fff;
                position: absolute;
                margin-top: -2px;
-               box-shadow: 0 0.15em 0 0 rgba( 0, 0, 0, 0.15 );
+               border-radius: 2px;
+               box-shadow: 0 2px 2px 0 rgba( 0, 0, 0, 0.25 );
                z-index: 1;
 
                &:focus {
-                       box-shadow: inset 0 0 0 1px #36c, 0 0.15em 0 0 rgba( 0, 0, 0, 0.15 );
+                       box-shadow: inset 0 0 0 1px #36c, 0 2px 2px 0 rgba( 0, 0, 0, 0.25 );
                        z-index: 3;
                }
        }
@@ -68,8 +61,8 @@
 
        &.oo-ui-flaggedElement-invalid {
                .mw-widget-dateInputWidget-handle {
-                       border-color: #f00;
-                       box-shadow: inset 0 0 0 0 #f00;
+                       border-color: #d33;
+                       box-shadow: none;
                }
        }
 
index 18cf723..74b5abc 100644 (file)
@@ -5,6 +5,32 @@
  * @license The MIT License (MIT); see LICENSE.txt
  */
 
+// Variables taken from OOUI's WikimediaUI theme
+@oo-ui-font-size-browser: 16; // assumed browser default of `16px`
+@oo-ui-font-size-base: 0.8em; // equals `12.8px` at browser default of `16px`
+
+@background-color-base: #fff;
+
+@color-base--emphasized: #000;
+
+@border-base: 1px solid #a2a9b1;
+@border-color-base--focus: #36c;
+@border-color-input--hover: #72777d;
+@border-radius-base: 2px;
+
+@padding-input-text: @padding-top-base @padding-horizontal-input-text @padding-bottom-base;
+@padding-horizontal-input-text: 8 / @oo-ui-font-size-browser / @oo-ui-font-size-base;
+@padding-top-base: 8 / @oo-ui-font-size-browser / @oo-ui-font-size-base; // equals `0.625em`≈`8px`
+@padding-bottom-base: 7 / @oo-ui-font-size-browser / @oo-ui-font-size-base; // equals `0.547em`≈`7px`
+
+@box-shadow-widget: inset 0 0 0 1px transparent;
+@box-shadow-widget--focus: inset 0 0 0 1px #36c;
+
+@line-height-widget-singleline: 1.172em; // Firefox needs a value, Chrome the unit; equals `15px` at base `font-size: 12.8px`
+
+@transition-ease-out-sine-medium: 200ms cubic-bezier( 0.39, 0.575, 0.565, 1 );
+
+// Mixins taken from OOUI
 .oo-ui-box-sizing( @type: border-box ) {
        -webkit-box-sizing: @type;
        -moz-box-sizing: @type;
        }
 }
 
+.oo-ui-transition( @value1, @value2: X, ... ) {
+       @value: ~`"@{arguments}".replace( /[\[\]]|\,\sX/g, '' )`; // stylelint-disable-line function-comma-space-after, function-whitespace-after, string-quotes, value-keyword-case
+       -webkit-transition: @value;
+       -moz-transition: @value;
+       transition: @value;
+}
+
+// DateInputWidget rules
 .mw-widget-dateInputWidget {
        &.oo-ui-textInputWidget {
                display: inline-block;
                position: relative;
                width: 21em;
                margin-top: 0.25em;
-               .oo-ui-inline-spacing( 0.5em );
+               // .oo-ui-inline-spacing( 0.5em ); already inherited from `.oo-ui-inputWidget`
                margin-bottom: 0.25em;
                margin-left: 0;
        }
        // Note that this block applies to both the PHP widget and the JS widget
        &-handle,
        &.oo-ui-textInputWidget input {
-               background-color: #fff;
                display: inline-block;
                position: relative;
-               .oo-ui-box-sizing( border-box );
-               width: 100%;
                cursor: pointer;
-               padding: 0.5em 1em;
-               border: 1px solid #a2a9b1;
-               border-radius: 2px;
-               outline: 0;
-               line-height: 1.275;
                /**
                 * Ensures non-infused and infused widget have the same height.
                 * Equal to line height + top padding + bottom padding
                 */
-               height: 2.275em;
+               max-height: 2.458em;
+       }
+
+       // Ensure `.mw-widget-dateInputWidget-handle` similar appearance to OOUI's `.oo-ui-textInputWidget`
+       &-handle {
+               background-color: @background-color-base;
+               color: @color-base--emphasized;
+               .oo-ui-box-sizing( border-box );
+               width: 100%;
+               border: @border-base;
+               border-radius: @border-radius-base;
+               padding: @padding-input-text;
+               line-height: @line-height-widget-singleline;
+       }
+
+       &.oo-ui-widget-enabled {
+               .mw-widget-dateInputWidget-handle {
+                       box-shadow: @box-shadow-widget; // necessary for smooth transition
+                       .oo-ui-transition(
+                               border-color @transition-ease-out-sine-medium,
+                               box-shadow @transition-ease-out-sine-medium
+                       );
+
+                       &:hover {
+                               border-color: @border-color-input--hover;
+                       }
+
+                       &:focus {
+                               outline: 0;
+                               border-color: @border-color-base--focus;
+                               box-shadow: @box-shadow-widget--focus;
+                       }
+
+                       & > .oo-ui-labelElement-label {
+                               cursor: pointer;
+                       }
+               }
+       }
+
+       &-active {
+               &.oo-ui-textInputWidget input {
+                       cursor: text;
+               }
        }
 }
index 633798d..481980f 100644 (file)
@@ -15,6 +15,7 @@
        margin-bottom: 0.5em;
        border: solid 1px #ddd;
        background-color: #fcfcfc;
+       color: #252525;
        /* Click handler in mediawiki.notification.js */
        cursor: pointer;
 
index ca31fbc..f7bf7a6 100644 (file)
@@ -64,6 +64,7 @@ $wgAutoloadClasses += [
        'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php",
 
        # tests/phpunit/includes
+       'RevisionDbTestBase' => "$testDir/phpunit/includes/RevisionDbTestBase.php",
        'RevisionTestModifyableContent' => "$testDir/phpunit/includes/RevisionTestModifyableContent.php",
        'RevisionTestModifyableContentHandler' => "$testDir/phpunit/includes/RevisionTestModifyableContentHandler.php",
        'TestLogger' => "$testDir/phpunit/includes/TestLogger.php",
index 1204dbd..cef935c 100644 (file)
@@ -1912,6 +1912,33 @@ a <div>foo</div>
 <p>b</p>
 !! end
 
+!! test
+No p-wrappable content
+!! wikitext
+<span><div>x</div></span>
+<span><s><div>x</div></s></span>
+<small><em></em></small><span><s><div>x</div></s></span>
+!! html+tidy
+<div><span>x</span></div>
+<div><span><s>x</s></span></div>
+<div><span><s>x</s></span></div>
+!! html/parsoid
+<span><div>x</div></span>
+<span><s><div>x</div></s></span>
+<small><em></em></small><span><s><div>x</div></s></span>
+!! end
+
+# T177612: Parsoid-only test
+!! test
+Transclusion meta tags shouldn't trip Parsoid's useless p-wrapper stripping code
+!! wikitext
+{{echo|<span><div>x</div></span>}}
+x
+!! html/parsoid
+<span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"stx":"html","pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;span>&lt;div>x&lt;/div>&lt;/span>"}},"i":0}}]}'><div>x</div></span>
+<p>x</p>
+!! end
+
 !! test
 Block tag on one line (<blockquote>)
 !! wikitext
@@ -4806,8 +4833,11 @@ foo//example.com/Foo
 </p>
 !! end
 
+## html2wt and html2html will fail because we will prefer the :en: interwiki prefix over wikipedia:
 !! test
 External links: with no contents
+!! options
+parsoid=wt2html,wt2wt
 !! wikitext
 [http://en.wikipedia.org/wiki/Foo]
 
@@ -4911,7 +4941,7 @@ External links: Free with trailing quotes (T113666)
 news:'a'b''c''d e
 !! html/php
 <p><b>News:</b> Stuff here
-</p><p><a rel="nofollow" class="external free" href="news:'a'b">news:'a'b</a><i>c</i>d e
+</p><p><a rel="nofollow" class="external free" href="news:&#39;a&#39;b">news:'a'b</a><i>c</i>d e
 </p>
 !! html/parsoid
 <p><b>News:</b> Stuff here</p>
@@ -5557,8 +5587,8 @@ External link containing a single quote. (T65947)
 
 [//foo.org/bar'baz bang]
 !! html/php
-<p><a rel="nofollow" class="external autonumber" href="//foo.org/bar'baz">[1]</a>
-</p><p><a rel="nofollow" class="external text" href="//foo.org/bar'baz">bang</a>
+<p><a rel="nofollow" class="external autonumber" href="//foo.org/bar&#39;baz">[1]</a>
+</p><p><a rel="nofollow" class="external text" href="//foo.org/bar&#39;baz">bang</a>
 </p>
 !! html/parsoid
 <p><a rel="mw:ExtLink" href="//foo.org/bar'baz"></a></p>
@@ -5935,11 +5965,11 @@ parsoid=html2wt
 !! wikitext
 [[Foo|Bar]]
 [[Foo|Bar]]
-[[wikipedia:Foo|Bar]]
-[[wikipedia:Foo|Bar]]
+[[:en:Foo|Bar]]
+[[:en:Foo|Bar]]
 
-[[wikipedia:European_Robin|European Robin]]
-[[wikipedia:European_Robin|European Robin]]
+[[:en:European_Robin|European Robin]]
+[[:en:European_Robin|European Robin]]
 !! end
 
 !! test
@@ -7973,7 +8003,7 @@ Link containing double-single-quotes '' (T6598)
 !! wikitext
 [[Lista d''e paise d''o munno]]
 !! html/php
-<p><a href="/index.php?title=Lista_d%27%27e_paise_d%27%27o_munno&amp;action=edit&amp;redlink=1" class="new" title="Lista d''e paise d''o munno (page does not exist)">Lista d''e paise d''o munno</a>
+<p><a href="/index.php?title=Lista_d%27%27e_paise_d%27%27o_munno&amp;action=edit&amp;redlink=1" class="new" title="Lista d&#39;&#39;e paise d&#39;&#39;o munno (page does not exist)">Lista d''e paise d''o munno</a>
 </p>
 !! html/parsoid
 <p><a rel="mw:WikiLink" href="./Lista_d''e_paise_d''o_munno" title="Lista d''e paise d''o munno">Lista d''e paise d''o munno</a></p>
@@ -8038,9 +8068,9 @@ Link with double quotes in title part (literal) and alternate part (interpreted)
 [[''Pentecoste''|''Pentecoste'']]
 !! html/php
 <p><a href="/index.php?title=Special:Upload&amp;wpDestFile=Denys_Savchenko_%27%27Pentecoste%27%27.jpg" class="new" title="File:Denys Savchenko &#39;&#39;Pentecoste&#39;&#39;.jpg">File:Denys Savchenko <i>Pentecoste</i>.jpg</a>
-</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="''Pentecoste'' (page does not exist)">''Pentecoste''</a>
-</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="''Pentecoste'' (page does not exist)">Pentecoste</a>
-</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="''Pentecoste'' (page does not exist)"><i>Pentecoste</i></a>
+</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="&#39;&#39;Pentecoste&#39;&#39; (page does not exist)">''Pentecoste''</a>
+</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="&#39;&#39;Pentecoste&#39;&#39; (page does not exist)">Pentecoste</a>
+</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="&#39;&#39;Pentecoste&#39;&#39; (page does not exist)"><i>Pentecoste</i></a>
 </p>
 !! html/parsoid
 <p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"apierror-filedoesnotexist","message":"This image does not exist."}]}'><a href="./File:Denys_Savchenko_''Pentecoste''.jpg"><img resource="./File:Denys_Savchenko_''Pentecoste''.jpg" src="./Special:FilePath/Denys_Savchenko_''Pentecoste''.jpg" height="220" width="220"/></a></span></p>
@@ -8333,7 +8363,7 @@ language=kaa
 !! wikitext
 [[Something]]'nice
 !! html
-<p><a href="/index.php?title=Something&amp;action=edit&amp;redlink=1" class="new" title="Something (bet ele jaratılmag'an)">Something'nice</a>
+<p><a href="/index.php?title=Something&amp;action=edit&amp;redlink=1" class="new" title="Something (bet ele jaratılmag&#39;an)">Something'nice</a>
 </p>
 !! end
 
@@ -8517,6 +8547,31 @@ parsoid=html2wt,html2html
 Aðrir mótmælenda<nowiki/>[[söfnuður]]
 !! end
 
+!! test
+Parsoid link bracket escaping
+!! options
+parsoid=html2wt,html2html
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./Test" title="Test">Test</a></p>
+<p>[<a rel="mw:WikiLink" href="./Test" title="Test">Test</a>]</p>
+<p>[[<a rel="mw:WikiLink" href="./Test" title="Test">Test</a>]]</p>
+<p>[[[<a rel="mw:WikiLink" href="./Test" title="Test">Test</a>]]]</p>
+<p>[[[[<a rel="mw:WikiLink" href="./Test" title="Test">Test</a>]]]]</p>
+<p>[[[[[<a rel="mw:WikiLink" href="./Test" title="Test">Test</a>]]]]]</p>
+!! wikitext
+[[Test]]
+
+[<nowiki/>[[Test]]]
+
+[[[[Test]]]]
+
+[[[<nowiki/>[[Test]]]]]
+
+[[[[[[Test]]]]]]
+
+[[[[[<nowiki/>[[Test]]]]]]]
+!! end
+
 !! test
 Parsoid-centric test: Whitespace in ext- and wiki-links should be preserved
 !! wikitext
@@ -8584,8 +8639,11 @@ parsoid=wt2html,wt2wt,html2html
 <p><a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?" title="meatball:">MeatBall:</a></p>
 !! end
 
+## html2wt and html2html will fail because we will prefer the :en: interwiki prefix over wikipedia:
 !! test
 Interwiki link encoding conversion (T3636)
+!! options
+parsoid=wt2html,wt2wt
 !! wikitext
 *[[Wikipedia:ro:Olteni&#0355;a]]
 *[[Wikipedia:ro:Olteni&#355;a]]
@@ -8598,6 +8656,11 @@ Interwiki link encoding conversion (T3636)
 <li><a href="http://en.wikipedia.org/wiki/ro:Olteni%C5%A3a" class="extiw" title="wikipedia:ro:Olteniţa">Wikipedia:ro:Olteniţa</a></li>
 <li><a href="http://en.wikipedia.org/wiki/ro:Olteni%C5%A3a" class="extiw" title="wikipedia:ro:Olteniţa">Wikipedia:ro:Olteniţa</a></li>
 </ul>
+!! html/parsoid
+<ul>
+<li><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/ro:Olteniţa" title="wikipedia:ro:Olteniţa">Wikipedia:ro:Olteniţa</a></li>
+<li><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/ro:Olteniţa" title="wikipedia:ro:Olteniţa">Wikipedia:ro:Olteniţa</a></li>
+</ul>
 !! end
 
 !! test
@@ -9411,7 +9474,7 @@ Handling html with a div self-closing tag
 !! html/parsoid
 <div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
 <div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
-<div title="" data-parsoid='{"stx":"html","selfClose":true,"brokenHTMLTag":true}'></div>
+<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
 <div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div>
 <div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div>
 <div title="bar/" data-parsoid='{"stx":"html","autoInsertedEnd":true}'></div>
@@ -11324,6 +11387,15 @@ Templates with templated name
 <ul about="#mwt4" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|inner list}} ","href":"./Template:Inner_list"},"params":{},"i":0}}]}'><li> item 1</li></ul>
 !! end
 
+## Regression test; the output here isn't really that interesting.
+!! test
+Templates with templated name and top level template args
+!! wikitext
+{{1{{2{{{3}}}|4=5}}}}
+!! html/parsoid
+<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"1{{2{{{3}}}|4=5}}"},"params":{},"i":0}}]}'>{{1{{2{{{3}}}|4=5}}}}</p>
+!! end
+
 # Parsoid markup is deliberate "broken". This is an edge case.
 # See long comment in TemplateHandler.js:convertAttribsToString.
 !! test
@@ -14762,6 +14834,28 @@ Alt image option should handle most kinds of wikitext without barfing
 <figure class="mw-default-size" typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"This is the image caption"},{"ck":"alt","ak":"alt=This is a [[link]] and a {{echo|&#39;&#39;bold template&#39;&#39;}}."}]}' data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["alt",{"html":"alt=This is a &lt;a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid=&#39;{\"stx\":\"simple\",\"a\":{\"href\":\"./Link\"},\"sa\":{\"href\":\"link\"},\"dsr\":[65,73,2,2]}&#39;>link&lt;/a> and a &lt;i about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=&#39;{\"dsr\":[80,106,null,null],\"pi\":[[{\"k\":\"1\"}]]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&amp;#39;&amp;#39;bold template&amp;#39;&amp;#39;\"}},\"i\":0}}]}&#39;>bold template&lt;/i>."}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img alt="This is a link and a bold template." resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"alt":"This is a link and a bold template.","resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"alt":"alt=This is a [[link]] and a {{echo|&#39;&#39;bold template&#39;&#39;}}.","resource":"Image:Foobar.jpg"}}'/></a><figcaption>This is the image caption</figcaption></figure>
 !! end
 
+!! test
+Image with nested tables in caption
+!! wikitext
+[[File:Foobar.jpg|thumb|Foo<br />
+{|
+|
+{|
+|z
+|}
+|}
+]]
+!! html/parsoid
+<figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"Foo&lt;br/>\n{|\n|\n{|\n|z\n|}\n|}\n"}]}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption data-parsoid='{"dsr":[null,50,null,null]}'>Foo<br data-parsoid='{"stx":"html","selfClose":true}'/>
+<table>
+<tbody><tr><td>
+<table>
+<tbody><tr><td>z</td></tr>
+</tbody></table></td></tr>
+</tbody></table>
+</figcaption></figure>
+!! end
+
 ###################
 # Conflicting image format options.
 # First option specified should 'win'.
@@ -15615,9 +15709,9 @@ T93580: 2. <ref> inside inline images
 
 <references />
 !! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: &lt;ref>foo&lt;/ref>"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: &lt;span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid=&#39;{\"dsr\":[64,78,5,6]}&#39; data-mw=&#39;{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-1\"},\"attrs\":{}}&#39;>&lt;a href=\"./Main_Page#cite_note-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\">&lt;span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]&lt;/span>&lt;/a>&lt;/span>&lt;meta typeof=\"mw:Extension/ref/Marker\" about=\"#mwt2\" data-parsoid=&#39;{\"group\":\"\",\"name\":\"\",\"content\":\"foo\",\"hasRefInRef\":false,\"dsr\":[64,78,5,6]}&#39;/>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: &lt;ref>foo&lt;/ref>"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: &lt;span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid=&#39;{\"dsr\":[64,78,5,6]}&#39; data-mw=&#39;{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-1\"},\"attrs\":{}}&#39;>&lt;a href=\"./Main_Page#cite_note-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\">&lt;span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]&lt;/span>&lt;/a>&lt;/span>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{"href":"File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
 
-<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text" data-parsoid="{}">foo</span></li></ol>
+<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li></ol>
 !! end
 
 !! test
@@ -15627,9 +15721,9 @@ T93580: 3. Templated <ref> inside inline images
 
 <references />
 !! html/parsoid
-<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: {{echo|&lt;ref>{{echo|foo}}&lt;/ref>}}"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: &lt;span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Transclusion  mw:Extension/ref\" data-parsoid=&#39;{\"dsr\":[64,96,null,null],\"pi\":[[{\"k\":\"1\"}]]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&amp;lt;ref>{{echo|foo}}&amp;lt;/ref>\"}},\"i\":0}}]}&#39;>&lt;a href=\"./Main_Page#cite_note-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\">&lt;span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]&lt;/span>&lt;/a>&lt;/span>&lt;meta typeof=\"mw:Transclusion mw:Extension/ref/Marker\" about=\"#mwt2\" data-parsoid=&#39;{\"group\":\"\",\"name\":\"\",\"content\":\"foo\",\"hasRefInRef\":false,\"dsr\":[64,96,null,null],\"pi\":[[{\"k\":\"1\"}]]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&amp;lt;ref>{{echo|foo}}&amp;lt;/ref>\"}},\"i\":0}}]}&#39;/>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"caption","ak":"Undisplayed caption in inline image with ref: {{echo|&lt;ref>{{echo|foo}}&lt;/ref>}}"}]}' data-mw='{"caption":"Undisplayed caption in inline image with ref: &lt;span about=\"#mwt2\" class=\"mw-ref\" id=\"cite_ref-1\" rel=\"dc:references\" typeof=\"mw:Transclusion  mw:Extension/ref\" data-parsoid=&#39;{\"dsr\":[64,96,null,null],\"pi\":[[{\"k\":\"1\"}]]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"&amp;lt;ref>{{echo|foo}}&amp;lt;/ref>\"}},\"i\":0}}]}&#39;>&lt;a href=\"./Main_Page#cite_note-1\" style=\"counter-reset: mw-Ref 1;\" data-parsoid=\"{}\">&lt;span class=\"mw-reflink-text\" data-parsoid=\"{}\">[1]&lt;/span>&lt;/a>&lt;/span>"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{"href":"File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"1941"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p>
 
-<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text" data-parsoid="{}">foo</span></li></ol>
+<ol class="mw-references references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><a href="./Main_Page#cite_ref-1" rel="mw:referencedBy"><span class="mw-linkback-text">↑ </span></a> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li></ol>
 !! end
 
 ###
@@ -15817,7 +15911,7 @@ Link to category
 !! wikitext
 [[:Category:MediaWiki User's Guide]]
 !! html
-<p><a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User's Guide">Category:MediaWiki User's Guide</a>
+<p><a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User&#39;s Guide">Category:MediaWiki User's Guide</a>
 </p>
 !! end
 
@@ -16794,7 +16888,7 @@ section 5
 <h2><span class="mw-headline" id="text_.26_text">text &amp; text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: text &amp; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <p>section 3
 </p>
-<h2><span class="mw-headline" id="text_.27_text">text ' text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text ' text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id="text_.27_text">text ' text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text &#039; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <p>section 4
 </p>
 <h2><span class="mw-headline" id="text_.22_text">text " text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: text &quot; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
@@ -18272,18 +18366,16 @@ Nested template calls
 ### Sanitizer
 ###
 
-# HTML+Tidy effectively strips out the empty tags completely
-# But since Parsoid doesn't it wraps the <s></s> tags in p-tags
-# which Tidy would have done for the PHP parser had there been content inside it.
+# HTML+Tidy strips out empty tags completely. Parsoid doesn't.
+# FIXME: Wikitext for this first test doesn't match its title.
 !! test
 Sanitizer: Closing of open tags
 !! wikitext
 <s></s><table></table>
-!! html
-<s></s><table></table>
+!! html/php+tidy
 
 !! html/parsoid
-<p><s></s></p><table></table>
+<s></s><table></table>
 !! end
 
 !! test
@@ -19993,7 +20085,7 @@ parsoid=wt2html
 '''''
 !! html/php
 !! html/parsoid
-<p><b><i></i></b></p>
+<b><i></i></b>
 !! end
 
 # same html as previous, but wikitext adjusted to match parsoid html2wt
@@ -22298,7 +22390,7 @@ parsoid={
 |}
 !! end
 
-# Tests LanguageVariantText._fromSelser
+# Tests LanguageVariantText._fromSelSer
 !! test
 LanguageConverter selser (4)
 !! options
@@ -22672,6 +22764,21 @@ a:b=>c xyz
 </p>
 !! end
 
+!! test
+T179579: Nowiki and lc interaction
+!! options
+parsoid=wt2html
+language=sr
+!! wikitext
+-{</nowiki>123}-
+
+-{123<nowiki>|</nowiki>456}-
+!! html/parsoid
+<p><span typeof="mw:LanguageVariant" data-mw-variant='{"disabled":{"t":"&amp;lt;/nowiki>123"}}' data-parsoid='{"fl":[],"src":"-{&lt;/nowiki>123}-"}'></span></p>
+
+<p><span typeof="mw:LanguageVariant" data-mw-variant='{"disabled":{"t":"123&lt;span typeof=\"mw:Nowiki\" data-parsoid=&#39;{\"dsr\":[23,41,8,9]}&#39;>|&lt;/span>456"}}' data-parsoid='{"fl":[],"src":"-{123&lt;nowiki>|&lt;/nowiki>456}-"}'></span></p>
+!! end
+
 !! test
 T2529: Uncovered bullet
 !! wikitext
@@ -24448,9 +24555,7 @@ parsoid=wt2html,wt2wt
 !! wikitext
 '''<small>[[Image:Foobar.jpg|right|300px]]</small>'''
 !! html/parsoid
-<p><b><small></small></b></p>
-<figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a></figure>
-<p></p>
+<b><small><figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a></figure></small></b>
 !! end
 
 #### ----------------------------------------------------------------
@@ -29427,7 +29532,7 @@ wgFragmentMode=[ 'html5', 'legacy' ]
 <li class="toclevel-1 tocsection-3"><a href="#Тест"><span class="tocnumber">3</span> <span class="toctext">Тест</span></a></li>
 <li class="toclevel-1 tocsection-4"><a href="#Тест_2"><span class="tocnumber">4</span> <span class="toctext">Тест</span></a></li>
 <li class="toclevel-1 tocsection-5"><a href="#тест"><span class="tocnumber">5</span> <span class="toctext">тест</span></a></li>
-<li class="toclevel-1 tocsection-6"><a href="#Hey_&lt;_#_&quot;_&gt;_%_:_'"><span class="tocnumber">6</span> <span class="toctext">Hey &lt; # " &gt;&#160;%&#160;: '</span></a></li>
+<li class="toclevel-1 tocsection-6"><a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;"><span class="tocnumber">6</span> <span class="toctext">Hey &lt; # " &gt;&#160;%&#160;: '</span></a></li>
 </ul>
 </div>
 
@@ -29436,8 +29541,8 @@ wgFragmentMode=[ 'html5', 'legacy' ]
 <h2><span id=".D0.A2.D0.B5.D1.81.D1.82"></span><span class="mw-headline" id="Тест">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span id=".D0.A2.D0.B5.D1.81.D1.82_2"></span><span class="mw-headline" id="Тест_2">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span id=".D1.82.D0.B5.D1.81.D1.82"></span><span class="mw-headline" id="тест">тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<h2><span id="Hey_.3C_.23_.22_.3E_.25_:_.27"></span><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : '">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_'">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
+<h2><span id="Hey_.3C_.23_.22_.3E_.25_:_.27"></span><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
 </p><p>💩 <span id="💩"></span>
 </p><p><a href="#啤酒">#啤酒</a> <a href="#啤酒">#啤酒</a>
 </p>
@@ -29483,7 +29588,7 @@ wgFragmentMode=[ 'legacy', 'html5' ]
 <h2><span id="Тест"></span><span class="mw-headline" id=".D0.A2.D0.B5.D1.81.D1.82">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span id="Тест_2"></span><span class="mw-headline" id=".D0.A2.D0.B5.D1.81.D1.82_2">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span id="тест"></span><span class="mw-headline" id=".D1.82.D0.B5.D1.81.D1.82">тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<h2><span id="Hey_&lt;_#_&quot;_&gt;_%_:_'"></span><span class="mw-headline" id="Hey_.3C_.23_.22_.3E_.25_:_.27">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : '">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span id="Hey_&lt;_#_&quot;_&gt;_%_:_'"></span><span class="mw-headline" id="Hey_.3C_.23_.22_.3E_.25_:_.27">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#.D0.A2.D0.B5.D1.81.D1.82">#Тест</a> <a href="#.D1.82.D0.B5.D1.81.D1.82">#тест</a> <a href="#Hey_.3C_.23_.22_.3E_.25_:_.27">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
 </p><p>.F0.9F.92.A9 <span id=".F0.9F.92.A9"></span>
 </p><p><a href="#.E5.95.A4.E9.85.92">#啤酒</a> <a href="#.E5.95.A4.E9.85.92">#啤酒</a>
@@ -29521,7 +29626,7 @@ wgFragmentMode=[ 'html5' ]
 <li class="toclevel-1 tocsection-3"><a href="#Тест"><span class="tocnumber">3</span> <span class="toctext">Тест</span></a></li>
 <li class="toclevel-1 tocsection-4"><a href="#Тест_2"><span class="tocnumber">4</span> <span class="toctext">Тест</span></a></li>
 <li class="toclevel-1 tocsection-5"><a href="#тест"><span class="tocnumber">5</span> <span class="toctext">тест</span></a></li>
-<li class="toclevel-1 tocsection-6"><a href="#Hey_&lt;_#_&quot;_&gt;_%_:_'"><span class="tocnumber">6</span> <span class="toctext">Hey &lt; # " &gt;&#160;%&#160;: '</span></a></li>
+<li class="toclevel-1 tocsection-6"><a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;"><span class="tocnumber">6</span> <span class="toctext">Hey &lt; # " &gt;&#160;%&#160;: '</span></a></li>
 </ul>
 </div>
 
@@ -29530,8 +29635,8 @@ wgFragmentMode=[ 'html5' ]
 <h2><span class="mw-headline" id="Тест">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span class="mw-headline" id="Тест_2">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <h2><span class="mw-headline" id="тест">тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<h2><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : '">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_'">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
+<h2><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
 </p><p>💩 <span id="💩"></span>
 </p><p><a href="#啤酒">#啤酒</a> <a href="#啤酒">#啤酒</a>
 </p>
index 106ab68..6f09d4c 100644 (file)
@@ -38,16 +38,13 @@ $maintenance->setup();
 // to $maintenance->mSelf. Keep that here for b/c
 $self = $maintenance->getName();
 global $IP;
-# Start the autoloader, so that extensions can derive classes from core files
-require_once "$IP/includes/AutoLoader.php";
-# Grab profiling functions
-require_once "$IP/includes/profiler/ProfilerFunctions.php";
-
-# Start the profiler
+# Get profiler configuraton
 $wgProfiler = [];
 if ( file_exists( "$IP/StartProfiler.php" ) ) {
        require "$IP/StartProfiler.php";
 }
+# Start the autoloader, so that extensions can derive classes from core files
+require_once "$IP/includes/AutoLoader.php";
 
 $requireOnceGlobalsScope = function ( $file ) use ( $self ) {
        foreach ( array_keys( $GLOBALS ) as $varName ) {
diff --git a/tests/phpunit/includes/RevisionContentHandlerDbTest.php b/tests/phpunit/includes/RevisionContentHandlerDbTest.php
new file mode 100644 (file)
index 0000000..fa0153d
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @group Database
+ * @group medium
+ * @group ContentHandler
+ */
+class RevisionContentHandlerDbTest extends RevisionDbTestBase {
+
+       protected function getContentHandlerUseDB() {
+               return true;
+       }
+
+}
diff --git a/tests/phpunit/includes/RevisionDbTestBase.php b/tests/phpunit/includes/RevisionDbTestBase.php
new file mode 100644 (file)
index 0000000..73559f3
--- /dev/null
@@ -0,0 +1,1225 @@
+<?php
+
+/**
+ * RevisionDbTestBase contains test cases for the Revision class that have Database interactions.
+ *
+ * @group Database
+ * @group medium
+ */
+abstract class RevisionDbTestBase extends MediaWikiTestCase {
+
+       /**
+        * @var WikiPage $testPage
+        */
+       private $testPage;
+
+       public function __construct( $name = null, array $data = [], $dataName = '' ) {
+               parent::__construct( $name, $data, $dataName );
+
+               $this->tablesUsed = array_merge( $this->tablesUsed,
+                       [
+                               'page',
+                               'revision',
+                               'ip_changes',
+                               'text',
+                               'archive',
+
+                               'recentchanges',
+                               'logging',
+
+                               'page_props',
+                               'pagelinks',
+                               'categorylinks',
+                               'langlinks',
+                               'externallinks',
+                               'imagelinks',
+                               'templatelinks',
+                               'iwlinks'
+                       ]
+               );
+       }
+
+       protected function setUp() {
+               global $wgContLang;
+
+               parent::setUp();
+
+               $this->mergeMwGlobalArrayValue(
+                       'wgExtraNamespaces',
+                       [
+                               12312 => 'Dummy',
+                               12313 => 'Dummy_talk',
+                       ]
+               );
+
+               $this->mergeMwGlobalArrayValue(
+                       'wgNamespaceContentModels',
+                       [
+                               12312 => DummyContentForTesting::MODEL_ID,
+                       ]
+               );
+
+               $this->mergeMwGlobalArrayValue(
+                       'wgContentHandlers',
+                       [
+                               DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting',
+                               RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler',
+                       ]
+               );
+
+               $this->setMwGlobals( 'wgContentHandlerUseDB', $this->getContentHandlerUseDB() );
+
+               MWNamespace::clearCaches();
+               // Reset namespace cache
+               $wgContLang->resetNamespaces();
+               if ( !$this->testPage ) {
+                       /**
+                        * We have to create a new page for each subclass as the page creation may result
+                        * in different DB fields being filled based on configuration.
+                        */
+                       $this->testPage = $this->createPage( __CLASS__, __CLASS__ );
+               }
+       }
+
+       protected function tearDown() {
+               global $wgContLang;
+
+               parent::tearDown();
+
+               MWNamespace::clearCaches();
+               // Reset namespace cache
+               $wgContLang->resetNamespaces();
+       }
+
+       abstract protected function getContentHandlerUseDB();
+
+       private function makeRevisionWithProps( $props = null ) {
+               if ( $props === null ) {
+                       $props = [];
+               }
+
+               if ( !isset( $props['content'] ) && !isset( $props['text'] ) ) {
+                       $props['text'] = 'Lorem Ipsum';
+               }
+
+               if ( !isset( $props['comment'] ) ) {
+                       $props['comment'] = 'just a test';
+               }
+
+               if ( !isset( $props['page'] ) ) {
+                       $props['page'] = $this->testPage->getId();
+               }
+
+               $rev = new Revision( $props );
+
+               $dbw = wfGetDB( DB_MASTER );
+               $rev->insertOn( $dbw );
+
+               return $rev;
+       }
+
+       /**
+        * @param string $titleString
+        * @param string $text
+        * @param string|null $model
+        *
+        * @return WikiPage
+        */
+       private function createPage( $titleString, $text, $model = null ) {
+               if ( !preg_match( '/:/', $titleString ) &&
+                       ( $model === null || $model === CONTENT_MODEL_WIKITEXT )
+               ) {
+                       $ns = $this->getDefaultWikitextNS();
+                       $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString;
+               }
+
+               $title = Title::newFromText( $titleString );
+               $wikipage = new WikiPage( $title );
+
+               // Delete the article if it already exists
+               if ( $wikipage->exists() ) {
+                       $wikipage->doDeleteArticle( "done" );
+               }
+
+               $content = ContentHandler::makeContent( $text, $title, $model );
+               $wikipage->doEditContent( $content, __METHOD__, EDIT_NEW );
+
+               return $wikipage;
+       }
+
+       private function assertRevEquals( Revision $orig, Revision $rev = null ) {
+               $this->assertNotNull( $rev, 'missing revision' );
+
+               $this->assertEquals( $orig->getId(), $rev->getId() );
+               $this->assertEquals( $orig->getPage(), $rev->getPage() );
+               $this->assertEquals( $orig->getTimestamp(), $rev->getTimestamp() );
+               $this->assertEquals( $orig->getUser(), $rev->getUser() );
+               $this->assertEquals( $orig->getContentModel(), $rev->getContentModel() );
+               $this->assertEquals( $orig->getContentFormat(), $rev->getContentFormat() );
+               $this->assertEquals( $orig->getSha1(), $rev->getSha1() );
+       }
+
+       /**
+        * @covers Revision::insertOn
+        */
+       public function testInsertOn_success() {
+               $parentId = $this->testPage->getLatest();
+
+               // If an ExternalStore is set don't use it.
+               $this->setMwGlobals( 'wgDefaultExternalStore', false );
+
+               $rev = new Revision( [
+                       'page' => $this->testPage->getId(),
+                       'title' => $this->testPage->getTitle(),
+                       'text' => 'Revision Text',
+                       'comment' => 'Revision comment',
+               ] );
+
+               $revId = $rev->insertOn( wfGetDB( DB_MASTER ) );
+
+               $this->assertInternalType( 'integer', $revId );
+               $this->assertInternalType( 'integer', $rev->getTextId() );
+               $this->assertSame( $revId, $rev->getId() );
+
+               $this->assertSelect(
+                       'text',
+                       [ 'old_id', 'old_text' ],
+                       "old_id = {$rev->getTextId()}",
+                       [ [ strval( $rev->getTextId() ), 'Revision Text' ] ]
+               );
+               $this->assertSelect(
+                       'revision',
+                       [
+                               'rev_id',
+                               'rev_page',
+                               'rev_text_id',
+                               'rev_user',
+                               'rev_minor_edit',
+                               'rev_deleted',
+                               'rev_len',
+                               'rev_parent_id',
+                               'rev_sha1',
+                       ],
+                       "rev_id = {$rev->getId()}",
+                       [ [
+                               strval( $rev->getId() ),
+                               strval( $this->testPage->getId() ),
+                               strval( $rev->getTextId() ),
+                               '0',
+                               '0',
+                               '0',
+                               '13',
+                               strval( $parentId ),
+                               's0ngbdoxagreuf2vjtuxzwdz64n29xm',
+                       ] ]
+               );
+       }
+
+       /**
+        * @covers Revision::insertOn
+        */
+       public function testInsertOn_exceptionOnNoPage() {
+               // If an ExternalStore is set don't use it.
+               $this->setMwGlobals( 'wgDefaultExternalStore', false );
+               $this->setExpectedException(
+                       MWException::class,
+                       "Cannot insert revision: page ID must be nonzero"
+               );
+
+               $rev = new Revision( [] );
+
+               $rev->insertOn( wfGetDB( DB_MASTER ) );
+       }
+
+       /**
+        * @covers Revision::newFromTitle
+        */
+       public function testNewFromTitle_withoutId() {
+               $latestRevId = $this->testPage->getLatest();
+
+               $rev = Revision::newFromTitle( $this->testPage->getTitle() );
+
+               $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
+               $this->assertEquals( $latestRevId, $rev->getId() );
+       }
+
+       /**
+        * @covers Revision::newFromTitle
+        */
+       public function testNewFromTitle_withId() {
+               $latestRevId = $this->testPage->getLatest();
+
+               $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId );
+
+               $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
+               $this->assertEquals( $latestRevId, $rev->getId() );
+       }
+
+       /**
+        * @covers Revision::newFromTitle
+        */
+       public function testNewFromTitle_withBadId() {
+               $latestRevId = $this->testPage->getLatest();
+
+               $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId + 1 );
+
+               $this->assertNull( $rev );
+       }
+
+       /**
+        * @covers Revision::newFromRow
+        */
+       public function testNewFromRow() {
+               $orig = $this->makeRevisionWithProps();
+
+               $dbr = wfGetDB( DB_REPLICA );
+               $revQuery = Revision::getQueryInfo();
+               $res = $dbr->select( $revQuery['tables'], $revQuery['fields'], [ 'rev_id' => $orig->getId() ],
+                  __METHOD__, [], $revQuery['joins'] );
+               $this->assertTrue( is_object( $res ), 'query failed' );
+
+               $row = $res->fetchObject();
+               $res->free();
+
+               $rev = Revision::newFromRow( $row );
+
+               $this->assertRevEquals( $orig, $rev );
+       }
+
+       public function provideNewFromArchiveRow() {
+               yield [
+                       function ( $f ) {
+                               return $f;
+                       },
+               ];
+               yield [
+                       function ( $f ) {
+                               return $f + [ 'ar_namespace', 'ar_title' ];
+                       },
+               ];
+               yield [
+                       function ( $f ) {
+                               unset( $f['ar_text_id'] );
+                               return $f;
+                       },
+               ];
+       }
+
+       /**
+        * @dataProvider provideNewFromArchiveRow
+        * @covers Revision::newFromArchiveRow
+        */
+       public function testNewFromArchiveRow( $selectModifier ) {
+               $page = $this->createPage(
+                       'RevisionStorageTest_testNewFromArchiveRow',
+                       'Lorem Ipsum',
+                       CONTENT_MODEL_WIKITEXT
+               );
+               $orig = $page->getRevision();
+               $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
+
+               $dbr = wfGetDB( DB_REPLICA );
+               $arQuery = Revision::getArchiveQueryInfo();
+               $arQuery['fields'] = $selectModifier( $arQuery['fields'] );
+               $res = $dbr->select(
+                       $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
+                       __METHOD__, [], $arQuery['joins']
+               );
+               $this->assertTrue( is_object( $res ), 'query failed' );
+
+               $row = $res->fetchObject();
+               $res->free();
+
+               $rev = Revision::newFromArchiveRow( $row );
+
+               $this->assertRevEquals( $orig, $rev );
+       }
+
+       /**
+        * @covers Revision::newFromArchiveRow
+        */
+       public function testNewFromArchiveRowOverrides() {
+               $page = $this->createPage(
+                       'RevisionStorageTest_testNewFromArchiveRow',
+                       'Lorem Ipsum',
+                       CONTENT_MODEL_WIKITEXT
+               );
+               $orig = $page->getRevision();
+               $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
+
+               $dbr = wfGetDB( DB_REPLICA );
+               $arQuery = Revision::getArchiveQueryInfo();
+               $res = $dbr->select(
+                       $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
+                       __METHOD__, [], $arQuery['joins']
+               );
+               $this->assertTrue( is_object( $res ), 'query failed' );
+
+               $row = $res->fetchObject();
+               $res->free();
+
+               $rev = Revision::newFromArchiveRow( $row, [ 'comment' => 'SOMEOVERRIDE' ] );
+
+               $this->assertNotEquals( $orig->getComment(), $rev->getComment() );
+               $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() );
+       }
+
+       /**
+        * @covers Revision::newFromId
+        */
+       public function testNewFromId() {
+               $orig = $this->testPage->getRevision();
+               $rev = Revision::newFromId( $orig->getId() );
+               $this->assertRevEquals( $orig, $rev );
+       }
+
+       /**
+        * @covers Revision::newFromPageId
+        */
+       public function testNewFromPageId() {
+               $rev = Revision::newFromPageId( $this->testPage->getId() );
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       $rev
+               );
+       }
+
+       /**
+        * @covers Revision::newFromPageId
+        */
+       public function testNewFromPageIdWithLatestId() {
+               $rev = Revision::newFromPageId(
+                       $this->testPage->getId(),
+                       $this->testPage->getLatest()
+               );
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       $rev
+               );
+       }
+
+       /**
+        * @covers Revision::newFromPageId
+        */
+       public function testNewFromPageIdWithNotLatestId() {
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $rev = Revision::newFromPageId(
+                       $this->testPage->getId(),
+                       $this->testPage->getRevision()->getPrevious()->getId()
+               );
+               $this->assertRevEquals(
+                       $this->testPage->getRevision()->getPrevious(),
+                       $rev
+               );
+       }
+
+       /**
+        * @covers Revision::fetchRevision
+        */
+       public function testFetchRevision() {
+               // Hidden process cache assertion below
+               $this->testPage->getRevision()->getId();
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $id = $this->testPage->getRevision()->getId();
+
+               $res = Revision::fetchRevision( $this->testPage->getTitle() );
+
+               # note: order is unspecified
+               $rows = [];
+               while ( ( $row = $res->fetchObject() ) ) {
+                       $rows[$row->rev_id] = $row;
+               }
+
+               $this->assertEquals( 1, count( $rows ), 'expected exactly one revision' );
+               $this->assertArrayHasKey( $id, $rows, 'missing revision with id ' . $id );
+       }
+
+       /**
+        * @covers Revision::getPage
+        */
+       public function testGetPage() {
+               $page = $this->testPage;
+
+               $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] );
+               $rev = Revision::newFromId( $orig->getId() );
+
+               $this->assertEquals( $page->getId(), $rev->getPage() );
+       }
+
+       /**
+        * @covers Revision::isCurrent
+        */
+       public function testIsCurrent() {
+               $rev1 = $this->testPage->getRevision();
+
+               # @todo find out if this should be true
+               # $this->assertTrue( $rev1->isCurrent() );
+
+               $rev1x = Revision::newFromId( $rev1->getId() );
+               $this->assertTrue( $rev1x->isCurrent() );
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $rev2 = $this->testPage->getRevision();
+
+               # @todo find out if this should be true
+               # $this->assertTrue( $rev2->isCurrent() );
+
+               $rev1x = Revision::newFromId( $rev1->getId() );
+               $this->assertFalse( $rev1x->isCurrent() );
+
+               $rev2x = Revision::newFromId( $rev2->getId() );
+               $this->assertTrue( $rev2x->isCurrent() );
+       }
+
+       /**
+        * @covers Revision::getPrevious
+        */
+       public function testGetPrevious() {
+               $oldestRevision = $this->testPage->getOldestRevision();
+               $latestRevision = $this->testPage->getLatest();
+
+               $this->assertNull( $oldestRevision->getPrevious() );
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $newRevision = $this->testPage->getRevision();
+
+               $this->assertNotNull( $newRevision->getPrevious() );
+               $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() );
+       }
+
+       /**
+        * @covers Revision::getNext
+        */
+       public function testGetNext() {
+               $rev1 = $this->testPage->getRevision();
+
+               $this->assertNull( $rev1->getNext() );
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $rev2 = $this->testPage->getRevision();
+
+               $this->assertNotNull( $rev1->getNext() );
+               $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() );
+       }
+
+       /**
+        * @covers Revision::newNullRevision
+        */
+       public function testNewNullRevision() {
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $orig = $this->testPage->getRevision();
+
+               $dbw = wfGetDB( DB_MASTER );
+               $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false );
+
+               $this->assertNotEquals( $orig->getId(), $rev->getId(),
+                       'new null revision should have a different id from the original revision' );
+               $this->assertEquals( $orig->getTextId(), $rev->getTextId(),
+                       'new null revision should have the same text id as the original revision' );
+               $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() );
+       }
+
+       /**
+        * @covers Revision::insertOn
+        */
+       public function testInsertOn() {
+               $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7';
+
+               $orig = $this->makeRevisionWithProps( [
+                       'user_text' => $ip
+               ] );
+
+               // Make sure the revision was copied to ip_changes
+               $dbr = wfGetDB( DB_REPLICA );
+               $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] );
+               $row = $res->fetchObject();
+
+               $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex );
+               $this->assertEquals( $orig->getTimestamp(), $row->ipc_rev_timestamp );
+       }
+
+       public static function provideUserWasLastToEdit() {
+               yield 'actually the last edit' => [ 3, true ];
+               yield 'not the current edit, but still by this user' => [ 2, true ];
+               yield 'edit by another user' => [ 1, false ];
+               yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ];
+       }
+
+       /**
+        * @dataProvider provideUserWasLastToEdit
+        */
+       public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) {
+               $userA = User::newFromName( "RevisionStorageTest_userA" );
+               $userB = User::newFromName( "RevisionStorageTest_userB" );
+
+               if ( $userA->getId() === 0 ) {
+                       $userA = User::createNew( $userA->getName() );
+               }
+
+               if ( $userB->getId() === 0 ) {
+                       $userB = User::createNew( $userB->getName() );
+               }
+
+               $ns = $this->getDefaultWikitextNS();
+
+               $dbw = wfGetDB( DB_MASTER );
+               $revisions = [];
+
+               // create revisions -----------------------------
+               $page = WikiPage::factory( Title::newFromText(
+                       'RevisionStorageTest_testUserWasLastToEdit', $ns ) );
+               $page->insertOn( $dbw );
+
+               $revisions[0] = new Revision( [
+                       'page' => $page->getId(),
+                       // we need the title to determine the page's default content model
+                       'title' => $page->getTitle(),
+                       'timestamp' => '20120101000000',
+                       'user' => $userA->getId(),
+                       'text' => 'zero',
+                       'content_model' => CONTENT_MODEL_WIKITEXT,
+                       'summary' => 'edit zero'
+               ] );
+               $revisions[0]->insertOn( $dbw );
+
+               $revisions[1] = new Revision( [
+                       'page' => $page->getId(),
+                       // still need the title, because $page->getId() is 0 (there's no entry in the page table)
+                       'title' => $page->getTitle(),
+                       'timestamp' => '20120101000100',
+                       'user' => $userA->getId(),
+                       'text' => 'one',
+                       'content_model' => CONTENT_MODEL_WIKITEXT,
+                       'summary' => 'edit one'
+               ] );
+               $revisions[1]->insertOn( $dbw );
+
+               $revisions[2] = new Revision( [
+                       'page' => $page->getId(),
+                       'title' => $page->getTitle(),
+                       'timestamp' => '20120101000200',
+                       'user' => $userB->getId(),
+                       'text' => 'two',
+                       'content_model' => CONTENT_MODEL_WIKITEXT,
+                       'summary' => 'edit two'
+               ] );
+               $revisions[2]->insertOn( $dbw );
+
+               $revisions[3] = new Revision( [
+                       'page' => $page->getId(),
+                       'title' => $page->getTitle(),
+                       'timestamp' => '20120101000300',
+                       'user' => $userA->getId(),
+                       'text' => 'three',
+                       'content_model' => CONTENT_MODEL_WIKITEXT,
+                       'summary' => 'edit three'
+               ] );
+               $revisions[3]->insertOn( $dbw );
+
+               $revisions[4] = new Revision( [
+                       'page' => $page->getId(),
+                       'title' => $page->getTitle(),
+                       'timestamp' => '20120101000200',
+                       'user' => $userA->getId(),
+                       'text' => 'zero',
+                       'content_model' => CONTENT_MODEL_WIKITEXT,
+                       'summary' => 'edit four'
+               ] );
+               $revisions[4]->insertOn( $dbw );
+
+               // test it ---------------------------------
+               $since = $revisions[$sinceIdx]->getTimestamp();
+
+               $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since );
+
+               $this->assertEquals( $expectedLast, $wasLast );
+       }
+
+       /**
+        * @param string $text
+        * @param string $title
+        * @param string $model
+        * @param string $format
+        *
+        * @return Revision
+        */
+       private function newTestRevision( $text, $title = "Test",
+               $model = CONTENT_MODEL_WIKITEXT, $format = null
+       ) {
+               if ( is_string( $title ) ) {
+                       $title = Title::newFromText( $title );
+               }
+
+               $content = ContentHandler::makeContent( $text, $title, $model, $format );
+
+               $rev = new Revision(
+                       [
+                               'id' => 42,
+                               'page' => 23,
+                               'title' => $title,
+
+                               'content' => $content,
+                               'length' => $content->getSize(),
+                               'comment' => "testing",
+                               'minor_edit' => false,
+
+                               'content_format' => $format,
+                       ]
+               );
+
+               return $rev;
+       }
+
+       public function provideGetContentModel() {
+               // NOTE: we expect the help namespace to always contain wikitext
+               return [
+                       [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ],
+                       [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ],
+                       [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetContentModel
+        * @covers Revision::getContentModel
+        */
+       public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) {
+               $rev = $this->newTestRevision( $text, $title, $model, $format );
+
+               $this->assertEquals( $expectedModel, $rev->getContentModel() );
+       }
+
+       public function provideGetContentFormat() {
+               // NOTE: we expect the help namespace to always contain wikitext
+               return [
+                       [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ],
+                       [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ],
+                       [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ],
+                       [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetContentFormat
+        * @covers Revision::getContentFormat
+        */
+       public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) {
+               $rev = $this->newTestRevision( $text, $title, $model, $format );
+
+               $this->assertEquals( $expectedFormat, $rev->getContentFormat() );
+       }
+
+       public function provideGetContentHandler() {
+               // NOTE: we expect the help namespace to always contain wikitext
+               return [
+                       [ 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ],
+                       [ 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ],
+                       [ serialize( 'hello world' ), 'Dummy:Hello', null, null, 'DummyContentHandlerForTesting' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetContentHandler
+        * @covers Revision::getContentHandler
+        */
+       public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) {
+               $rev = $this->newTestRevision( $text, $title, $model, $format );
+
+               $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) );
+       }
+
+       public function provideGetContent() {
+               // NOTE: we expect the help namespace to always contain wikitext
+               return [
+                       [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ],
+                       [
+                               serialize( 'hello world' ),
+                               'Hello',
+                               DummyContentForTesting::MODEL_ID,
+                               null,
+                               Revision::FOR_PUBLIC,
+                               serialize( 'hello world' )
+                       ],
+                       [
+                               serialize( 'hello world' ),
+                               'Dummy:Hello',
+                               null,
+                               null,
+                               Revision::FOR_PUBLIC,
+                               serialize( 'hello world' )
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetContent
+        * @covers Revision::getContent
+        */
+       public function testGetContent( $text, $title, $model, $format,
+               $audience, $expectedSerialization
+       ) {
+               $rev = $this->newTestRevision( $text, $title, $model, $format );
+               $content = $rev->getContent( $audience );
+
+               $this->assertEquals(
+                       $expectedSerialization,
+                       is_null( $content ) ? null : $content->serialize( $format )
+               );
+       }
+
+       /**
+        * @covers Revision::getContent
+        */
+       public function testGetContent_failure() {
+               $rev = new Revision( [
+                       'page' => $this->testPage->getId(),
+                       'content_model' => $this->testPage->getContentModel(),
+                       'text_id' => 123456789, // not in the test DB
+               ] );
+
+               $this->assertNull( $rev->getContent(),
+                       "getContent() should return null if the revision's text blob could not be loaded." );
+
+               // NOTE: check this twice, once for lazy initialization, and once with the cached value.
+               $this->assertNull( $rev->getContent(),
+                       "getContent() should return null if the revision's text blob could not be loaded." );
+       }
+
+       public function provideGetSize() {
+               return [
+                       [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ],
+                       [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ],
+               ];
+       }
+
+       /**
+        * @covers Revision::getSize
+        * @dataProvider provideGetSize
+        */
+       public function testGetSize( $text, $model, $expected_size ) {
+               $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model );
+               $this->assertEquals( $expected_size, $rev->getSize() );
+       }
+
+       public function provideGetSha1() {
+               return [
+                       [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ],
+                       [
+                               serialize( "hello world." ),
+                               DummyContentForTesting::MODEL_ID,
+                               Revision::base36Sha1( serialize( "hello world." ) )
+                       ],
+               ];
+       }
+
+       /**
+        * @covers Revision::getSha1
+        * @dataProvider provideGetSha1
+        */
+       public function testGetSha1( $text, $model, $expected_hash ) {
+               $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model );
+               $this->assertEquals( $expected_hash, $rev->getSha1() );
+       }
+
+       /**
+        * Tests whether $rev->getContent() returns a clone when needed.
+        *
+        * @covers Revision::getContent
+        */
+       public function testGetContentClone() {
+               $content = new RevisionTestModifyableContent( "foo" );
+
+               $rev = new Revision(
+                       [
+                               'id' => 42,
+                               'page' => 23,
+                               'title' => Title::newFromText( "testGetContentClone_dummy" ),
+
+                               'content' => $content,
+                               'length' => $content->getSize(),
+                               'comment' => "testing",
+                               'minor_edit' => false,
+                       ]
+               );
+
+               /** @var RevisionTestModifyableContent $content */
+               $content = $rev->getContent( Revision::RAW );
+               $content->setText( "bar" );
+
+               /** @var RevisionTestModifyableContent $content2 */
+               $content2 = $rev->getContent( Revision::RAW );
+               // content is mutable, expect clone
+               $this->assertNotSame( $content, $content2, "expected a clone" );
+               // clone should contain the original text
+               $this->assertEquals( "foo", $content2->getText() );
+
+               $content2->setText( "bla bla" );
+               // clones should be independent
+               $this->assertEquals( "bar", $content->getText() );
+       }
+
+       /**
+        * Tests whether $rev->getContent() returns the same object repeatedly if appropriate.
+        * @covers Revision::getContent
+        */
+       public function testGetContentUncloned() {
+               $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT );
+               $content = $rev->getContent( Revision::RAW );
+               $content2 = $rev->getContent( Revision::RAW );
+
+               // for immutable content like wikitext, this should be the same object
+               $this->assertSame( $content, $content2 );
+       }
+
+       /**
+        * @covers Revision::loadFromId
+        */
+       public function testLoadFromId() {
+               $rev = $this->testPage->getRevision();
+               $this->assertRevEquals(
+                       $rev,
+                       Revision::loadFromId( wfGetDB( DB_MASTER ), $rev->getId() )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromPageId
+        */
+       public function testLoadFromPageId() {
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromPageId
+        */
+       public function testLoadFromPageIdWithLatestRevId() {
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       Revision::loadFromPageId(
+                               wfGetDB( DB_MASTER ),
+                               $this->testPage->getId(),
+                               $this->testPage->getLatest()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromPageId
+        */
+       public function testLoadFromPageIdWithNotLatestRevId() {
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $this->assertRevEquals(
+                       $this->testPage->getRevision()->getPrevious(),
+                       Revision::loadFromPageId(
+                               wfGetDB( DB_MASTER ),
+                               $this->testPage->getId(),
+                               $this->testPage->getRevision()->getPrevious()->getId()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromTitle
+        */
+       public function testLoadFromTitle() {
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromTitle
+        */
+       public function testLoadFromTitleWithLatestRevId() {
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       Revision::loadFromTitle(
+                               wfGetDB( DB_MASTER ),
+                               $this->testPage->getTitle(),
+                               $this->testPage->getLatest()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromTitle
+        */
+       public function testLoadFromTitleWithNotLatestRevId() {
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $this->assertRevEquals(
+                       $this->testPage->getRevision()->getPrevious(),
+                       Revision::loadFromTitle(
+                               wfGetDB( DB_MASTER ),
+                               $this->testPage->getTitle(),
+                               $this->testPage->getRevision()->getPrevious()->getId()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::loadFromTimestamp()
+        */
+       public function testLoadFromTimestamp() {
+               $this->assertRevEquals(
+                       $this->testPage->getRevision(),
+                       Revision::loadFromTimestamp(
+                               wfGetDB( DB_MASTER ),
+                               $this->testPage->getTitle(),
+                               $this->testPage->getRevision()->getTimestamp()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::getParentLengths
+        */
+       public function testGetParentLengths_noRevIds() {
+               $this->assertSame(
+                       [],
+                       Revision::getParentLengths(
+                               wfGetDB( DB_MASTER ),
+                               []
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::getParentLengths
+        */
+       public function testGetParentLengths_oneRevId() {
+               $text = '831jr091jr0921kr21kr0921kjr0921j09rj1';
+               $textLength = strlen( $text );
+
+               $this->testPage->doEditContent( new WikitextContent( $text ), __METHOD__ );
+               $rev[1] = $this->testPage->getLatest();
+
+               $this->assertSame(
+                       [ $rev[1] => strval( $textLength ) ],
+                       Revision::getParentLengths(
+                               wfGetDB( DB_MASTER ),
+                               [ $rev[1] ]
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::getParentLengths
+        */
+       public function testGetParentLengths_multipleRevIds() {
+               $textOne = '831jr091jr0921kr21kr0921kjr0921j09rj1';
+               $textOneLength = strlen( $textOne );
+               $textTwo = '831jr091jr092121j09rj1';
+               $textTwoLength = strlen( $textTwo );
+
+               $this->testPage->doEditContent( new WikitextContent( $textOne ), __METHOD__ );
+               $rev[1] = $this->testPage->getLatest();
+               $this->testPage->doEditContent( new WikitextContent( $textTwo ), __METHOD__ );
+               $rev[2] = $this->testPage->getLatest();
+
+               $this->assertSame(
+                       [ $rev[1] => strval( $textOneLength ), $rev[2] => strval( $textTwoLength ) ],
+                       Revision::getParentLengths(
+                               wfGetDB( DB_MASTER ),
+                               [ $rev[1], $rev[2] ]
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::getTitle
+        */
+       public function testGetTitle_fromExistingRevision() {
+               $this->assertTrue(
+                       $this->testPage->getTitle()->equals(
+                               $this->testPage->getRevision()->getTitle()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::getTitle
+        */
+       public function testGetTitle_fromRevisionWhichWillLoadTheTitle() {
+               $rev = new Revision( [ 'id' => $this->testPage->getLatest() ] );
+               $this->assertTrue(
+                       $this->testPage->getTitle()->equals(
+                               $rev->getTitle()
+                       )
+               );
+       }
+
+       /**
+        * @covers Revision::getTitle
+        */
+       public function testGetTitle_forBadRevision() {
+               $rev = new Revision( [] );
+               $this->assertNull( $rev->getTitle() );
+       }
+
+       /**
+        * @covers Revision::isMinor
+        */
+       public function testIsMinor_true() {
+               // Use a sysop to ensure we can mark edits as minor
+               $sysop = $this->getTestSysop()->getUser();
+
+               $this->testPage->doEditContent(
+                       new WikitextContent( __METHOD__ ),
+                       __METHOD__,
+                       EDIT_MINOR,
+                       false,
+                       $sysop
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( true, $rev->isMinor() );
+       }
+
+       /**
+        * @covers Revision::isMinor
+        */
+       public function testIsMinor_false() {
+               $this->testPage->doEditContent(
+                       new WikitextContent( __METHOD__ ),
+                       __METHOD__,
+                       0
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( false, $rev->isMinor() );
+       }
+
+       /**
+        * @covers Revision::getTimestamp
+        */
+       public function testGetTimestamp() {
+               $testTimestamp = wfTimestampNow();
+
+               $this->testPage->doEditContent(
+                       new WikitextContent( __METHOD__ ),
+                       __METHOD__
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertInternalType( 'string', $rev->getTimestamp() );
+               $this->assertTrue( strlen( $rev->getTimestamp() ) == strlen( 'YYYYMMDDHHMMSS' ) );
+               $this->assertContains( substr( $testTimestamp, 0, 10 ), $rev->getTimestamp() );
+       }
+
+       /**
+        * @covers Revision::getUser
+        * @covers Revision::getUserText
+        */
+       public function testGetUserAndText() {
+               $sysop = $this->getTestSysop()->getUser();
+
+               $this->testPage->doEditContent(
+                       new WikitextContent( __METHOD__ ),
+                       __METHOD__,
+                       0,
+                       false,
+                       $sysop
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( $sysop->getId(), $rev->getUser() );
+               $this->assertSame( $sysop->getName(), $rev->getUserText() );
+       }
+
+       /**
+        * @covers Revision::isDeleted
+        */
+       public function testIsDeleted_nothingDeleted() {
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
+               $this->assertSame( false, $rev->isDeleted( Revision::DELETED_COMMENT ) );
+               $this->assertSame( false, $rev->isDeleted( Revision::DELETED_RESTRICTED ) );
+               $this->assertSame( false, $rev->isDeleted( Revision::DELETED_USER ) );
+       }
+
+       /**
+        * @covers Revision::getVisibility
+        */
+       public function testGetVisibility_nothingDeleted() {
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( 0, $rev->getVisibility() );
+       }
+
+       /**
+        * @covers Revision::getComment
+        */
+       public function testGetComment_notDeleted() {
+               $expectedSummary = 'goatlicious summary';
+
+               $this->testPage->doEditContent(
+                       new WikitextContent( __METHOD__ ),
+                       $expectedSummary
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( $expectedSummary, $rev->getComment() );
+       }
+
+       /**
+        * @covers Revision::isUnpatrolled
+        */
+       public function testIsUnpatrolled_returnsRecentChangesId() {
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertGreaterThan( 0, $rev->isUnpatrolled() );
+               $this->assertSame( $rev->getRecentChange()->getAttribute( 'rc_id' ), $rev->isUnpatrolled() );
+       }
+
+       /**
+        * @covers Revision::isUnpatrolled
+        */
+       public function testIsUnpatrolled_returnsZeroIfPatrolled() {
+               // This assumes that sysops are auto patrolled
+               $sysop = $this->getTestSysop()->getUser();
+               $this->testPage->doEditContent(
+                       new WikitextContent( __METHOD__ ),
+                       __METHOD__,
+                       0,
+                       false,
+                       $sysop
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( 0, $rev->isUnpatrolled() );
+       }
+
+       /**
+        * This is a simple blanket test for all simple content getters and is methods to provide some
+        * coverage before the split of Revision into multiple classes for MCR work.
+        * @covers Revision::getContent
+        * @covers Revision::getSerializedData
+        * @covers Revision::getContentModel
+        * @covers Revision::getContentFormat
+        * @covers Revision::getContentHandler
+        */
+       public function testSimpleContentGetters() {
+               $expectedText = 'testSimpleContentGetters in Revision. Goats love MCR...';
+               $expectedSummary = 'goatlicious testSimpleContentGetters summary';
+
+               $this->testPage->doEditContent(
+                       new WikitextContent( $expectedText ),
+                       $expectedSummary
+               );
+               $rev = $this->testPage->getRevision();
+
+               $this->assertSame( $expectedText, $rev->getContent()->getNativeData() );
+               $this->assertSame( $expectedText, $rev->getSerializedData() );
+               $this->assertSame( $this->testPage->getContentModel(), $rev->getContentModel() );
+               $this->assertSame( $this->testPage->getContent()->getDefaultFormat(), $rev->getContentFormat() );
+               $this->assertSame( $this->testPage->getContentHandler(), $rev->getContentHandler() );
+       }
+
+}
diff --git a/tests/phpunit/includes/RevisionIntegrationTest.php b/tests/phpunit/includes/RevisionIntegrationTest.php
deleted file mode 100644 (file)
index 48e00e0..0000000
+++ /dev/null
@@ -1,1049 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- * @group Database
- *
- * @group medium
- */
-class RevisionIntegrationTest extends MediaWikiTestCase {
-
-       /**
-        * @var WikiPage $testPage
-        */
-       private $testPage;
-
-       public function __construct( $name = null, array $data = [], $dataName = '' ) {
-               parent::__construct( $name, $data, $dataName );
-
-               $this->tablesUsed = array_merge( $this->tablesUsed,
-                       [
-                               'page',
-                               'revision',
-                               'ip_changes',
-                               'text',
-                               'archive',
-
-                               'recentchanges',
-                               'logging',
-
-                               'page_props',
-                               'pagelinks',
-                               'categorylinks',
-                               'langlinks',
-                               'externallinks',
-                               'imagelinks',
-                               'templatelinks',
-                               'iwlinks'
-                       ]
-               );
-       }
-
-       protected function setUp() {
-               global $wgContLang;
-
-               parent::setUp();
-
-               $this->mergeMwGlobalArrayValue(
-                       'wgExtraNamespaces',
-                       [
-                               12312 => 'Dummy',
-                               12313 => 'Dummy_talk',
-                       ]
-               );
-
-               $this->mergeMwGlobalArrayValue(
-                       'wgNamespaceContentModels',
-                       [
-                               12312 => DummyContentForTesting::MODEL_ID,
-                       ]
-               );
-
-               $this->mergeMwGlobalArrayValue(
-                       'wgContentHandlers',
-                       [
-                               DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting',
-                               RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler',
-                       ]
-               );
-
-               MWNamespace::clearCaches();
-               // Reset namespace cache
-               $wgContLang->resetNamespaces();
-               if ( !$this->testPage ) {
-                       $this->testPage = WikiPage::factory( Title::newFromText( 'UTPage' ) );
-               }
-       }
-
-       protected function tearDown() {
-               global $wgContLang;
-
-               parent::tearDown();
-
-               MWNamespace::clearCaches();
-               // Reset namespace cache
-               $wgContLang->resetNamespaces();
-       }
-
-       private function makeRevisionWithProps( $props = null ) {
-               if ( $props === null ) {
-                       $props = [];
-               }
-
-               if ( !isset( $props['content'] ) && !isset( $props['text'] ) ) {
-                       $props['text'] = 'Lorem Ipsum';
-               }
-
-               if ( !isset( $props['comment'] ) ) {
-                       $props['comment'] = 'just a test';
-               }
-
-               if ( !isset( $props['page'] ) ) {
-                       $props['page'] = $this->testPage->getId();
-               }
-
-               $rev = new Revision( $props );
-
-               $dbw = wfGetDB( DB_MASTER );
-               $rev->insertOn( $dbw );
-
-               return $rev;
-       }
-
-       /**
-        * @param string $titleString
-        * @param string $text
-        * @param string|null $model
-        *
-        * @return WikiPage
-        */
-       private function createPage( $titleString, $text, $model = null ) {
-               if ( !preg_match( '/:/', $titleString ) &&
-                       ( $model === null || $model === CONTENT_MODEL_WIKITEXT )
-               ) {
-                       $ns = $this->getDefaultWikitextNS();
-                       $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString;
-               }
-
-               $title = Title::newFromText( $titleString );
-               $wikipage = new WikiPage( $title );
-
-               // Delete the article if it already exists
-               if ( $wikipage->exists() ) {
-                       $wikipage->doDeleteArticle( "done" );
-               }
-
-               $content = ContentHandler::makeContent( $text, $title, $model );
-               $wikipage->doEditContent( $content, __METHOD__, EDIT_NEW );
-
-               return $wikipage;
-       }
-
-       private function assertRevEquals( Revision $orig, Revision $rev = null ) {
-               $this->assertNotNull( $rev, 'missing revision' );
-
-               $this->assertEquals( $orig->getId(), $rev->getId() );
-               $this->assertEquals( $orig->getPage(), $rev->getPage() );
-               $this->assertEquals( $orig->getTimestamp(), $rev->getTimestamp() );
-               $this->assertEquals( $orig->getUser(), $rev->getUser() );
-               $this->assertEquals( $orig->getContentModel(), $rev->getContentModel() );
-               $this->assertEquals( $orig->getContentFormat(), $rev->getContentFormat() );
-               $this->assertEquals( $orig->getSha1(), $rev->getSha1() );
-       }
-
-       /**
-        * @covers Revision::insertOn
-        */
-       public function testInsertOn_success() {
-               $parentId = $this->testPage->getLatest();
-
-               // If an ExternalStore is set don't use it.
-               $this->setMwGlobals( 'wgDefaultExternalStore', false );
-
-               $rev = new Revision( [
-                       'page' => $this->testPage->getId(),
-                       'title' => $this->testPage->getTitle(),
-                       'text' => 'Revision Text',
-                       'comment' => 'Revision comment',
-               ] );
-
-               $revId = $rev->insertOn( wfGetDB( DB_MASTER ) );
-
-               $this->assertInternalType( 'integer', $revId );
-               $this->assertInternalType( 'integer', $rev->getTextId() );
-               $this->assertSame( $revId, $rev->getId() );
-
-               $this->assertSelect(
-                       'text',
-                       [ 'old_id', 'old_text' ],
-                       "old_id = {$rev->getTextId()}",
-                       [ [ strval( $rev->getTextId() ), 'Revision Text' ] ]
-               );
-               $this->assertSelect(
-                       'revision',
-                       [
-                               'rev_id',
-                               'rev_page',
-                               'rev_text_id',
-                               'rev_user',
-                               'rev_minor_edit',
-                               'rev_deleted',
-                               'rev_len',
-                               'rev_parent_id',
-                               'rev_sha1',
-                       ],
-                       "rev_id = {$rev->getId()}",
-                       [ [
-                               strval( $rev->getId() ),
-                               strval( $this->testPage->getId() ),
-                               strval( $rev->getTextId() ),
-                               '0',
-                               '0',
-                               '0',
-                               '13',
-                               strval( $parentId ),
-                               's0ngbdoxagreuf2vjtuxzwdz64n29xm',
-                       ] ]
-               );
-       }
-
-       /**
-        * @covers Revision::insertOn
-        */
-       public function testInsertOn_exceptionOnNoPage() {
-               // If an ExternalStore is set don't use it.
-               $this->setMwGlobals( 'wgDefaultExternalStore', false );
-               $this->setExpectedException(
-                       MWException::class,
-                       "Cannot insert revision: page ID must be nonzero"
-               );
-
-               $rev = new Revision( [] );
-
-               $rev->insertOn( wfGetDB( DB_MASTER ) );
-       }
-
-       /**
-        * @covers Revision::newFromTitle
-        */
-       public function testNewFromTitle_withoutId() {
-               $latestRevId = $this->testPage->getLatest();
-
-               $rev = Revision::newFromTitle( $this->testPage->getTitle() );
-
-               $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
-               $this->assertEquals( $latestRevId, $rev->getId() );
-       }
-
-       /**
-        * @covers Revision::newFromTitle
-        */
-       public function testNewFromTitle_withId() {
-               $latestRevId = $this->testPage->getLatest();
-
-               $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId );
-
-               $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
-               $this->assertEquals( $latestRevId, $rev->getId() );
-       }
-
-       /**
-        * @covers Revision::newFromTitle
-        */
-       public function testNewFromTitle_withBadId() {
-               $latestRevId = $this->testPage->getLatest();
-
-               $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId + 1 );
-
-               $this->assertNull( $rev );
-       }
-
-       /**
-        * @covers Revision::newFromRow
-        */
-       public function testNewFromRow() {
-               $orig = $this->makeRevisionWithProps();
-
-               $dbr = wfGetDB( DB_REPLICA );
-               $revQuery = Revision::getQueryInfo();
-               $res = $dbr->select( $revQuery['tables'], $revQuery['fields'], [ 'rev_id' => $orig->getId() ],
-                  __METHOD__, [], $revQuery['joins'] );
-               $this->assertTrue( is_object( $res ), 'query failed' );
-
-               $row = $res->fetchObject();
-               $res->free();
-
-               $rev = Revision::newFromRow( $row );
-
-               $this->assertRevEquals( $orig, $rev );
-       }
-
-       public function provideNewFromArchiveRow() {
-               yield [
-                       true,
-                       function ( $f ) {
-                               return $f;
-                       },
-               ];
-               yield [
-                       false,
-                       function ( $f ) {
-                               return $f;
-                       },
-               ];
-               yield [
-                       true,
-                       function ( $f ) {
-                               return $f + [ 'ar_namespace', 'ar_title' ];
-                       },
-               ];
-               yield [
-                       false,
-                       function ( $f ) {
-                               return $f + [ 'ar_namespace', 'ar_title' ];
-                       },
-               ];
-               yield [
-                       true,
-                       function ( $f ) {
-                               unset( $f['ar_text_id'] );
-                               return $f;
-                       },
-               ];
-               yield [
-                       false,
-                       function ( $f ) {
-                               unset( $f['ar_text_id'] );
-                               return $f;
-                       },
-               ];
-       }
-
-       /**
-        * @dataProvider provideNewFromArchiveRow
-        * @covers Revision::newFromArchiveRow
-        */
-       public function testNewFromArchiveRow( $contentHandlerUseDB, $selectModifier ) {
-               $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
-
-               $page = $this->createPage(
-                       'RevisionStorageTest_testNewFromArchiveRow',
-                       'Lorem Ipsum',
-                       CONTENT_MODEL_WIKITEXT
-               );
-               $orig = $page->getRevision();
-               $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
-
-               $dbr = wfGetDB( DB_REPLICA );
-               $arQuery = Revision::getArchiveQueryInfo();
-               $arQuery['fields'] = $selectModifier( $arQuery['fields'] );
-               $res = $dbr->select(
-                       $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
-                       __METHOD__, [], $arQuery['joins']
-               );
-               $this->assertTrue( is_object( $res ), 'query failed' );
-
-               $row = $res->fetchObject();
-               $res->free();
-
-               $rev = Revision::newFromArchiveRow( $row );
-
-               $this->assertRevEquals( $orig, $rev );
-       }
-
-       /**
-        * @covers Revision::newFromArchiveRow
-        */
-       public function testNewFromArchiveRowOverrides() {
-               $page = $this->createPage(
-                       'RevisionStorageTest_testNewFromArchiveRow',
-                       'Lorem Ipsum',
-                       CONTENT_MODEL_WIKITEXT
-               );
-               $orig = $page->getRevision();
-               $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
-
-               $dbr = wfGetDB( DB_REPLICA );
-               $arQuery = Revision::getArchiveQueryInfo();
-               $res = $dbr->select(
-                       $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
-                       __METHOD__, [], $arQuery['joins']
-               );
-               $this->assertTrue( is_object( $res ), 'query failed' );
-
-               $row = $res->fetchObject();
-               $res->free();
-
-               $rev = Revision::newFromArchiveRow( $row, [ 'comment' => 'SOMEOVERRIDE' ] );
-
-               $this->assertNotEquals( $orig->getComment(), $rev->getComment() );
-               $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() );
-       }
-
-       /**
-        * @covers Revision::newFromId
-        */
-       public function testNewFromId() {
-               $orig = $this->testPage->getRevision();
-               $rev = Revision::newFromId( $orig->getId() );
-               $this->assertRevEquals( $orig, $rev );
-       }
-
-       /**
-        * @covers Revision::newFromPageId
-        */
-       public function testNewFromPageId() {
-               $rev = Revision::newFromPageId( $this->testPage->getId() );
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       $rev
-               );
-       }
-
-       /**
-        * @covers Revision::newFromPageId
-        */
-       public function testNewFromPageIdWithLatestId() {
-               $rev = Revision::newFromPageId(
-                       $this->testPage->getId(),
-                       $this->testPage->getLatest()
-               );
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       $rev
-               );
-       }
-
-       /**
-        * @covers Revision::newFromPageId
-        */
-       public function testNewFromPageIdWithNotLatestId() {
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $rev = Revision::newFromPageId(
-                       $this->testPage->getId(),
-                       $this->testPage->getRevision()->getPrevious()->getId()
-               );
-               $this->assertRevEquals(
-                       $this->testPage->getRevision()->getPrevious(),
-                       $rev
-               );
-       }
-
-       /**
-        * @covers Revision::fetchRevision
-        */
-       public function testFetchRevision() {
-               // Hidden process cache assertion below
-               $this->testPage->getRevision()->getId();
-
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $id = $this->testPage->getRevision()->getId();
-
-               $res = Revision::fetchRevision( $this->testPage->getTitle() );
-
-               # note: order is unspecified
-               $rows = [];
-               while ( ( $row = $res->fetchObject() ) ) {
-                       $rows[$row->rev_id] = $row;
-               }
-
-               $this->assertEquals( 1, count( $rows ), 'expected exactly one revision' );
-               $this->assertArrayHasKey( $id, $rows, 'missing revision with id ' . $id );
-       }
-
-       /**
-        * @covers Revision::getPage
-        */
-       public function testGetPage() {
-               $page = $this->testPage;
-
-               $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] );
-               $rev = Revision::newFromId( $orig->getId() );
-
-               $this->assertEquals( $page->getId(), $rev->getPage() );
-       }
-
-       /**
-        * @covers Revision::isCurrent
-        */
-       public function testIsCurrent() {
-               $rev1 = $this->testPage->getRevision();
-
-               # @todo find out if this should be true
-               # $this->assertTrue( $rev1->isCurrent() );
-
-               $rev1x = Revision::newFromId( $rev1->getId() );
-               $this->assertTrue( $rev1x->isCurrent() );
-
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $rev2 = $this->testPage->getRevision();
-
-               # @todo find out if this should be true
-               # $this->assertTrue( $rev2->isCurrent() );
-
-               $rev1x = Revision::newFromId( $rev1->getId() );
-               $this->assertFalse( $rev1x->isCurrent() );
-
-               $rev2x = Revision::newFromId( $rev2->getId() );
-               $this->assertTrue( $rev2x->isCurrent() );
-       }
-
-       /**
-        * @covers Revision::getPrevious
-        */
-       public function testGetPrevious() {
-               $oldestRevision = $this->testPage->getOldestRevision();
-               $latestRevision = $this->testPage->getLatest();
-
-               $this->assertNull( $oldestRevision->getPrevious() );
-
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $newRevision = $this->testPage->getRevision();
-
-               $this->assertNotNull( $newRevision->getPrevious() );
-               $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() );
-       }
-
-       /**
-        * @covers Revision::getNext
-        */
-       public function testGetNext() {
-               $rev1 = $this->testPage->getRevision();
-
-               $this->assertNull( $rev1->getNext() );
-
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $rev2 = $this->testPage->getRevision();
-
-               $this->assertNotNull( $rev1->getNext() );
-               $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() );
-       }
-
-       /**
-        * @covers Revision::newNullRevision
-        */
-       public function testNewNullRevision() {
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $orig = $this->testPage->getRevision();
-
-               $dbw = wfGetDB( DB_MASTER );
-               $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false );
-
-               $this->assertNotEquals( $orig->getId(), $rev->getId(),
-                       'new null revision should have a different id from the original revision' );
-               $this->assertEquals( $orig->getTextId(), $rev->getTextId(),
-                       'new null revision should have the same text id as the original revision' );
-               $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() );
-       }
-
-       /**
-        * @covers Revision::insertOn
-        */
-       public function testInsertOn() {
-               $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7';
-
-               $orig = $this->makeRevisionWithProps( [
-                       'user_text' => $ip
-               ] );
-
-               // Make sure the revision was copied to ip_changes
-               $dbr = wfGetDB( DB_REPLICA );
-               $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] );
-               $row = $res->fetchObject();
-
-               $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex );
-               $this->assertEquals( $orig->getTimestamp(), $row->ipc_rev_timestamp );
-       }
-
-       public static function provideUserWasLastToEdit() {
-               yield 'actually the last edit' => [ 3, true ];
-               yield 'not the current edit, but still by this user' => [ 2, true ];
-               yield 'edit by another user' => [ 1, false ];
-               yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ];
-       }
-
-       /**
-        * @dataProvider provideUserWasLastToEdit
-        */
-       public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) {
-               $userA = User::newFromName( "RevisionStorageTest_userA" );
-               $userB = User::newFromName( "RevisionStorageTest_userB" );
-
-               if ( $userA->getId() === 0 ) {
-                       $userA = User::createNew( $userA->getName() );
-               }
-
-               if ( $userB->getId() === 0 ) {
-                       $userB = User::createNew( $userB->getName() );
-               }
-
-               $ns = $this->getDefaultWikitextNS();
-
-               $dbw = wfGetDB( DB_MASTER );
-               $revisions = [];
-
-               // create revisions -----------------------------
-               $page = WikiPage::factory( Title::newFromText(
-                       'RevisionStorageTest_testUserWasLastToEdit', $ns ) );
-               $page->insertOn( $dbw );
-
-               $revisions[0] = new Revision( [
-                       'page' => $page->getId(),
-                       // we need the title to determine the page's default content model
-                       'title' => $page->getTitle(),
-                       'timestamp' => '20120101000000',
-                       'user' => $userA->getId(),
-                       'text' => 'zero',
-                       'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit zero'
-               ] );
-               $revisions[0]->insertOn( $dbw );
-
-               $revisions[1] = new Revision( [
-                       'page' => $page->getId(),
-                       // still need the title, because $page->getId() is 0 (there's no entry in the page table)
-                       'title' => $page->getTitle(),
-                       'timestamp' => '20120101000100',
-                       'user' => $userA->getId(),
-                       'text' => 'one',
-                       'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit one'
-               ] );
-               $revisions[1]->insertOn( $dbw );
-
-               $revisions[2] = new Revision( [
-                       'page' => $page->getId(),
-                       'title' => $page->getTitle(),
-                       'timestamp' => '20120101000200',
-                       'user' => $userB->getId(),
-                       'text' => 'two',
-                       'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit two'
-               ] );
-               $revisions[2]->insertOn( $dbw );
-
-               $revisions[3] = new Revision( [
-                       'page' => $page->getId(),
-                       'title' => $page->getTitle(),
-                       'timestamp' => '20120101000300',
-                       'user' => $userA->getId(),
-                       'text' => 'three',
-                       'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit three'
-               ] );
-               $revisions[3]->insertOn( $dbw );
-
-               $revisions[4] = new Revision( [
-                       'page' => $page->getId(),
-                       'title' => $page->getTitle(),
-                       'timestamp' => '20120101000200',
-                       'user' => $userA->getId(),
-                       'text' => 'zero',
-                       'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit four'
-               ] );
-               $revisions[4]->insertOn( $dbw );
-
-               // test it ---------------------------------
-               $since = $revisions[$sinceIdx]->getTimestamp();
-
-               $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since );
-
-               $this->assertEquals( $expectedLast, $wasLast );
-       }
-
-       /**
-        * @param string $text
-        * @param string $title
-        * @param string $model
-        * @param string $format
-        *
-        * @return Revision
-        */
-       private function newTestRevision( $text, $title = "Test",
-               $model = CONTENT_MODEL_WIKITEXT, $format = null
-       ) {
-               if ( is_string( $title ) ) {
-                       $title = Title::newFromText( $title );
-               }
-
-               $content = ContentHandler::makeContent( $text, $title, $model, $format );
-
-               $rev = new Revision(
-                       [
-                               'id' => 42,
-                               'page' => 23,
-                               'title' => $title,
-
-                               'content' => $content,
-                               'length' => $content->getSize(),
-                               'comment' => "testing",
-                               'minor_edit' => false,
-
-                               'content_format' => $format,
-                       ]
-               );
-
-               return $rev;
-       }
-
-       public function provideGetContentModel() {
-               // NOTE: we expect the help namespace to always contain wikitext
-               return [
-                       [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ],
-                       [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ],
-                       [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetContentModel
-        * @covers Revision::getContentModel
-        */
-       public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) {
-               $rev = $this->newTestRevision( $text, $title, $model, $format );
-
-               $this->assertEquals( $expectedModel, $rev->getContentModel() );
-       }
-
-       public function provideGetContentFormat() {
-               // NOTE: we expect the help namespace to always contain wikitext
-               return [
-                       [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ],
-                       [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ],
-                       [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ],
-                       [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetContentFormat
-        * @covers Revision::getContentFormat
-        */
-       public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) {
-               $rev = $this->newTestRevision( $text, $title, $model, $format );
-
-               $this->assertEquals( $expectedFormat, $rev->getContentFormat() );
-       }
-
-       public function provideGetContentHandler() {
-               // NOTE: we expect the help namespace to always contain wikitext
-               return [
-                       [ 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ],
-                       [ 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ],
-                       [ serialize( 'hello world' ), 'Dummy:Hello', null, null, 'DummyContentHandlerForTesting' ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetContentHandler
-        * @covers Revision::getContentHandler
-        */
-       public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) {
-               $rev = $this->newTestRevision( $text, $title, $model, $format );
-
-               $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) );
-       }
-
-       public function provideGetContent() {
-               // NOTE: we expect the help namespace to always contain wikitext
-               return [
-                       [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ],
-                       [
-                               serialize( 'hello world' ),
-                               'Hello',
-                               DummyContentForTesting::MODEL_ID,
-                               null,
-                               Revision::FOR_PUBLIC,
-                               serialize( 'hello world' )
-                       ],
-                       [
-                               serialize( 'hello world' ),
-                               'Dummy:Hello',
-                               null,
-                               null,
-                               Revision::FOR_PUBLIC,
-                               serialize( 'hello world' )
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetContent
-        * @covers Revision::getContent
-        */
-       public function testGetContent( $text, $title, $model, $format,
-               $audience, $expectedSerialization
-       ) {
-               $rev = $this->newTestRevision( $text, $title, $model, $format );
-               $content = $rev->getContent( $audience );
-
-               $this->assertEquals(
-                       $expectedSerialization,
-                       is_null( $content ) ? null : $content->serialize( $format )
-               );
-       }
-
-       /**
-        * @covers Revision::getContent
-        */
-       public function testGetContent_failure() {
-               $rev = new Revision( [
-                       'page' => $this->testPage->getId(),
-                       'content_model' => $this->testPage->getContentModel(),
-                       'text_id' => 123456789, // not in the test DB
-               ] );
-
-               $this->assertNull( $rev->getContent(),
-                       "getContent() should return null if the revision's text blob could not be loaded." );
-
-               // NOTE: check this twice, once for lazy initialization, and once with the cached value.
-               $this->assertNull( $rev->getContent(),
-                       "getContent() should return null if the revision's text blob could not be loaded." );
-       }
-
-       public function provideGetSize() {
-               return [
-                       [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ],
-                       [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ],
-               ];
-       }
-
-       /**
-        * @covers Revision::getSize
-        * @dataProvider provideGetSize
-        */
-       public function testGetSize( $text, $model, $expected_size ) {
-               $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model );
-               $this->assertEquals( $expected_size, $rev->getSize() );
-       }
-
-       public function provideGetSha1() {
-               return [
-                       [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ],
-                       [
-                               serialize( "hello world." ),
-                               DummyContentForTesting::MODEL_ID,
-                               Revision::base36Sha1( serialize( "hello world." ) )
-                       ],
-               ];
-       }
-
-       /**
-        * @covers Revision::getSha1
-        * @dataProvider provideGetSha1
-        */
-       public function testGetSha1( $text, $model, $expected_hash ) {
-               $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model );
-               $this->assertEquals( $expected_hash, $rev->getSha1() );
-       }
-
-       /**
-        * Tests whether $rev->getContent() returns a clone when needed.
-        *
-        * @covers Revision::getContent
-        */
-       public function testGetContentClone() {
-               $content = new RevisionTestModifyableContent( "foo" );
-
-               $rev = new Revision(
-                       [
-                               'id' => 42,
-                               'page' => 23,
-                               'title' => Title::newFromText( "testGetContentClone_dummy" ),
-
-                               'content' => $content,
-                               'length' => $content->getSize(),
-                               'comment' => "testing",
-                               'minor_edit' => false,
-                       ]
-               );
-
-               /** @var RevisionTestModifyableContent $content */
-               $content = $rev->getContent( Revision::RAW );
-               $content->setText( "bar" );
-
-               /** @var RevisionTestModifyableContent $content2 */
-               $content2 = $rev->getContent( Revision::RAW );
-               // content is mutable, expect clone
-               $this->assertNotSame( $content, $content2, "expected a clone" );
-               // clone should contain the original text
-               $this->assertEquals( "foo", $content2->getText() );
-
-               $content2->setText( "bla bla" );
-               // clones should be independent
-               $this->assertEquals( "bar", $content->getText() );
-       }
-
-       /**
-        * Tests whether $rev->getContent() returns the same object repeatedly if appropriate.
-        * @covers Revision::getContent
-        */
-       public function testGetContentUncloned() {
-               $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT );
-               $content = $rev->getContent( Revision::RAW );
-               $content2 = $rev->getContent( Revision::RAW );
-
-               // for immutable content like wikitext, this should be the same object
-               $this->assertSame( $content, $content2 );
-       }
-
-       /**
-        * @covers Revision::loadFromId
-        */
-       public function testLoadFromId() {
-               $rev = $this->testPage->getRevision();
-               $this->assertRevEquals(
-                       $rev,
-                       Revision::loadFromId( wfGetDB( DB_MASTER ), $rev->getId() )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromPageId
-        */
-       public function testLoadFromPageId() {
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromPageId
-        */
-       public function testLoadFromPageIdWithLatestRevId() {
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       Revision::loadFromPageId(
-                               wfGetDB( DB_MASTER ),
-                               $this->testPage->getId(),
-                               $this->testPage->getLatest()
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromPageId
-        */
-       public function testLoadFromPageIdWithNotLatestRevId() {
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $this->assertRevEquals(
-                       $this->testPage->getRevision()->getPrevious(),
-                       Revision::loadFromPageId(
-                               wfGetDB( DB_MASTER ),
-                               $this->testPage->getId(),
-                               $this->testPage->getRevision()->getPrevious()->getId()
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromTitle
-        */
-       public function testLoadFromTitle() {
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromTitle
-        */
-       public function testLoadFromTitleWithLatestRevId() {
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       Revision::loadFromTitle(
-                               wfGetDB( DB_MASTER ),
-                               $this->testPage->getTitle(),
-                               $this->testPage->getLatest()
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromTitle
-        */
-       public function testLoadFromTitleWithNotLatestRevId() {
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
-               $this->assertRevEquals(
-                       $this->testPage->getRevision()->getPrevious(),
-                       Revision::loadFromTitle(
-                               wfGetDB( DB_MASTER ),
-                               $this->testPage->getTitle(),
-                               $this->testPage->getRevision()->getPrevious()->getId()
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::loadFromTimestamp()
-        */
-       public function testLoadFromTimestamp() {
-               $this->assertRevEquals(
-                       $this->testPage->getRevision(),
-                       Revision::loadFromTimestamp(
-                               wfGetDB( DB_MASTER ),
-                               $this->testPage->getTitle(),
-                               $this->testPage->getRevision()->getTimestamp()
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::getParentLengths
-        */
-       public function testGetParentLengths_noRevIds() {
-               $this->assertSame(
-                       [],
-                       Revision::getParentLengths(
-                               wfGetDB( DB_MASTER ),
-                               []
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::getParentLengths
-        */
-       public function testGetParentLengths_oneRevId() {
-               $text = '831jr091jr0921kr21kr0921kjr0921j09rj1';
-               $textLength = strlen( $text );
-
-               $this->testPage->doEditContent( new WikitextContent( $text ), __METHOD__ );
-               $rev[1] = $this->testPage->getLatest();
-
-               $this->assertSame(
-                       [ $rev[1] => strval( $textLength ) ],
-                       Revision::getParentLengths(
-                               wfGetDB( DB_MASTER ),
-                               [ $rev[1] ]
-                       )
-               );
-       }
-
-       /**
-        * @covers Revision::getParentLengths
-        */
-       public function testGetParentLengths_multipleRevIds() {
-               $textOne = '831jr091jr0921kr21kr0921kjr0921j09rj1';
-               $textOneLength = strlen( $textOne );
-               $textTwo = '831jr091jr092121j09rj1';
-               $textTwoLength = strlen( $textTwo );
-
-               $this->testPage->doEditContent( new WikitextContent( $textOne ), __METHOD__ );
-               $rev[1] = $this->testPage->getLatest();
-               $this->testPage->doEditContent( new WikitextContent( $textTwo ), __METHOD__ );
-               $rev[2] = $this->testPage->getLatest();
-
-               $this->assertSame(
-                       [ $rev[1] => strval( $textOneLength ), $rev[2] => strval( $textTwoLength ) ],
-                       Revision::getParentLengths(
-                               wfGetDB( DB_MASTER ),
-                               [ $rev[1], $rev[2] ]
-                       )
-               );
-       }
-
-}
diff --git a/tests/phpunit/includes/RevisionNoContentHandlerDbTest.php b/tests/phpunit/includes/RevisionNoContentHandlerDbTest.php
new file mode 100644 (file)
index 0000000..c980a48
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @group Database
+ * @group medium
+ * @group ContentHandler
+ */
+class RevisionNoContentHandlerDbTest extends RevisionDbTestBase {
+
+       protected function getContentHandlerUseDB() {
+               return false;
+       }
+
+}
diff --git a/tests/phpunit/includes/RevisionTest.php b/tests/phpunit/includes/RevisionTest.php
new file mode 100644 (file)
index 0000000..953c795
--- /dev/null
@@ -0,0 +1,469 @@
+<?php
+
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * Test cases in RevisionTest should not interact with the Database.
+ * For test cases that need Database interaction see RevisionDbTestBase.
+ */
+class RevisionTest extends MediaWikiTestCase {
+
+       public function provideConstructFromArray() {
+               yield 'with text' => [
+                       [
+                               'text' => 'hello world.',
+                               'content_model' => CONTENT_MODEL_JAVASCRIPT
+                       ],
+               ];
+               yield 'with content' => [
+                       [
+                               'content' => new JavaScriptContent( 'hellow world.' )
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideConstructFromArray
+        * @covers Revision::__construct
+        * @covers Revision::constructFromRowArray
+        */
+       public function testConstructFromArray( array $rowArray ) {
+               $rev = new Revision( $rowArray );
+               $this->assertNotNull( $rev->getContent(), 'no content object available' );
+               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
+               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
+       }
+
+       public function provideConstructFromArrayThrowsExceptions() {
+               yield 'content and text_id both not empty' => [
+                       [
+                               'content' => new WikitextContent( 'GOAT' ),
+                               'text_id' => 'someid',
+                               ],
+                       new MWException( "Text already stored in external store (id someid), " .
+                               "can't serialize content object" )
+               ];
+               yield 'with bad content object (class)' => [
+                       [ 'content' => new stdClass() ],
+                       new MWException( '`content` field must contain a Content object.' )
+               ];
+               yield 'with bad content object (string)' => [
+                       [ 'content' => 'ImAGoat' ],
+                       new MWException( '`content` field must contain a Content object.' )
+               ];
+               yield 'bad row format' => [
+                       'imastring, not a row',
+                       new MWException( 'Revision constructor passed invalid row format.' )
+               ];
+       }
+
+       /**
+        * @dataProvider provideConstructFromArrayThrowsExceptions
+        * @covers Revision::__construct
+        * @covers Revision::constructFromRowArray
+        */
+       public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) {
+               $this->setExpectedException(
+                       get_class( $expectedException ),
+                       $expectedException->getMessage(),
+                       $expectedException->getCode()
+               );
+               new Revision( $rowArray );
+       }
+
+       public function provideConstructFromRow() {
+               yield 'Full construction' => [
+                       [
+                               'rev_id' => '2',
+                               'rev_page' => '1',
+                               'rev_text_id' => '2',
+                               'rev_timestamp' => '20171017114835',
+                               'rev_user_text' => '127.0.0.1',
+                               'rev_user' => '0',
+                               'rev_minor_edit' => '0',
+                               'rev_deleted' => '0',
+                               'rev_len' => '46',
+                               'rev_parent_id' => '1',
+                               'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
+                               'rev_comment_text' => 'Goat Comment!',
+                               'rev_comment_data' => null,
+                               'rev_comment_cid' => null,
+                               'rev_content_format' => 'GOATFORMAT',
+                               'rev_content_model' => 'GOATMODEL',
+                       ],
+                       function ( RevisionTest $testCase, Revision $rev ) {
+                               $testCase->assertSame( 2, $rev->getId() );
+                               $testCase->assertSame( 1, $rev->getPage() );
+                               $testCase->assertSame( 2, $rev->getTextId() );
+                               $testCase->assertSame( '20171017114835', $rev->getTimestamp() );
+                               $testCase->assertSame( '127.0.0.1', $rev->getUserText() );
+                               $testCase->assertSame( 0, $rev->getUser() );
+                               $testCase->assertSame( false, $rev->isMinor() );
+                               $testCase->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
+                               $testCase->assertSame( 46, $rev->getSize() );
+                               $testCase->assertSame( 1, $rev->getParentId() );
+                               $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() );
+                               $testCase->assertSame( 'Goat Comment!', $rev->getComment() );
+                               $testCase->assertSame( 'GOATFORMAT', $rev->getContentFormat() );
+                               $testCase->assertSame( 'GOATMODEL', $rev->getContentModel() );
+                       }
+               ];
+               yield 'null fields' => [
+                       [
+                               'rev_id' => '2',
+                               'rev_page' => '1',
+                               'rev_text_id' => '2',
+                               'rev_timestamp' => '20171017114835',
+                               'rev_user_text' => '127.0.0.1',
+                               'rev_user' => '0',
+                               'rev_minor_edit' => '0',
+                               'rev_deleted' => '0',
+                               'rev_comment_text' => 'Goat Comment!',
+                               'rev_comment_data' => null,
+                               'rev_comment_cid' => null,
+                       ],
+                       function ( RevisionTest $testCase, Revision $rev ) {
+                               $testCase->assertNull( $rev->getSize() );
+                               $testCase->assertNull( $rev->getParentId() );
+                               $testCase->assertNull( $rev->getSha1() );
+                               $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat() );
+                               $testCase->assertSame( 'wikitext', $rev->getContentModel() );
+                       }
+               ];
+       }
+
+       /**
+        * @dataProvider provideConstructFromRow
+        * @covers Revision::__construct
+        * @covers Revision::constructFromDbRowObject
+        */
+       public function testConstructFromRow( array $arrayData, $assertions ) {
+               $row = (object)$arrayData;
+               $rev = new Revision( $row );
+               $assertions( $this, $rev );
+       }
+
+       public function provideGetRevisionText() {
+               yield 'Generic test' => [
+                       'This is a goat of revision text.',
+                       [
+                               'old_flags' => '',
+                               'old_text' => 'This is a goat of revision text.',
+                       ],
+               ];
+       }
+
+       public function provideGetId() {
+               yield [
+                       [],
+                       null
+               ];
+               yield [
+                       [ 'id' => 998 ],
+                       998
+               ];
+       }
+
+       /**
+        * @dataProvider provideGetId
+        * @covers Revision::getId
+        */
+       public function testGetId( $rowArray, $expectedId ) {
+               $rev = new Revision( $rowArray );
+               $this->assertEquals( $expectedId, $rev->getId() );
+       }
+
+       public function provideSetId() {
+               yield [ '123', 123 ];
+               yield [ 456, 456 ];
+       }
+
+       /**
+        * @dataProvider provideSetId
+        * @covers Revision::setId
+        */
+       public function testSetId( $input, $expected ) {
+               $rev = new Revision( [] );
+               $rev->setId( $input );
+               $this->assertSame( $expected, $rev->getId() );
+       }
+
+       public function provideSetUserIdAndName() {
+               yield [ '123', 123, 'GOaT' ];
+               yield [ 456, 456, 'GOaT' ];
+       }
+
+       /**
+        * @dataProvider provideSetUserIdAndName
+        * @covers Revision::setUserIdAndName
+        */
+       public function testSetUserIdAndName( $inputId, $expectedId, $name ) {
+               $rev = new Revision( [] );
+               $rev->setUserIdAndName( $inputId, $name );
+               $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) );
+               $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) );
+       }
+
+       public function provideGetTextId() {
+               yield [ [], null ];
+               yield [ [ 'text_id' => '123' ], 123 ];
+               yield [ [ 'text_id' => 456 ], 456 ];
+       }
+
+       /**
+        * @dataProvider provideGetTextId
+        * @covers Revision::getTextId()
+        */
+       public function testGetTextId( $rowArray, $expected ) {
+               $rev = new Revision( $rowArray );
+               $this->assertSame( $expected, $rev->getTextId() );
+       }
+
+       public function provideGetParentId() {
+               yield [ [], null ];
+               yield [ [ 'parent_id' => '123' ], 123 ];
+               yield [ [ 'parent_id' => 456 ], 456 ];
+       }
+
+       /**
+        * @dataProvider provideGetParentId
+        * @covers Revision::getParentId()
+        */
+       public function testGetParentId( $rowArray, $expected ) {
+               $rev = new Revision( $rowArray );
+               $this->assertSame( $expected, $rev->getParentId() );
+       }
+
+       /**
+        * @covers Revision::getRevisionText
+        * @dataProvider provideGetRevisionText
+        */
+       public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) {
+               $this->assertEquals(
+                       $expected,
+                       Revision::getRevisionText( (object)$rowData, $prefix, $wiki ) );
+       }
+
+       public function provideGetRevisionTextWithZlibExtension() {
+               yield 'Generic gzip test' => [
+                       'This is a small goat of revision text.',
+                       [
+                               'old_flags' => 'gzip',
+                               'old_text' => gzdeflate( 'This is a small goat of revision text.' ),
+                       ],
+               ];
+       }
+
+       /**
+        * @covers Revision::getRevisionText
+        * @dataProvider provideGetRevisionTextWithZlibExtension
+        */
+       public function testGetRevisionWithZlibExtension( $expected, $rowData ) {
+               $this->checkPHPExtension( 'zlib' );
+               $this->testGetRevisionText( $expected, $rowData );
+       }
+
+       public function provideGetRevisionTextWithLegacyEncoding() {
+               yield 'Utf8Native' => [
+                       "Wiki est l'\xc3\xa9cole superieur !",
+                       'iso-8859-1',
+                       [
+                               'old_flags' => 'utf-8',
+                               'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
+                       ]
+               ];
+               yield 'Utf8Legacy' => [
+                       "Wiki est l'\xc3\xa9cole superieur !",
+                       'iso-8859-1',
+                       [
+                               'old_flags' => '',
+                               'old_text' => "Wiki est l'\xe9cole superieur !",
+                       ]
+               ];
+       }
+
+       /**
+        * @covers Revision::getRevisionText
+        * @dataProvider provideGetRevisionTextWithLegacyEncoding
+        */
+       public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $rowData ) {
+               $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
+               $this->testGetRevisionText( $expected, $rowData );
+       }
+
+       public function provideGetRevisionTextWithGzipAndLegacyEncoding() {
+               /**
+                * WARNING!
+                * Do not set the external flag!
+                * Otherwise, getRevisionText will hit the live database (if ExternalStore is enabled)!
+                */
+               yield 'Utf8NativeGzip' => [
+                       "Wiki est l'\xc3\xa9cole superieur !",
+                       'iso-8859-1',
+                       [
+                               'old_flags' => 'gzip,utf-8',
+                               'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
+                       ]
+               ];
+               yield 'Utf8LegacyGzip' => [
+                       "Wiki est l'\xc3\xa9cole superieur !",
+                       'iso-8859-1',
+                       [
+                               'old_flags' => 'gzip',
+                               'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
+                       ]
+               ];
+       }
+
+       /**
+        * @covers Revision::getRevisionText
+        * @dataProvider provideGetRevisionTextWithGzipAndLegacyEncoding
+        */
+       public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $rowData ) {
+               $this->checkPHPExtension( 'zlib' );
+               $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
+               $this->testGetRevisionText( $expected, $rowData );
+       }
+
+       /**
+        * @covers Revision::compressRevisionText
+        */
+       public function testCompressRevisionTextUtf8() {
+               $row = new stdClass;
+               $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
+               $row->old_flags = Revision::compressRevisionText( $row->old_text );
+               $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
+                       "Flags should contain 'utf-8'" );
+               $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ),
+                       "Flags should not contain 'gzip'" );
+               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
+                       $row->old_text, "Direct check" );
+               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
+                       Revision::getRevisionText( $row ), "getRevisionText" );
+       }
+
+       /**
+        * @covers Revision::compressRevisionText
+        */
+       public function testCompressRevisionTextUtf8Gzip() {
+               $this->checkPHPExtension( 'zlib' );
+               $this->setMwGlobals( 'wgCompressRevisions', true );
+
+               $row = new stdClass;
+               $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
+               $row->old_flags = Revision::compressRevisionText( $row->old_text );
+               $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
+                       "Flags should contain 'utf-8'" );
+               $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ),
+                       "Flags should contain 'gzip'" );
+               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
+                       gzinflate( $row->old_text ), "Direct check" );
+               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
+                       Revision::getRevisionText( $row ), "getRevisionText" );
+       }
+
+       public function provideFetchFromConds() {
+               yield [ 0, [] ];
+               yield [ Revision::READ_LOCKING, [ 'FOR UPDATE' ] ];
+       }
+
+       /**
+        * @dataProvider provideFetchFromConds
+        * @covers Revision::fetchFromConds
+        */
+       public function testFetchFromConds( $flags, array $options ) {
+               $conditions = [ 'conditionsArray' ];
+
+               $db = $this->getMock( IDatabase::class );
+               $db->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               $this->equalTo( [ 'revision', 'page', 'user' ] ),
+                               // We don't really care about the fields are they come from the selectField methods
+                               $this->isType( 'array' ),
+                               $this->equalTo( $conditions ),
+                               // Method name
+                               $this->equalTo( 'Revision::fetchFromConds' ),
+                               $this->equalTo( $options ),
+                               // We don't really care about the join conds are they come from the joinCond methods
+                               $this->isType( 'array' )
+                       )
+                       ->willReturn( 'RETURNVALUE' );
+
+               $wrapper = TestingAccessWrapper::newFromClass( Revision::class );
+               $result = $wrapper->fetchFromConds( $db, $conditions, $flags );
+
+               $this->assertEquals( 'RETURNVALUE', $result );
+       }
+
+       public function provideDecompressRevisionText() {
+               yield '(no legacy encoding), false in false out' => [ false, false, [], false ];
+               yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
+               yield '(no legacy encoding), empty in empty out' => [ false, 'A', [], 'A' ];
+               yield '(no legacy encoding), string in with gzip flag returns string' => [
+                       // gzip string below generated with gzdeflate( 'AAAABBAAA' )
+                       false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
+               ];
+               yield '(no legacy encoding), string in with object flag returns false' => [
+                       // gzip string below generated with serialize( 'JOJO' )
+                       false, "s:4:\"JOJO\";", [ 'object' ], false,
+               ];
+               yield '(no legacy encoding), serialized object in with object flag returns string' => [
+                       false,
+                       // Using a TitleValue object as it has a getText method (which is needed)
+                       serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
+                       [ 'object' ],
+                       'HHJJDDFF',
+               ];
+               yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
+                       false,
+                       // Using a TitleValue object as it has a getText method (which is needed)
+                       gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
+                       [ 'object', 'gzip' ],
+                       '8219JJJ840',
+               ];
+               yield '(ISO-8859-1 encoding), string in string out' => [
+                       'ISO-8859-1',
+                       iconv( 'utf8', 'ISO-8859-1', "1®Àþ1" ),
+                       [],
+                       '1®Àþ1',
+               ];
+               yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
+                       'ISO-8859-1',
+                       gzdeflate( iconv( 'utf8', 'ISO-8859-1', "4®Àþ4" ) ),
+                       [ 'gzip' ],
+                       '4®Àþ4',
+               ];
+               yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
+                       'ISO-8859-1',
+                       serialize( new TitleValue( 0, iconv( 'utf8', 'ISO-8859-1', "3®Àþ3" ) ) ),
+                       [ 'object' ],
+                       '3®Àþ3',
+               ];
+               yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
+                       'ISO-8859-1',
+                       gzdeflate( serialize( new TitleValue( 0, iconv( 'utf8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
+                       [ 'gzip', 'object' ],
+                       '2®Àþ2',
+               ];
+       }
+
+       /**
+        * @dataProvider provideDecompressRevisionText
+        * @covers Revision::decompressRevisionText
+        *
+        * @param bool $legacyEncoding
+        * @param mixed $text
+        * @param array $flags
+        * @param mixed $expected
+        */
+       public function testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected ) {
+               $this->setMwGlobals( 'wgLegacyEncoding', $legacyEncoding );
+               $this->setMwGlobals( 'wgLanguageCode', 'en' );
+               $this->assertSame(
+                       $expected,
+                       Revision::decompressRevisionText( $text, $flags )
+               );
+       }
+
+}
diff --git a/tests/phpunit/includes/RevisionUnitTest.php b/tests/phpunit/includes/RevisionUnitTest.php
deleted file mode 100644 (file)
index 7b8d316..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-<?php
-
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @group ContentHandler
- */
-class RevisionUnitTest extends MediaWikiTestCase {
-
-       public function provideConstructFromArray() {
-               yield 'with text' => [
-                       [
-                               'text' => 'hello world.',
-                               'content_model' => CONTENT_MODEL_JAVASCRIPT
-                       ],
-               ];
-               yield 'with content' => [
-                       [
-                               'content' => new JavaScriptContent( 'hellow world.' )
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideConstructFromArray
-        * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
-        */
-       public function testConstructFromArray( array $rowArray ) {
-               $rev = new Revision( $rowArray );
-               $this->assertNotNull( $rev->getContent(), 'no content object available' );
-               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
-               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
-       }
-
-       public function provideConstructFromArrayThrowsExceptions() {
-               yield 'content and text_id both not empty' => [
-                       [
-                               'content' => new WikitextContent( 'GOAT' ),
-                               'text_id' => 'someid',
-                               ],
-                       new MWException( "Text already stored in external store (id someid), " .
-                               "can't serialize content object" )
-               ];
-               yield 'with bad content object (class)' => [
-                       [ 'content' => new stdClass() ],
-                       new MWException( '`content` field must contain a Content object.' )
-               ];
-               yield 'with bad content object (string)' => [
-                       [ 'content' => 'ImAGoat' ],
-                       new MWException( '`content` field must contain a Content object.' )
-               ];
-               yield 'bad row format' => [
-                       'imastring, not a row',
-                       new MWException( 'Revision constructor passed invalid row format.' )
-               ];
-       }
-
-       /**
-        * @dataProvider provideConstructFromArrayThrowsExceptions
-        * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
-        */
-       public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) {
-               $this->setExpectedException(
-                       get_class( $expectedException ),
-                       $expectedException->getMessage(),
-                       $expectedException->getCode()
-               );
-               new Revision( $rowArray );
-       }
-
-       public function provideConstructFromRow() {
-               yield 'Full construction' => [
-                       [
-                               'rev_id' => '2',
-                               'rev_page' => '1',
-                               'rev_text_id' => '2',
-                               'rev_timestamp' => '20171017114835',
-                               'rev_user_text' => '127.0.0.1',
-                               'rev_user' => '0',
-                               'rev_minor_edit' => '0',
-                               'rev_deleted' => '0',
-                               'rev_len' => '46',
-                               'rev_parent_id' => '1',
-                               'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
-                               'rev_comment_text' => 'Goat Comment!',
-                               'rev_comment_data' => null,
-                               'rev_comment_cid' => null,
-                               'rev_content_format' => 'GOATFORMAT',
-                               'rev_content_model' => 'GOATMODEL',
-                       ],
-                       function ( RevisionUnitTest $testCase, Revision $rev ) {
-                               $testCase->assertSame( 2, $rev->getId() );
-                               $testCase->assertSame( 1, $rev->getPage() );
-                               $testCase->assertSame( 2, $rev->getTextId() );
-                               $testCase->assertSame( '20171017114835', $rev->getTimestamp() );
-                               $testCase->assertSame( '127.0.0.1', $rev->getUserText() );
-                               $testCase->assertSame( 0, $rev->getUser() );
-                               $testCase->assertSame( false, $rev->isMinor() );
-                               $testCase->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
-                               $testCase->assertSame( 46, $rev->getSize() );
-                               $testCase->assertSame( 1, $rev->getParentId() );
-                               $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() );
-                               $testCase->assertSame( 'Goat Comment!', $rev->getComment() );
-                               $testCase->assertSame( 'GOATFORMAT', $rev->getContentFormat() );
-                               $testCase->assertSame( 'GOATMODEL', $rev->getContentModel() );
-                       }
-               ];
-               yield 'null fields' => [
-                       [
-                               'rev_id' => '2',
-                               'rev_page' => '1',
-                               'rev_text_id' => '2',
-                               'rev_timestamp' => '20171017114835',
-                               'rev_user_text' => '127.0.0.1',
-                               'rev_user' => '0',
-                               'rev_minor_edit' => '0',
-                               'rev_deleted' => '0',
-                               'rev_comment_text' => 'Goat Comment!',
-                               'rev_comment_data' => null,
-                               'rev_comment_cid' => null,
-                       ],
-                       function ( RevisionUnitTest $testCase, Revision $rev ) {
-                               $testCase->assertNull( $rev->getSize() );
-                               $testCase->assertNull( $rev->getParentId() );
-                               $testCase->assertNull( $rev->getSha1() );
-                               $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat() );
-                               $testCase->assertSame( 'wikitext', $rev->getContentModel() );
-                       }
-               ];
-       }
-
-       /**
-        * @dataProvider provideConstructFromRow
-        * @covers Revision::__construct
-        * @covers Revision::constructFromDbRowObject
-        */
-       public function testConstructFromRow( array $arrayData, $assertions ) {
-               $row = (object)$arrayData;
-               $rev = new Revision( $row );
-               $assertions( $this, $rev );
-       }
-
-       public function provideGetRevisionText() {
-               yield 'Generic test' => [
-                       'This is a goat of revision text.',
-                       [
-                               'old_flags' => '',
-                               'old_text' => 'This is a goat of revision text.',
-                       ],
-               ];
-       }
-
-       public function provideGetId() {
-               yield [
-                       [],
-                       null
-               ];
-               yield [
-                       [ 'id' => 998 ],
-                       998
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetId
-        * @covers Revision::getId
-        */
-       public function testGetId( $rowArray, $expectedId ) {
-               $rev = new Revision( $rowArray );
-               $this->assertEquals( $expectedId, $rev->getId() );
-       }
-
-       public function provideSetId() {
-               yield [ '123', 123 ];
-               yield [ 456, 456 ];
-       }
-
-       /**
-        * @dataProvider provideSetId
-        * @covers Revision::setId
-        */
-       public function testSetId( $input, $expected ) {
-               $rev = new Revision( [] );
-               $rev->setId( $input );
-               $this->assertSame( $expected, $rev->getId() );
-       }
-
-       public function provideSetUserIdAndName() {
-               yield [ '123', 123, 'GOaT' ];
-               yield [ 456, 456, 'GOaT' ];
-       }
-
-       /**
-        * @dataProvider provideSetUserIdAndName
-        * @covers Revision::setUserIdAndName
-        */
-       public function testSetUserIdAndName( $inputId, $expectedId, $name ) {
-               $rev = new Revision( [] );
-               $rev->setUserIdAndName( $inputId, $name );
-               $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) );
-               $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) );
-       }
-
-       public function provideGetTextId() {
-               yield [ [], null ];
-               yield [ [ 'text_id' => '123' ], 123 ];
-               yield [ [ 'text_id' => 456 ], 456 ];
-       }
-
-       /**
-        * @dataProvider provideGetTextId
-        * @covers Revision::getTextId()
-        */
-       public function testGetTextId( $rowArray, $expected ) {
-               $rev = new Revision( $rowArray );
-               $this->assertSame( $expected, $rev->getTextId() );
-       }
-
-       public function provideGetParentId() {
-               yield [ [], null ];
-               yield [ [ 'parent_id' => '123' ], 123 ];
-               yield [ [ 'parent_id' => 456 ], 456 ];
-       }
-
-       /**
-        * @dataProvider provideGetParentId
-        * @covers Revision::getParentId()
-        */
-       public function testGetParentId( $rowArray, $expected ) {
-               $rev = new Revision( $rowArray );
-               $this->assertSame( $expected, $rev->getParentId() );
-       }
-
-       /**
-        * @covers Revision::getRevisionText
-        * @dataProvider provideGetRevisionText
-        */
-       public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) {
-               $this->assertEquals(
-                       $expected,
-                       Revision::getRevisionText( (object)$rowData, $prefix, $wiki ) );
-       }
-
-       public function provideGetRevisionTextWithZlibExtension() {
-               yield 'Generic gzip test' => [
-                       'This is a small goat of revision text.',
-                       [
-                               'old_flags' => 'gzip',
-                               'old_text' => gzdeflate( 'This is a small goat of revision text.' ),
-                       ],
-               ];
-       }
-
-       /**
-        * @covers Revision::getRevisionText
-        * @dataProvider provideGetRevisionTextWithZlibExtension
-        */
-       public function testGetRevisionWithZlibExtension( $expected, $rowData ) {
-               $this->checkPHPExtension( 'zlib' );
-               $this->testGetRevisionText( $expected, $rowData );
-       }
-
-       public function provideGetRevisionTextWithLegacyEncoding() {
-               yield 'Utf8Native' => [
-                       "Wiki est l'\xc3\xa9cole superieur !",
-                       'iso-8859-1',
-                       [
-                               'old_flags' => 'utf-8',
-                               'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
-                       ]
-               ];
-               yield 'Utf8Legacy' => [
-                       "Wiki est l'\xc3\xa9cole superieur !",
-                       'iso-8859-1',
-                       [
-                               'old_flags' => '',
-                               'old_text' => "Wiki est l'\xe9cole superieur !",
-                       ]
-               ];
-       }
-
-       /**
-        * @covers Revision::getRevisionText
-        * @dataProvider provideGetRevisionTextWithLegacyEncoding
-        */
-       public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $rowData ) {
-               $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
-               $this->testGetRevisionText( $expected, $rowData );
-       }
-
-       public function provideGetRevisionTextWithGzipAndLegacyEncoding() {
-               /**
-                * WARNING!
-                * Do not set the external flag!
-                * Otherwise, getRevisionText will hit the live database (if ExternalStore is enabled)!
-                */
-               yield 'Utf8NativeGzip' => [
-                       "Wiki est l'\xc3\xa9cole superieur !",
-                       'iso-8859-1',
-                       [
-                               'old_flags' => 'gzip,utf-8',
-                               'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
-                       ]
-               ];
-               yield 'Utf8LegacyGzip' => [
-                       "Wiki est l'\xc3\xa9cole superieur !",
-                       'iso-8859-1',
-                       [
-                               'old_flags' => 'gzip',
-                               'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
-                       ]
-               ];
-       }
-
-       /**
-        * @covers Revision::getRevisionText
-        * @dataProvider provideGetRevisionTextWithGzipAndLegacyEncoding
-        */
-       public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $rowData ) {
-               $this->checkPHPExtension( 'zlib' );
-               $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
-               $this->testGetRevisionText( $expected, $rowData );
-       }
-
-       /**
-        * @covers Revision::compressRevisionText
-        */
-       public function testCompressRevisionTextUtf8() {
-               $row = new stdClass;
-               $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
-               $row->old_flags = Revision::compressRevisionText( $row->old_text );
-               $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
-                       "Flags should contain 'utf-8'" );
-               $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ),
-                       "Flags should not contain 'gzip'" );
-               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
-                       $row->old_text, "Direct check" );
-               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
-                       Revision::getRevisionText( $row ), "getRevisionText" );
-       }
-
-       /**
-        * @covers Revision::compressRevisionText
-        */
-       public function testCompressRevisionTextUtf8Gzip() {
-               $this->checkPHPExtension( 'zlib' );
-               $this->setMwGlobals( 'wgCompressRevisions', true );
-
-               $row = new stdClass;
-               $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
-               $row->old_flags = Revision::compressRevisionText( $row->old_text );
-               $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
-                       "Flags should contain 'utf-8'" );
-               $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ),
-                       "Flags should contain 'gzip'" );
-               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
-                       gzinflate( $row->old_text ), "Direct check" );
-               $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
-                       Revision::getRevisionText( $row ), "getRevisionText" );
-       }
-
-       public function provideFetchFromConds() {
-               yield [ 0, [] ];
-               yield [ Revision::READ_LOCKING, [ 'FOR UPDATE' ] ];
-       }
-
-       /**
-        * @dataProvider provideFetchFromConds
-        * @covers Revision::fetchFromConds
-        */
-       public function testFetchFromConds( $flags, array $options ) {
-               $conditions = [ 'conditionsArray' ];
-
-               $db = $this->getMock( IDatabase::class );
-               $db->expects( $this->once() )
-                       ->method( 'selectRow' )
-                       ->with(
-                               $this->equalTo( [ 'revision', 'page', 'user' ] ),
-                               // We don't really care about the fields are they come from the selectField methods
-                               $this->isType( 'array' ),
-                               $this->equalTo( $conditions ),
-                               // Method name
-                               $this->equalTo( 'Revision::fetchFromConds' ),
-                               $this->equalTo( $options ),
-                               // We don't really care about the join conds are they come from the joinCond methods
-                               $this->isType( 'array' )
-                       )
-                       ->willReturn( 'RETURNVALUE' );
-
-               $wrapper = TestingAccessWrapper::newFromClass( Revision::class );
-               $result = $wrapper->fetchFromConds( $db, $conditions, $flags );
-
-               $this->assertEquals( 'RETURNVALUE', $result );
-       }
-}