Merge "RCFilters: Add 'boolean' group"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sat, 22 Jul 2017 00:29:34 +0000 (00:29 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 22 Jul 2017 00:29:34 +0000 (00:29 +0000)
104 files changed:
includes/Feed.php
includes/FileDeleteForm.php
includes/HistoryBlob.php
includes/Revision.php
includes/SiteStats.php
includes/api/ApiBase.php
includes/api/ApiMain.php
includes/api/ApiUsageException.php
includes/changes/ChangesFeed.php
includes/collation/NumericUppercaseCollation.php
includes/context/DerivativeContext.php
includes/db/CloneDatabase.php
includes/deferred/LinksUpdate.php
includes/deferred/SearchUpdate.php
includes/diff/DifferenceEngine.php
includes/exception/HttpError.php
includes/installer/DatabaseUpdater.php
includes/installer/i18n/csb.json
includes/libs/objectcache/APCBagOStuff.php
includes/libs/objectcache/APCUBagOStuff.php
includes/libs/objectcache/MemcachedPeclBagOStuff.php
includes/libs/rdbms/loadbalancer/ILoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/logging/LogPage.php
includes/logging/LogPager.php
includes/media/DjVuImage.php
includes/media/Exif.php
includes/media/SVGMetadataExtractor.php
includes/parser/ParserOptions.php
includes/profiler/output/ProfilerOutput.php
includes/resourceloader/ResourceLoaderClientHtml.php
includes/resourceloader/ResourceLoaderModule.php
includes/search/SearchDatabase.php
includes/specials/SpecialActiveusers.php
includes/specials/SpecialAllMessages.php
includes/specials/SpecialAllPages.php
includes/specials/SpecialImport.php
includes/specials/SpecialListusers.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialUpload.php
includes/tidy/RemexCompatMunger.php
languages/ConverterRule.php
languages/i18n/ast.json
languages/i18n/ba.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/cdo.json
languages/i18n/cs.json
languages/i18n/csb.json
languages/i18n/de.json
languages/i18n/din.json
languages/i18n/en.json
languages/i18n/eu.json
languages/i18n/fr.json
languages/i18n/frr.json
languages/i18n/gl.json
languages/i18n/gsw.json
languages/i18n/hak.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/it.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/li.json
languages/i18n/mk.json
languages/i18n/nan.json
languages/i18n/nn.json
languages/i18n/pl.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/roa-tara.json
languages/i18n/skr-arab.json [new file with mode: 0644]
languages/i18n/sl.json
languages/i18n/sv.json
languages/i18n/te.json
languages/i18n/tet.json
languages/i18n/tg-cyrl.json
languages/i18n/vi.json
languages/i18n/yi.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
maintenance/generateSitemap.php
maintenance/language/checkLanguage.inc
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js
resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.LiveUpdateButtonWidget.less
resources/src/mediawiki.widgets.visibleByteLimit/mediawiki.widgets.visibleByteLimit.js
resources/src/oojs-ui-local.js
tests/phpunit/ResourceLoaderTestCase.php
tests/phpunit/includes/api/ApiErrorFormatterTest.php
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/db/DatabaseMysqlBaseTest.php [deleted file]
tests/phpunit/includes/db/DatabaseSQLTest.php [deleted file]
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/db/DatabaseTest.php [deleted file]
tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php [new file with mode: 0644]
tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php [new file with mode: 0644]
tests/phpunit/includes/libs/rdbms/database/DatabaseTest.php [new file with mode: 0644]
tests/phpunit/includes/resourceloader/ResourceLoaderClientHtmlTest.php
tests/phpunit/structure/DatabaseIntegrationTest.php [new file with mode: 0644]
tests/qunit/data/testrunner.js

index 189fd9f..f76a634 100644 (file)
@@ -54,8 +54,6 @@ class FeedItem {
        public $rssIsPermalink = false;
 
        /**
-        * Constructor
-        *
         * @param string|Title $title Item's title
         * @param string $description
         * @param string $url URL uniquely designating the item.
index e7b4a1f..8a1cd35 100644 (file)
@@ -47,8 +47,6 @@ class FileDeleteForm {
        private $oldimage = '';
 
        /**
-        * Constructor
-        *
         * @param File $file File object we're deleting
         */
        public function __construct( $file ) {
index 56cf815..51bd7a9 100644 (file)
@@ -76,9 +76,6 @@ class ConcatenatedGzipHistoryBlob implements HistoryBlob {
        public $mMaxSize = 10000000;
        public $mMaxCount = 100;
 
-       /**
-        * Constructor
-        */
        public function __construct() {
                if ( !function_exists( 'gzdeflate' ) ) {
                        throw new MWException( "Need zlib support to read or write this "
index c3782ba..c6b50f4 100644 (file)
@@ -559,8 +559,6 @@ class Revision implements IDBAccessObject {
        }
 
        /**
-        * Constructor
-        *
         * @param object|array $row Either a database row or an array
         * @throws MWException
         * @access private
index 6ce1aed..5a0947d 100644 (file)
@@ -296,7 +296,6 @@ class SiteStatsInit {
        private $mUsers = null, $mFiles = null;
 
        /**
-        * Constructor
         * @param bool|IDatabase $database
         * - boolean: Whether to use the master DB
         * - IDatabase: Database connection to use
index bc3def8..c0b8828 100644 (file)
@@ -2614,6 +2614,7 @@ abstract class ApiBase extends ContextSource {
         * @param string $warning Warning message
         */
        public function setWarning( $warning ) {
+               wfDeprecated( __METHOD__, '1.29' );
                $msg = new ApiRawMessage( $warning, 'warning' );
                $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg );
        }
@@ -2632,6 +2633,7 @@ abstract class ApiBase extends ContextSource {
         * @throws ApiUsageException always
         */
        public function dieUsage( $description, $errorCode, $httpRespCode = 0, $extradata = null ) {
+               wfDeprecated( __METHOD__, '1.29' );
                $this->dieWithError(
                        new RawMessage( '$1', [ $description ] ),
                        $errorCode,
@@ -2651,6 +2653,7 @@ abstract class ApiBase extends ContextSource {
         * @throws MWException
         */
        public function getErrorFromStatus( $status, &$extraData = null ) {
+               wfDeprecated( __METHOD__, '1.29' );
                if ( $status->isGood() ) {
                        throw new MWException( 'Successful status passed to ApiBase::dieStatus' );
                }
@@ -2860,6 +2863,7 @@ abstract class ApiBase extends ContextSource {
         * @return [ 'code' => code, 'info' => info ]
         */
        public function parseMsg( $error ) {
+               wfDeprecated( __METHOD__, '1.29' );
                // Check whether someone passed the whole array, instead of one element as
                // documented. This breaks if it's actually an array of fallback keys, but
                // that's long-standing misbehavior introduced in r87627 to incorrectly
@@ -2889,6 +2893,7 @@ abstract class ApiBase extends ContextSource {
         * @throws ApiUsageException always
         */
        public function dieUsageMsg( $error ) {
+               wfDeprecated( __METHOD__, '1.29' );
                $this->dieWithError( $this->parseMsgInternal( $error ) );
        }
 
@@ -2901,6 +2906,7 @@ abstract class ApiBase extends ContextSource {
         * @since 1.21
         */
        public function dieUsageMsgOrDebug( $error ) {
+               wfDeprecated( __METHOD__, '1.29' );
                $this->dieWithErrorOrDebug( $this->parseMsgInternal( $error ) );
        }
 
index 52f79ee..869865e 100644 (file)
@@ -1041,7 +1041,7 @@ class ApiMain extends ApiBase {
                        // None of the rest have any messages for non-error types
                } elseif ( $e instanceof UsageException ) {
                        // User entered incorrect parameters - generate error response
-                       $data = $e->getMessageArray();
+                       $data = MediaWiki\quietCall( [ $e, 'getMessageArray' ] );
                        $code = $data['code'];
                        $info = $data['info'];
                        unset( $data['code'], $data['info'] );
index 9dc1f92..fb49e2d 100644 (file)
@@ -45,6 +45,10 @@ class UsageException extends MWException {
                $this->mCodestr = $codestr;
                $this->mExtraData = $extradata;
 
+               if ( !$this instanceof ApiUsageException ) {
+                       wfDeprecated( __METHOD__, '1.29' );
+               }
+
                // This should never happen, so throw an exception about it that will
                // hopefully get logged with a backtrace (T138585)
                if ( !is_string( $codestr ) || $codestr === '' ) {
@@ -58,6 +62,7 @@ class UsageException extends MWException {
         * @return string
         */
        public function getCodeString() {
+               wfDeprecated( __METHOD__, '1.29' );
                return $this->mCodestr;
        }
 
@@ -65,6 +70,7 @@ class UsageException extends MWException {
         * @return array
         */
        public function getMessageArray() {
+               wfDeprecated( __METHOD__, '1.29' );
                $result = [
                        'code' => $this->mCodestr,
                        'info' => $this->getMessage()
@@ -183,6 +189,7 @@ class ApiUsageException extends UsageException implements ILocalizedException {
         * @inheritdoc
         */
        public function getCodeString() {
+               wfDeprecated( __METHOD__, '1.29' );
                return $this->getApiMessage()->getApiCode();
        }
 
@@ -192,6 +199,7 @@ class ApiUsageException extends UsageException implements ILocalizedException {
         * @inheritdoc
         */
        public function getMessageArray() {
+               wfDeprecated( __METHOD__, '1.29' );
                $enMsg = clone $this->getApiMessage();
                $enMsg->inLanguage( 'en' )->useDatabase( false );
 
index cffb59a..99dc899 100644 (file)
@@ -31,8 +31,6 @@ class ChangesFeed {
        public $format, $type, $titleMsg, $descMsg;
 
        /**
-        * Constructor
-        *
         * @param string $format Feed's format (either 'rss' or 'atom')
         * @param string $type Type of feed (for cache keys)
         */
index 2d2ca47..8dd7a38 100644 (file)
@@ -40,8 +40,6 @@ class NumericUppercaseCollation extends UppercaseCollation {
        private $digitTransformLang;
 
        /**
-        * Constructor
-        *
         * @param $lang Language How to convert digits.
         *  For example, if given language "my" than ၇ is treated like 7.
         *
index 0d0c149..6e3eda6 100644 (file)
@@ -75,7 +75,6 @@ class DerivativeContext extends ContextSource implements MutableContext {
        private $timing;
 
        /**
-        * Constructor
         * @param IContextSource $context Context to inherit from
         */
        public function __construct( IContextSource $context ) {
index 6d18444..3d22c03 100644 (file)
@@ -46,8 +46,6 @@ class CloneDatabase {
        private $db;
 
        /**
-        * Constructor
-        *
         * @param IMaintainableDatabase $db A database subclass
         * @param array $tablesToClone An array of tables to clone, unprefixed
         * @param string $newTablePrefix Prefix to assign to the tables
index 072c1e0..c6facd9 100644 (file)
@@ -102,8 +102,6 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
        private $db;
 
        /**
-        * Constructor
-        *
         * @param Title $title Title of the page we're updating
         * @param ParserOutput $parserOutput Output from a full parse of this page
         * @param bool $recursive Queue jobs for recursive updates?
index b9a259b..2766bcb 100644 (file)
@@ -44,8 +44,6 @@ class SearchUpdate implements DeferrableUpdate {
        private $page;
 
        /**
-        * Constructor
-        *
         * @param int $id Page id to update
         * @param Title|string $title Title of page to update
         * @param Content|string|bool $c Content of the page to update. Default: false.
index 95420d9..d4bee29 100644 (file)
@@ -104,7 +104,6 @@ class DifferenceEngine extends ContextSource {
        /**#@-*/
 
        /**
-        * Constructor
         * @param IContextSource $context Context to use, anything else will be ignored
         * @param int $old Old ID we want to show and diff with.
         * @param string|int $new Either revision ID or 'prev' or 'next'. Default: 0.
index 48bc3bd..f464d8a 100644 (file)
@@ -31,8 +31,6 @@ class HttpError extends MWException {
        private $httpCode, $header, $content;
 
        /**
-        * Constructor
-        *
         * @param int $httpCode HTTP status code to send to the client
         * @param string|Message $content Content of the message
         * @param string|Message|null $header Content of the header (\<title\> and \<h1\>)
index e5cbb7c..7e43fb5 100644 (file)
@@ -105,8 +105,6 @@ abstract class DatabaseUpdater {
        protected $holdContentHandlerUseDB = true;
 
        /**
-        * Constructor
-        *
         * @param Database $db To perform updates on
         * @param bool $shared Whether to perform updates on shared tables
         * @param Maintenance $maintenance Maintenance object which created us
index 2ba47f1..27963bd 100644 (file)
@@ -1,4 +1,51 @@
 {
-       "@metadata": [],
-       "mainpagetext": "'''MediaWiki òsta zainstalowónô.'''"
+       "@metadata": {
+               "authors": [
+                       "Kaszeba"
+               ]
+       },
+       "config-desc": "Jinstalownik MediaWiki",
+       "config-title": "Jinstalowanié MediaWiki $1",
+       "config-information": "Wëdowiédzô",
+       "config-localsettings-key": "Klucz aktualizacëji:",
+       "config-localsettings-badkey": "Lëchi klucz aktualizacëji.",
+       "config-session-error": "Fela zrëszeniô sesëji – $1",
+       "config-your-language": "Twój jãzëk:",
+       "config-your-language-help": "Wybierzë jãzëk procesu jinstalacëji.",
+       "config-wiki-language": "Jãzëk wiki:",
+       "config-back": "← Nazôd",
+       "config-continue": "Dali →",
+       "config-page-language": "Jãzëk",
+       "config-page-welcome": "Witómë w MediaWiki!",
+       "config-page-dbconnect": "Sparłãczë z bazą pòdôwków",
+       "config-page-upgrade": "Zaktualnienié jinstalacëji",
+       "config-page-dbsettings": "Nastôw bazë pòdôwków",
+       "config-page-name": "Miono",
+       "config-page-options": "Òptacëje",
+       "config-page-install": "Wjinstalëjë",
+       "config-page-complete": "Fardich!",
+       "config-page-restart": "Zrëszë jinstalacëjã znowa",
+       "config-page-readme": "Spòdlowô wëdowiédzô",
+       "config-page-releasenotes": "Wëdowiédzô ò wersëji",
+       "config-page-copying": "Kòpérowanié",
+       "config-page-upgradedoc": "Zaktualnienié",
+       "config-page-existingwiki": "Egyzstëjącô wiki",
+       "config-restart": "Jo, zrëszë znowa",
+       "config-env-php": "PHP $1 je wjinastalowóné",
+       "config-env-hhvm": "HHVM $1 je wjinastalowóné",
+       "config-admin-box": "Kònto sprôwnika",
+       "config-admin-name": "Twòjé miono brëkòwnika:",
+       "config-admin-password": "Parola:",
+       "config-admin-password-confirm": "Pòwtórzë parolã:",
+       "config-admin-name-blank": "Wpiszë miono brëkòwnika, chtëren bãdze sprôwnikã.",
+       "config-admin-email": "E-mailowô adresa:",
+       "config-license-none": "Felënk stopczi z licencëją",
+       "config-email-settings": "Nastôwë e-mail",
+       "config-logo": "Adresa URL logo:",
+       "config-skins": "Wëzdrzatk",
+       "config-skins-use-as-default": "Ùżëjë tegò wëzdrzatkù za domëslny",
+       "config-install-step-done": "fardich",
+       "config-install-step-failed": "nie dzrzëło sã",
+       "config-help": "pòmòc",
+       "mainpagetext": "<strong>MediaWiki òsta wjinstalowónô.<strong>"
 }
index 9bfcee7..e41c3a2 100644 (file)
@@ -42,8 +42,6 @@ class APCBagOStuff extends BagOStuff {
        const KEY_SUFFIX = ':2';
 
        /**
-        * Constructor
-        *
         * Available parameters are:
         *   - nativeSerialize:     If true, pass objects to apc_store(), and trust it
         *                          to serialize them correctly. If false, serialize
index 6e6a3ad..a26e560 100644 (file)
@@ -28,8 +28,6 @@
  */
 class APCUBagOStuff extends APCBagOStuff {
        /**
-        * Constructor
-        *
         * Available parameters are:
         *   - nativeSerialize:     If true, pass objects to apcu_store(), and trust it
         *                          to serialize them correctly. If false, serialize
index c568e7b..e3e66d5 100644 (file)
@@ -29,8 +29,6 @@
 class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
 
        /**
-        * Constructor
-        *
         * Available parameters are:
         *   - servers:             The list of IP:port combinations holding the memcached servers.
         *   - persistent:          Whether to use a persistent connection
index acb4dce..fc50961 100644 (file)
@@ -233,12 +233,13 @@ interface ILoadBalancer {
 
        /**
         * Open a connection to the server given by the specified index
-        * Index must be an actual index into the array.
-        * If the server is already open, returns it.
+        *
+        * The index must be an actual index into the array. If a connection to the server is
+        * already open and not considered an "in use" foreign connection, this simply returns it.
         *
         * @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
         *
-        * @param int $i Server index or DB_MASTER/DB_REPLICA
+        * @param int $i Server index (does not support DB_MASTER/DB_REPLICA)
         * @param string|bool $domain Domain ID, or false for the current domain
         * @return Database|bool Returns false on errors
         * @throws DBAccessError
index 0b70010..72217da 100644 (file)
@@ -41,7 +41,7 @@ use Exception;
 class LoadBalancer implements ILoadBalancer {
        /** @var array[] Map of (server index => server config array) */
        private $mServers;
-       /** @var Database[][][] Map of local/foreignUsed/foreignFree => server index => IDatabase array */
+       /** @var Database[][][] Map of local/foreignUsed/foreignFree => server index => IDatabase[] */
        private $mConns;
        /** @var float[] Map of (server index => weight) */
        private $mLoads;
@@ -126,6 +126,10 @@ class LoadBalancer implements ILoadBalancer {
        /** @var integer Seconds to cache master server read-only status */
        const TTL_CACHE_READONLY = 5;
 
+       const KEY_LOCAL = 'local';
+       const KEY_FOREIGN_FREE = 'foreignFree';
+       const KEY_FOREIGN_INUSE = 'foreignInUse';
+
        public function __construct( array $params ) {
                if ( !isset( $params['servers'] ) ) {
                        throw new InvalidArgumentException( __CLASS__ . ': missing servers parameter' );
@@ -148,9 +152,9 @@ class LoadBalancer implements ILoadBalancer {
 
                $this->mReadIndex = -1;
                $this->mConns = [
-                       'local'       => [],
-                       'foreignUsed' => [],
-                       'foreignFree' => []
+                       self::KEY_LOCAL => [],
+                       self::KEY_FOREIGN_INUSE => [],
+                       self::KEY_FOREIGN_FREE => []
                ];
                $this->mLoads = [];
                $this->mWaitForPos = false;
@@ -711,19 +715,19 @@ class LoadBalancer implements ILoadBalancer {
                }
 
                $domain = $conn->getDomainID();
-               if ( !isset( $this->mConns['foreignUsed'][$serverIndex][$domain] ) ) {
+               if ( !isset( $this->mConns[self::KEY_FOREIGN_INUSE][$serverIndex][$domain] ) ) {
                        throw new InvalidArgumentException( __METHOD__ .
                                ": connection $serverIndex/$domain not found; it may have already been freed." );
-               } elseif ( $this->mConns['foreignUsed'][$serverIndex][$domain] !== $conn ) {
+               } elseif ( $this->mConns[self::KEY_FOREIGN_INUSE][$serverIndex][$domain] !== $conn ) {
                        throw new InvalidArgumentException( __METHOD__ .
                                ": connection $serverIndex/$domain mismatched; it may have already been freed." );
                }
                $conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
                if ( $refCount <= 0 ) {
-                       $this->mConns['foreignFree'][$serverIndex][$domain] = $conn;
-                       unset( $this->mConns['foreignUsed'][$serverIndex][$domain] );
-                       if ( !$this->mConns['foreignUsed'][$serverIndex] ) {
-                               unset( $this->mConns[ 'foreignUsed' ][$serverIndex] ); // clean up
+                       $this->mConns[self::KEY_FOREIGN_FREE][$serverIndex][$domain] = $conn;
+                       unset( $this->mConns[self::KEY_FOREIGN_INUSE][$serverIndex][$domain] );
+                       if ( !$this->mConns[self::KEY_FOREIGN_INUSE][$serverIndex] ) {
+                               unset( $this->mConns[ self::KEY_FOREIGN_INUSE ][$serverIndex] ); // clean up
                        }
                        $this->connLogger->debug( __METHOD__ . ": freed connection $serverIndex/$domain" );
                } else {
@@ -772,8 +776,8 @@ class LoadBalancer implements ILoadBalancer {
 
                if ( $domain !== false ) {
                        $conn = $this->openForeignConnection( $i, $domain );
-               } elseif ( isset( $this->mConns['local'][$i][0] ) ) {
-                       $conn = $this->mConns['local'][$i][0];
+               } elseif ( isset( $this->mConns[self::KEY_LOCAL][$i][0] ) ) {
+                       $conn = $this->mConns[self::KEY_LOCAL][$i][0];
                } else {
                        if ( !isset( $this->mServers[$i] ) || !is_array( $this->mServers[$i] ) ) {
                                throw new InvalidArgumentException( "No server with index '$i'." );
@@ -785,7 +789,7 @@ class LoadBalancer implements ILoadBalancer {
                        $serverName = $this->getServerName( $i );
                        if ( $conn->isOpen() ) {
                                $this->connLogger->debug( "Connected to database $i at '$serverName'." );
-                               $this->mConns['local'][$i][0] = $conn;
+                               $this->mConns[self::KEY_LOCAL][$i][0] = $conn;
                        } else {
                                $this->connLogger->warning( "Failed to connect to database $i at '$serverName'." );
                                $this->errorConnection = $conn;
@@ -830,20 +834,20 @@ class LoadBalancer implements ILoadBalancer {
                $dbName = $domainInstance->getDatabase();
                $prefix = $domainInstance->getTablePrefix();
 
-               if ( isset( $this->mConns['foreignUsed'][$i][$domain] ) ) {
-                       // Reuse an already-used connection
-                       $conn = $this->mConns['foreignUsed'][$i][$domain];
+               if ( isset( $this->mConns[self::KEY_FOREIGN_INUSE][$i][$domain] ) ) {
+                       // Reuse an in-use connection for the same domain that is not in-use
+                       $conn = $this->mConns[self::KEY_FOREIGN_INUSE][$i][$domain];
                        $this->connLogger->debug( __METHOD__ . ": reusing connection $i/$domain" );
-               } elseif ( isset( $this->mConns['foreignFree'][$i][$domain] ) ) {
-                       // Reuse a free connection for the same domain
-                       $conn = $this->mConns['foreignFree'][$i][$domain];
-                       unset( $this->mConns['foreignFree'][$i][$domain] );
-                       $this->mConns['foreignUsed'][$i][$domain] = $conn;
+               } elseif ( isset( $this->mConns[self::KEY_FOREIGN_FREE][$i][$domain] ) ) {
+                       // Reuse a free connection for the same domain that is not in-use
+                       $conn = $this->mConns[self::KEY_FOREIGN_FREE][$i][$domain];
+                       unset( $this->mConns[self::KEY_FOREIGN_FREE][$i][$domain] );
+                       $this->mConns[self::KEY_FOREIGN_INUSE][$i][$domain] = $conn;
                        $this->connLogger->debug( __METHOD__ . ": reusing free connection $i/$domain" );
-               } elseif ( !empty( $this->mConns['foreignFree'][$i] ) ) {
+               } elseif ( !empty( $this->mConns[self::KEY_FOREIGN_FREE][$i] ) ) {
                        // Reuse a connection from another domain
-                       $conn = reset( $this->mConns['foreignFree'][$i] );
-                       $oldDomain = key( $this->mConns['foreignFree'][$i] );
+                       $conn = reset( $this->mConns[self::KEY_FOREIGN_FREE][$i] );
+                       $oldDomain = key( $this->mConns[self::KEY_FOREIGN_FREE][$i] );
                        // The empty string as a DB name means "don't care".
                        // DatabaseMysqlBase::open() already handle this on connection.
                        if ( strlen( $dbName ) && !$conn->selectDB( $dbName ) ) {
@@ -853,8 +857,8 @@ class LoadBalancer implements ILoadBalancer {
                                $conn = false;
                        } else {
                                $conn->tablePrefix( $prefix );
-                               unset( $this->mConns['foreignFree'][$i][$oldDomain] );
-                               $this->mConns['foreignUsed'][$i][$domain] = $conn;
+                               unset( $this->mConns[self::KEY_FOREIGN_FREE][$i][$oldDomain] );
+                               $this->mConns[self::KEY_FOREIGN_INUSE][$i][$domain] = $conn;
                                $this->connLogger->debug( __METHOD__ .
                                        ": reusing free connection from $oldDomain for $domain" );
                        }
@@ -874,7 +878,7 @@ class LoadBalancer implements ILoadBalancer {
                                $conn = false;
                        } else {
                                $conn->tablePrefix( $prefix );
-                               $this->mConns['foreignUsed'][$i][$domain] = $conn;
+                               $this->mConns[self::KEY_FOREIGN_INUSE][$i][$domain] = $conn;
                                $this->connLogger->debug( __METHOD__ . ": opened new connection for $i/$domain" );
                        }
                }
@@ -1085,9 +1089,9 @@ class LoadBalancer implements ILoadBalancer {
                } );
 
                $this->mConns = [
-                       'local' => [],
-                       'foreignFree' => [],
-                       'foreignUsed' => [],
+                       self::KEY_LOCAL => [],
+                       self::KEY_FOREIGN_FREE => [],
+                       self::KEY_FOREIGN_INUSE => [],
                ];
                $this->connsOpened = 0;
        }
@@ -1621,13 +1625,19 @@ class LoadBalancer implements ILoadBalancer {
        }
 
        public function setDomainPrefix( $prefix ) {
-               if ( $this->mConns['foreignUsed'] ) {
-                       // Do not switch connections to explicit foreign domains unless marked as free
-                       $domains = [];
-                       foreach ( $this->mConns['foreignUsed'] as $i => $connsByDomain ) {
-                               $domains = array_merge( $domains, array_keys( $connsByDomain ) );
+               // Find connections to explicit foreign domains still marked as in-use...
+               $domainsInUse = [];
+               $this->forEachOpenConnection( function ( IDatabase $conn ) use ( &$domainsInUse ) {
+                       // Once reuseConnection() is called on a handle, its reference count goes from 1 to 0.
+                       // Until then, it is still in use by the caller (explicitly or via DBConnRef scope).
+                       if ( $conn->getLBInfo( 'foreignPoolRefCount' ) > 0 ) {
+                               $domainsInUse[] = $conn->getDomainID();
                        }
-                       $domains = implode( ', ', $domains );
+               } );
+
+               // Do not switch connections to explicit foreign domains unless marked as safe
+               if ( $domainsInUse ) {
+                       $domains = implode( ', ', $domainsInUse );
                        throw new DBUnexpectedError( null,
                                "Foreign domain connections are still in use ($domains)." );
                }
index f2b1670..faca5bc 100644 (file)
@@ -72,8 +72,6 @@ class LogPage {
        private $target;
 
        /**
-        * Constructor
-        *
         * @param string $type One of '', 'block', 'protect', 'rights', 'delete',
         *   'upload', 'move'
         * @param bool $rc Whether to update recent changes as well as the logging table
index 11dce31..f79fcfa 100644 (file)
@@ -49,8 +49,6 @@ class LogPager extends ReverseChronologicalPager {
        public $mLogEventsList;
 
        /**
-        * Constructor
-        *
         * @param LogEventsList $list
         * @param string|array $types Log types to show
         * @param string $performer The user who made the log entries
index 57b5b36..d25111c 100644 (file)
@@ -40,8 +40,6 @@ class DjVuImage {
        const DJVUTXT_MEMORY_LIMIT = 300000;
 
        /**
-        * Constructor
-        *
         * @param string $filename The DjVu file name.
         */
        function __construct( $filename ) {
index 9bfbc96..c355a06 100644 (file)
@@ -96,8 +96,6 @@ class Exif {
        private $byteOrder;
 
        /**
-        * Constructor
-        *
         * @param string $file Filename.
         * @param string $byteOrder Type of byte ordering either 'BE' (Big Endian)
         *   or 'LE' (Little Endian). Default ''.
index 2cf4d23..9b22cbe 100644 (file)
@@ -58,8 +58,6 @@ class SVGReader {
        private $languagePrefixes = [];
 
        /**
-        * Constructor
-        *
         * Creates an SVGReader drawing from the source provided
         * @param string $source URI from which to read
         * @throws MWException|Exception
index 96a4368..73a9927 100644 (file)
@@ -927,7 +927,6 @@ class ParserOptions {
        }
 
        /**
-        * Constructor
         * @warning For interaction with the parser cache, use
         *  WikiPage::makeParserOptions(), ContentHandler::makeParserOptions(), or
         *  ParserOptions::newCanonical() instead.
index ddf084e..20b0780 100644 (file)
@@ -31,7 +31,6 @@ abstract class ProfilerOutput {
        protected $params = [];
 
        /**
-        * Constructor
         * @param Profiler $collector The actual profiler
         * @param array $params Configuration array, passed down from $wgProfiler
         */
index 197ac51..06f9841 100644 (file)
@@ -149,9 +149,7 @@ class ResourceLoaderClientHtml {
                                continue;
                        }
 
-                       $group = $module->getGroup();
-
-                       if ( $group === 'private' ) {
+                       if ( $module->shouldEmbedModule( $this->context ) ) {
                                // Embed via mw.loader.implement per T36907.
                                $data['embed']['general'][] = $name;
                                // Avoid duplicate request from mw.loader
@@ -186,7 +184,7 @@ class ResourceLoaderClientHtml {
                                // Avoid needless request for empty module
                                $data['states'][$name] = 'ready';
                        } else {
-                               if ( $group === 'private' ) {
+                               if ( $module->shouldEmbedModule( $this->context ) ) {
                                        // Embed via style element
                                        $data['embed']['styles'][] = $name;
                                        // Avoid duplicate request from mw.loader
@@ -392,62 +390,75 @@ class ResourceLoaderClientHtml {
                foreach ( $sortedModules as $source => $groups ) {
                        foreach ( $groups as $group => $grpModules ) {
                                $context = self::makeContext( $mainContext, $group, $only, $extraQuery );
-                               $context->setModules( array_keys( $grpModules ) );
-
-                               if ( $group === 'private' ) {
-                                       // Decide whether to use style or script element
-                                       if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
-                                               $chunks[] = Html::inlineStyle(
-                                                       $rl->makeModuleResponse( $context, $grpModules )
-                                               );
-                                       } else {
-                                               $chunks[] = ResourceLoader::makeInlineScript(
-                                                       $rl->makeModuleResponse( $context, $grpModules )
-                                               );
-                                       }
-                                       continue;
-                               }
-
-                               // See if we have one or more raw modules
-                               $isRaw = false;
-                               foreach ( $grpModules as $key => $module ) {
-                                       $isRaw |= $module->isRaw();
-                               }
 
-                               // Special handling for the user group; because users might change their stuff
-                               // on-wiki like user pages, or user preferences; we need to find the highest
-                               // timestamp of these user-changeable modules so we can ensure cache misses on change
-                               // This should NOT be done for the site group (T29564) because anons get that too
-                               // and we shouldn't be putting timestamps in CDN-cached HTML
-                               if ( $group === 'user' ) {
-                                       // Must setModules() before makeVersionQuery()
-                                       $context->setVersion( $rl->makeVersionQuery( $context ) );
+                               // Separate sets of linked and embedded modules while preserving order
+                               $moduleSets = [];
+                               $idx = -1;
+                               foreach ( $grpModules as $name => $module ) {
+                                       $shouldEmbed = $module->shouldEmbedModule( $context );
+                                       if ( !$moduleSets || $moduleSets[$idx][0] !== $shouldEmbed ) {
+                                               $moduleSets[++$idx] = [ $shouldEmbed, [] ];
+                                       }
+                                       $moduleSets[$idx][1][$name] = $module;
                                }
 
-                               $url = $rl->createLoaderURL( $source, $context, $extraQuery );
-
-                               // Decide whether to use 'style' or 'script' element
-                               if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
-                                       $chunk = Html::linkedStyle( $url );
-                               } else {
-                                       if ( $context->getRaw() || $isRaw ) {
-                                               $chunk = Html::element( 'script', [
-                                                       // In SpecialJavaScriptTest, QUnit must load synchronous
-                                                       'async' => !isset( $extraQuery['sync'] ),
-                                                       'src' => $url
-                                               ] );
+                               // Link/embed each set
+                               foreach ( $moduleSets as list( $embed, $moduleSet ) ) {
+                                       $context->setModules( array_keys( $moduleSet ) );
+                                       if ( $embed ) {
+                                               // Decide whether to use style or script element
+                                               if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
+                                                       $chunks[] = Html::inlineStyle(
+                                                               $rl->makeModuleResponse( $context, $moduleSet )
+                                                       );
+                                               } else {
+                                                       $chunks[] = ResourceLoader::makeInlineScript(
+                                                               $rl->makeModuleResponse( $context, $moduleSet )
+                                                       );
+                                               }
                                        } else {
-                                               $chunk = ResourceLoader::makeInlineScript(
-                                                       Xml::encodeJsCall( 'mw.loader.load', [ $url ] )
-                                               );
+                                               // See if we have one or more raw modules
+                                               $isRaw = false;
+                                               foreach ( $moduleSet as $key => $module ) {
+                                                       $isRaw |= $module->isRaw();
+                                               }
+
+                                               // Special handling for the user group; because users might change their stuff
+                                               // on-wiki like user pages, or user preferences; we need to find the highest
+                                               // timestamp of these user-changeable modules so we can ensure cache misses on change
+                                               // This should NOT be done for the site group (T29564) because anons get that too
+                                               // and we shouldn't be putting timestamps in CDN-cached HTML
+                                               if ( $group === 'user' ) {
+                                                       // Must setModules() before makeVersionQuery()
+                                                       $context->setVersion( $rl->makeVersionQuery( $context ) );
+                                               }
+
+                                               $url = $rl->createLoaderURL( $source, $context, $extraQuery );
+
+                                               // Decide whether to use 'style' or 'script' element
+                                               if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
+                                                       $chunk = Html::linkedStyle( $url );
+                                               } else {
+                                                       if ( $context->getRaw() || $isRaw ) {
+                                                               $chunk = Html::element( 'script', [
+                                                                       // In SpecialJavaScriptTest, QUnit must load synchronous
+                                                                       'async' => !isset( $extraQuery['sync'] ),
+                                                                       'src' => $url
+                                                               ] );
+                                                       } else {
+                                                               $chunk = ResourceLoader::makeInlineScript(
+                                                                       Xml::encodeJsCall( 'mw.loader.load', [ $url ] )
+                                                               );
+                                                       }
+                                               }
+
+                                               if ( $group == 'noscript' ) {
+                                                       $chunks[] = Html::rawElement( 'noscript', [], $chunk );
+                                               } else {
+                                                       $chunks[] = $chunk;
+                                               }
                                        }
                                }
-
-                               if ( $group == 'noscript' ) {
-                                       $chunks[] = Html::rawElement( 'noscript', [], $chunk );
-                               } else {
-                                       $chunks[] = $chunk;
-                               }
                        }
                }
 
index 1c767fa..1608901 100644 (file)
@@ -918,6 +918,20 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
                return false;
        }
 
+       /**
+        * Check whether this module should be embeded rather than linked
+        *
+        * Modules returning true here will be embedded rather than loaded by
+        * ResourceLoaderClientHtml.
+        *
+        * @since 1.30
+        * @param ResourceLoaderContext $context
+        * @return bool
+        */
+       public function shouldEmbedModule( ResourceLoaderContext $context ) {
+               return $this->getGroup() === 'private';
+       }
+
        /** @var JSParser Lazy-initialized; use self::javaScriptParser() */
        private static $jsParser;
        private static $parseCacheVersion = 1;
index 1d7a4a3..643c2c1 100644 (file)
@@ -35,7 +35,6 @@ class SearchDatabase extends SearchEngine {
        protected $db;
 
        /**
-        * Constructor
         * @param IDatabase $db The database to search from
         */
        public function __construct( IDatabase $db = null ) {
index e7c9423..9028787 100644 (file)
@@ -28,9 +28,6 @@
  */
 class SpecialActiveUsers extends SpecialPage {
 
-       /**
-        * Constructor
-        */
        public function __construct() {
                parent::__construct( 'Activeusers' );
        }
index 4056709..9e66447 100644 (file)
@@ -33,9 +33,6 @@ class SpecialAllMessages extends SpecialPage {
         */
        protected $table;
 
-       /**
-        * Constructor
-        */
        public function __construct() {
                parent::__construct( 'Allmessages' );
        }
index 17f6cca..4d84e31 100644 (file)
@@ -44,8 +44,6 @@ class SpecialAllPages extends IncludableSpecialPage {
        protected $nsfromMsg = 'allpagesfrom';
 
        /**
-        * Constructor
-        *
         * @param string $name Name of the special page, as seen in links and URLs (default: 'Allpages')
         */
        function __construct( $name = 'Allpages' ) {
index a2930fc..a827e89 100644 (file)
@@ -46,9 +46,6 @@ class SpecialImport extends SpecialPage {
        private $pageLinkDepth;
        private $importSources;
 
-       /**
-        * Constructor
-        */
        public function __construct() {
                parent::__construct( 'Import', 'import' );
        }
index 1a8dccf..dee2968 100644 (file)
@@ -29,9 +29,7 @@
  * @ingroup SpecialPage
  */
 class SpecialListUsers extends IncludableSpecialPage {
-       /**
-        * Constructor
-        */
+
        public function __construct() {
                parent::__construct( 'Listusers' );
        }
index 15bbffd..c9c2475 100644 (file)
@@ -669,6 +669,15 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                                [ 'class' => 'rcfilters-container' ]
                        );
 
+                       $loadingContainer = Html::rawElement(
+                               'div',
+                               [ 'class' => 'rcfilters-spinner' ],
+                               Html::element(
+                                       'div',
+                                       [ 'class' => 'rcfilters-spinner-bounce' ]
+                               )
+                       );
+
                        // Wrap both with rcfilters-head
                        $this->getOutput()->addHTML(
                                Html::rawElement(
@@ -677,6 +686,9 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                                        $rcfilterContainer . $rcoptions
                                )
                        );
+
+                       // Add spinner
+                       $this->getOutput()->addHTML( $loadingContainer );
                } else {
                        $this->getOutput()->addHTML( $rcoptions );
                }
index 073e58d..4cdc78f 100644 (file)
@@ -33,7 +33,6 @@ use MediaWiki\MediaWikiServices;
  */
 class SpecialUpload extends SpecialPage {
        /**
-        * Constructor : initialise object
         * Get data POSTed through the form and assign them to the object
         * @param WebRequest $request Data posted.
         */
index dbcf568..a797398 100644 (file)
@@ -81,8 +81,6 @@ class RemexCompatMunger implements TreeHandler {
        ];
 
        /**
-        * Constructor
-        *
         * @param Serializer $serializer
         */
        public function __construct( Serializer $serializer ) {
index e51a8ed..8dfe00f 100644 (file)
@@ -38,8 +38,6 @@ class ConverterRule {
        public $mUnidtable = [];// array of the translation in each variant
 
        /**
-        * Constructor
-        *
         * @param string $text The text between -{ and }-
         * @param LanguageConverter $converter
         */
index 870d7b7..37fadac 100644 (file)
        "rcfilters-legend-heading": "<strong>Llista d'abreviatures:</strong>",
        "rcfilters-activefilters": "Filtros activos",
        "rcfilters-advancedfilters": "Filtros avanzaos",
+       "rcfilters-limit-title": "Cambios a amosar",
+       "rcfilters-limit-shownum": "Amosar los últimos $1 cambios",
+       "rcfilters-days-title": "Últimos díes",
+       "rcfilters-hours-title": "Últimes hores",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|día|díes}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|hora|hores}}",
        "rcfilters-quickfilters": "Filtros guardaos",
        "rcfilters-quickfilters-placeholder-title": "Entá nun se guardaron enllaces",
        "rcfilters-quickfilters-placeholder-description": "Pa guardar les preferencies del filtru y volver a usales sero, pulsia nel iconu del marcador del área de Filtru Activu más abaxo.",
        "rcfilters-invalid-filter": "Filtru inválidu",
        "rcfilters-empty-filter": "Nun hai filtros activos. Amuésense toles contribuciones.",
        "rcfilters-filterlist-title": "Filtros",
-       "rcfilters-filterlist-whatsthis": "¿Qué ye esto?",
+       "rcfilters-filterlist-whatsthis": "¿Como funciona esto?",
        "rcfilters-filterlist-feedbacklink": "Comentar sobro los nuevos filtros (beta)",
        "rcfilters-highlightbutton-title": "Resaltar resultaos",
        "rcfilters-highlightmenu-title": "Seleiciona un color",
        "rcfilters-filter-editsbyself-description": "Contribuciones de to.",
        "rcfilters-filter-editsbyother-label": "Cambios d'otros",
        "rcfilters-filter-editsbyother-description": "Tolos cambios menos los de to.",
-       "rcfilters-filtergroup-userExpLevel": "Nivel d'esperiencia (solo pa usuarios rexistraos)",
+       "rcfilters-filtergroup-userExpLevel": "Rexistru d'usuarios y esperiencia",
        "rcfilters-filter-user-experience-level-registered-label": "Rexistraos",
        "rcfilters-filter-user-experience-level-registered-description": "Editores coneutaos.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non rexistraos",
-       "rcfilters-filter-user-experience-level-unregistered-description": "Editores ensin coneutar.",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Editores que nun tán coneutaos.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Recién llegaos",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Menos de 10 ediciones y 4 díes d'actividá.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Editores rexistraos con menos de 10 ediciones y 4 díes d'actividá.",
        "rcfilters-filter-user-experience-level-learner-label": "Aprendices",
-       "rcfilters-filter-user-experience-level-learner-description": "Más esperiencia que los «Recién llegaos», pero menos que los «Usuarios espertos».",
+       "rcfilters-filter-user-experience-level-learner-description": "Editores rexistraos con esperiencia ente «Recién llegaos» y «Usuarios espertos».",
        "rcfilters-filter-user-experience-level-experienced-label": "Usuarios espertos",
-       "rcfilters-filter-user-experience-level-experienced-description": "Más de 30 díes d'actividá y 500 ediciones.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Editores rexistraos con más de 500 ediciones y 30 díes d'actividá.",
        "rcfilters-filtergroup-automated": "Contribuciones automátiques",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-bots-description": "Ediciones feches con ferramientes automátiques.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "El filtru «Ediciones menores» fai conflictu con un filtru «Tipu de cambiu» o más, porque dellos tipos de cambiu nun pueden designase como «menores». Los filtros que faen conflictu tan marcaos nel área de Filtros Activos, más arriba.",
        "rcfilters-hideminor-conflicts-typeofchange": "Dellos tipos de cambiu nun pueden designase como «menores», de manera qu'esti filtru fai conflictu colos siguientes filtros «Tipu de cambiu»: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Esti filtru de «Tipu de cambiu» fai conflictu col filtru «Ediciones menores». Dellos tipos de cambiu nun pueden designase como «menores».",
-       "rcfilters-filtergroup-lastRevision": "Última revisión",
+       "rcfilters-filtergroup-lastRevision": "Últimes revisiones",
        "rcfilters-filter-lastrevision-label": "Última revisión",
-       "rcfilters-filter-lastrevision-description": "El cambio más recien d'una páxina.",
-       "rcfilters-filter-previousrevision-label": "Revisiones anteriores",
-       "rcfilters-filter-previousrevision-description": "Tolos cambios que nun son los más recien d'una páxina.",
+       "rcfilters-filter-lastrevision-description": "Sólo el cambiu más recien d'una páxina.",
+       "rcfilters-filter-previousrevision-label": "Non la cabera revisión",
+       "rcfilters-filter-previousrevision-description": "Tolos cambios que nun son la «cabera revisión».",
        "rcfilters-filter-excluded": "Escluíu",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:non</strong> $1",
+       "rcfilters-exclude-button-off": "Torgar los seleicionaos",
+       "rcfilters-exclude-button-on": "Torgando los seleicionaos",
        "rcfilters-view-tags": "Ediciones etiquetaes",
        "rcfilters-view-namespaces-tooltip": "Filtriar los resultaos por espaciu de nomes",
        "rcfilters-view-tags-tooltip": "Filtriar los resultaos usando les etiquetes d'edición",
        "delete-warning-toobig": "Esta páxina tien un historial d'ediciones grande, más de $1 {{PLURAL:$1|revisión|revisiones}}.\nEsborralu pue perturbar les operaciones de la base de datos de {{SITENAME}};\nobra con precaución.",
        "deleteprotected": "Nun pues desaniciar esta páxina porque ta protexida.",
        "deleting-backlinks-warning": "<strong>Avisu:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Otres páxines]] enllacen a, o trescluyen de, la páxina que tas a piques de desaniciar.",
+       "deleting-subpages-warning": "<strong>Avisu:</strong> La páxina que vas desaniciar tien [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|una subpáxina|$1 subpáxines|51=más de 50 subpáxines}}]].",
        "rollback": "Revertir ediciones",
        "rollbacklink": "revertir",
        "rollbacklinkcount": "revertir $1 {{PLURAL:$1|edición|ediciones}}",
index 44e67df..84d105b 100644 (file)
        "botpasswords-updated-body": "$1 роботы өсөн $2 ҡулланыусыһы серһүҙе яңыртылды.",
        "botpasswords-deleted-title": "Робот серһүҙе юйылды.",
        "botpasswords-deleted-body": "$1 роботы өсөн $2 ҡулланыусыһы серһүҙе юйылды.",
-       "botpasswords-newpassword": "Ð\98неү Ó©Ñ\81өн Ñ\8fÒ£Ñ\8b Ñ\81еÑ\80Ò»Ò¯Ò\99 <strong>$1</strong> â\80\94 <strong>$2</strong>. <em>Ð\90Ñ\80Ñ\82абан Ò¡Ñ\83лланÑ\8bÑ\83 Ó©Ñ\81өн Ñ\8fÒ»Ñ\8bп Ð°Ð»Ñ\8bÒ\93Ñ\8bÒ\99.</em><strong>$3</strong> Ò¡Ð°Ñ\82наÑ\88Ñ\8bÑ\83Ñ\81Ñ\8b Ð¸Ñ\81еме <strong>$4</strong> Ð¿Ð°Ñ\80олÑ\8c Ñ\81иÑ\84аÑ\82Ñ\8b)",
+       "botpasswords-newpassword": "Ð\98неү Ó©Ñ\81өн Ñ\8fÒ£Ñ\8b Ñ\81еÑ\80Ò»Ò¯Ò\99 <strong>$1</strong> â\80\94 <strong>$2</strong>. <em>Ð\90Ñ\80Ñ\82абан Ò¡Ñ\83лланÑ\8bÑ\83 Ó©Ñ\81өн Ñ\8fÒ\99Ñ\8bп Ð°Ð»Ñ\8bÒ\93Ñ\8bÒ\99.</em> <br /> (Ð\98Ò«Ó\99п Ñ\8fÒ\99маһÑ\8b Ð¼ÐµÐ½Ó\99н Ò¡Ð°Ñ\82наÑ\88Ñ\8bÑ\83Ñ\81Ñ\8bнÑ\8bÒ£ Ð¸Ñ\81еме Ð±ÐµÑ\80 Ð±Ñ\83лÑ\8bÑ\83Ñ\8bн Ñ\82алап Ð¸Ñ\82кÓ\99н Ð¸Ò«ÐºÐµ Ð±Ð¾Ñ\82Ñ\82аÑ\80 Ó©Ñ\81өн, <strong>$3</strong> Ò¡Ð°Ñ\82наÑ\88Ñ\8bÑ\83Ñ\81Ñ\8b Ð¸Ñ\81еме Ð¸Ñ\82еп Ò»Ó\99м <strong>$4</strong> Ñ\81еÑ\80Ò»Ò¯Ò\99 Ð¸Ñ\82еп Ò¡Ñ\83ллана Ð°Ð»Ð°Ò»Ñ\8bÒ\93Ñ\8bÒ\99.)",
        "botpasswords-no-provider": "BotPasswordsSessionProvider ғәмәлдә түгел.",
        "botpasswords-restriction-failed": "Робот серһүҙе менән бәйле сәбәптәр булғанға инеү башҡарылманы.",
        "botpasswords-invalid-name": "Күрһәтелгән ҡулланыусы исемендә робот $1 серһүҙен бүлеүсе тамға юҡ.",
        "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": "Электрон почта адресын үҙгәртеү",
        "changeemail-no-info": "Был биткә туранан ирешеү өсөн һеҙгә системала танылыу кәрәк.",
        "preview": "Ҡарап сығыу",
        "showpreview": "Ҡарап сығырға",
        "showdiff": "Индерелгән үҙгәрештәр",
-       "blankarticle": "<strong>Иҫкәртеү:</strong> Һеҙ булдырасаҡ бит буш.\nӘгәр тағы ла «$1» кнопкаға баҫһағыҙ, шул уҡ йөкмәткеле бит  яңынан барлыҡҡа киләсәк.",
+       "blankarticle": "<strong>Иҫкәртеү:</strong> Һеҙ булдырасаҡ бит буш.\nӘгәр тағы ла «$1» төймәһенә баҫһағыҙ, йөкмәткеһеҙ бит барлыҡҡа киләсәк.",
        "anoneditwarning": "<strong>Иғтибар!</strong> Һеҙ сайтта теркәлмәнегеҙ. Әгәр ҙә һеҙ ниндәй ҙә булһа төҙәтмәләр  йәки үҙгәртүҙәр индерһәгеҙ, һеҙҙең IP-адрес башҡаларға ла күрһәтеләсәк. Сайтҡа <strong>[$1 керһәгеҙ]</strong> йәки <strong>[$2 ҡуллануысы яҙмаһын төҙөһәгеҙ]</strong>, һеҙ индергән үҙгәртеүҙәр һеҙҙең ҡулланыусы яҙмағыҙға бәйләнгән була, шулай уҡ башҡа мөмкинлектәр ҙә тыуасаҡ.",
        "anonpreviewwarning": "''Һеҙ танылмағанһығыҙ. Яҙҙырыу ваҡытында IP-адресығыҙ был биттең үҙгәртеүҙәр тарихына яҙыласаҡ.''",
        "missingsummary": "'''Иҫкәртеү.''' Һеҙ үҙгәртеүҙергә ҡыҫҡа тасуирлама яҙманығыҙ. Ҡабаттан «Битте һаҡларға» төймәһенә баҫһағыҙ, үҙгәртеүҙәрегеҙ тасуирламаһыҙ һаҡланасаҡ.",
        "selfredirect": "<strong>Иғтибар:</strong> Һеҙ шул уҡ мәҡәләгә йүнәлтеү эшләйһегеҙ.\n «$1» төәмәһенә баҫһағыҙ тағы шул биткә йүнәлтеләсәк.",
        "missingcommenttext": "Зинһар, аҫҡа үҙ тасуирламағыҙҙы керетегеҙ.",
        "missingcommentheader": "'''Иҫкәртеү:''' Һеҙ был комментарий өсөн тема/исем яҙманығыҙ.\n«$1» төймәһенә ҡабат баҫыу менән үҙгәртеүҙерегеҙ исемһеҙ яҙыласаҡ.",
-       "summary-preview": "Буласаҡ тасуирлама:",
-       "subject-preview": "Тема/башлыҡты алдан ҡарау:",
+       "summary-preview": "Үҙгәртеүҙәр аңлатмаһын ҡарап сығыу:",
+       "subject-preview": "Теманы/баш исемде алдан ҡарау:",
        "previewerrortext": "Алдан ҡарау ваҡытында хата китте.",
        "blockedtitle": "Ҡулланыусы блокланған",
        "blockedtext": "'''Иҫәп яҙыуығыҙ йәки IP-адресығыҙ блокланған.'''\n\nБлоклаусы хаким: $1.\nБелдерелгән сәбәп: ''$2''.\n\n* Блоклау башланған ваҡыт: $8\n* Блоклау  аҙағы: $6\n* Блоклауҙар һаны: $7\n\nҺеҙ $1 йәки башҡа [[{{MediaWiki:Grouppage-sysop}}|хакимгә]] блоклау буйынса һорауҙарығыҙҙы ебәрә алаһығыҙ.\nИҫегеҙҙе тотоғоҙ: әгәр һеҙ теркәлмәгән һәм электрон почта адресығыҙҙы раҫламаған булһағыҙ ([[Special:Preferences|көйләүҙәрем битендә]]), хакимгә хат ебәрә алмайһығыҙ. Шулай ук блоклау ваҡытында һеҙҙең хат ебәреү мөмкинлегегеҙ сикләгән булырға ла мөмкин.\nҺеҙҙең IP-адрес — $3, блоклау идентификаторы — #$5.\nХаттарҙа был мәғлүмәттәрҙе күрһәтергә онотмағыҙ.",
        "readonlywarning": "<strong>КИҪӘТЕҮ: Техник хеҙмәтләндереү сәбәпле мәғлүмәттәр базаһы блокланған, шунлыҡтан үҙгәртеүҙәрегеҙҙе хәҙер һаҡлай алмайһығыҙ.<strong>\nТексты аҙаҡтан ҡулланыу өсөн башҡа файлда һаҡлап тора алаһығыҙ.\n\nХаким белдергән сәбәп: $1",
        "protectedpagewarning": "'''КИҪӘТЕҮ: Һеҙ был битте үҙгәртә алмайһығыҙ, был хоҡуҡҡа хакимдәр генә эйә.'''\nБелешмә өсөн түбәндә һуңғы үҙгәртеү тураһында мәғлүмәт бирелә:",
        "semiprotectedpagewarning": "'''Киҫәтеү:''' был бит һаҡланған. Уны теркәлгән ҡулланыусылар ғына үҙгәртә ала.\nБелешмә өсөн түбәндә һуңғы үҙгәртеү тураһында мәғлүмәт бирелә:",
-       "cascadeprotectedwarning": "<strong>Киҫәтеү:</strong> Был битте тик хакимдәр генә үҙгәртә ала.  Сөнки бит {{PLURAL:$1|каскадлы яҡлау исемлегенә индерелгән}}:",
+       "cascadeprotectedwarning": "<strong>Киҫәтеү:</strong> Был битте тик [[Special:ListGroupRights|махсус хоҡуҡлы]] ҡатнашыусылар ғына үҙгәртә ала.  Сөнки бит {{PLURAL:$1|1=түбәндәге каскадлы яҡлау битенә индерелгән}}:",
        "titleprotectedwarning": "'''Киҫәтеү: Бындый исемле бит һаҡланған, уны үҙгәртеү өсөн [[Special:ListGroupRights|тейешле хоҡуҡҡа]] эйә булыу кәрәк.'''\nБелешмә өсөн түбәндә һуңғы үҙгәртеү тураһында мәғлүмәт бирелә:",
        "templatesused": "Был биттә ҡулланылған {{PLURAL:$1|1=ҡалып|ҡалыптар}}:",
        "templatesusedpreview": "Алдан ҡаралған биттә ҡулланылған {{PLURAL:$1|1=ҡалып|ҡалыптар}}:",
        "invalid-content-data": "Тыйылған мәғлүмәт",
        "content-not-allowed-here": "\"$1\" эстәлеге [[$2]] бит өсөн ярамай",
        "editwarning-warning": "Икенсе биткә күсеү һеҙ индергән үҙгәрештәрҙең юғалыуына килтереүе мөмкин.\nӘгәр системала танылыу үтһәгеҙ, көйләүҙәрегеҙ битенең \"Мөхәррирләү\" бүлегендә был киҫәтеүҙе һүндерә алаһығыҙ.",
+       "editpage-invalidcontentmodel-title": "Йөкмәтке форматы ҡабул ителмәй",
        "editpage-notsupportedcontentformat-title": "Йөкмәтке форматы асылмай",
        "editpage-notsupportedcontentformat-text": "$1 эстәлеге форматы $2 моделе форматы менән тап килмәй.",
        "content-model-wikitext": "викитекст",
index 989a466..cd48a7c 100644 (file)
        "rcfilters-activefilters": "Актыўныя фільтры",
        "rcfilters-advancedfilters": "Пашыраныя фільтры",
        "rcfilters-limit-title": "Паказаць зьменаў",
+       "rcfilters-limit-shownum": "Паказаць апошнія $1 зьменаў",
+       "rcfilters-days-title": "Апошнія дні",
        "rcfilters-quickfilters": "Захаваныя фільтры",
        "rcfilters-quickfilters-placeholder-title": "Спасылкі яшчэ не захаваныя",
        "rcfilters-quickfilters-placeholder-description": "Каб захаваць налады вашага фільтру і выкарыстаць іх пазьней, націсьніце на выяву закладкі ў зоне актыўнага фільтру ніжэй.",
        "rcfilters-filter-editsbyself-description": "Ваш уласны ўнёсак.",
        "rcfilters-filter-editsbyother-label": "Зьмены, зробленыя іншымі",
        "rcfilters-filter-editsbyother-description": "Усе зьмены, за выключэньнем вашых.",
-       "rcfilters-filtergroup-userExpLevel": "УзÑ\80овенÑ\8c Ð´Ð¾Ñ\81Ñ\8cведÑ\83 (Ñ\82олÑ\8cкÑ\96 Ð´Ð»Ñ\8f Ð·Ð°Ñ\80Ñ\8dгÑ\96Ñ\81Ñ\82Ñ\80аванÑ\8bÑ\85 Ñ\83дзелÑ\8cнÑ\96каÑ\9e)",
+       "rcfilters-filtergroup-userExpLevel": "РÑ\8dгÑ\96Ñ\81Ñ\82Ñ\80аÑ\86Ñ\8bÑ\8f Ñ\9eдзелÑ\8cнÑ\96каÑ\9e Ñ\96 Ð´Ð¾Ñ\81Ñ\8cвед",
        "rcfilters-filter-user-experience-level-registered-label": "Зарэгістраваныя",
        "rcfilters-filter-user-experience-level-registered-description": "Рэдактары, якія ўвайшлі ў сыстэму.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Незарэгістраваныя",
index 1190fab..031eabb 100644 (file)
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (гл. асобна [[Special:NewPages|новыя старонкі]])",
        "recentchanges-submit": "Паказаць",
        "rcfilters-activefilters": "Актыўныя фільтры",
+       "rcfilters-days-title": "Апошнія дні",
+       "rcfilters-hours-title": "Апошнія гадзіны",
        "rcfilters-savedqueries-rename": "Перайменаваць",
        "rcfilters-savedqueries-setdefault": "Устанавіць прадвызначаным",
        "rcfilters-savedqueries-unsetdefault": "Зняць прадвызначэнне",
        "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-learner-description": "Болей дзён актыўнасці і правак, чым у «навічкоў», але меней чым у «дасведчаных удзельнікаў».",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Зарэгістраваныя рэдактары з менш за 10 правак і 4 дзён актыўнасці.",
+       "rcfilters-filter-user-experience-level-learner-description": "Зарэгістраваныя рэдактары, вопыт якіх знаходзіцца паміж «навічкамі» і «дасведчанымі удзельнікамі».",
        "rcfilters-filter-user-experience-level-experienced-description": "Зарэгістраваныя рэдактары з больш за 500 правак і 30 дзён актыўнасці.",
        "rcfilters-filter-bots-label": "Бот",
        "rcfilters-filter-humans-label": "Чалавек (не бот)",
index 8b8e77f..d150323 100644 (file)
        "anontalk": "Păng-gōng",
        "navigation": "Īng-dô̤:",
        "and": "&#32;gâe̤ng",
-       "qbfind": "討",
-       "qbbrowse": "覷蜀覷",
-       "qbedit": "修改",
-       "qbpageoptions": "茲蜀頁",
-       "qbmyoptions": "我其頁面",
        "faq": "真稠碰著其問題",
-       "faqpage": "Project:稠問其問題",
        "actions": "動作",
        "namespaces": "Miàng-kŭng-găng",
        "variants": "Biéng-tā̤",
        "edit-local": "編輯當地描述",
        "create": "創建",
        "create-local": "添加當地描述",
-       "editthispage": "修改茲頁",
-       "create-this-page": "創建茲蜀頁",
        "delete": "刪除",
-       "deletethispage": "刪除茲頁",
-       "undeletethispage": "恢復茲蜀頁",
        "undelete_short": "恢復$1回修改{{PLURAL:$1}}",
        "viewdeleted_short": "覷蜀覷$1回刪掉其修改{{PLURAL:$1}}",
        "protect": "保護",
        "protect_change": "改變",
-       "protectthispage": "保護茲蜀頁",
        "unprotect": "改變保護其狀態",
-       "unprotectthispage": "改變茲蜀頁其保護狀態",
        "newpage": "新頁",
-       "talkpage": "討論茲頁",
        "talkpagelinktext": "páng-gōng",
        "specialpage": "特殊頁",
        "personaltools": "Gó̤-ìng gì gă-sĭ-huă",
-       "articlepage": "覷蜀覷內容頁面",
        "talk": "Tō̤-lâung",
        "views": "Ché̤ṳ-siŏh-ché̤ṳ",
        "toolbox": "Gă-sĭ-huă",
-       "userpage": "覷蜀覷用戶頁面",
-       "projectpage": "看工程頁",
        "imagepage": "覷蜀覷文件頁面",
        "mediawikipage": "看消息頁",
        "templatepage": "看模板頁",
        "minoredit": "過幼修改",
        "watchthis": "監視茲頁",
        "savearticle": "Bō̤-còng ciā hiĕk",
+       "publishpage": "Huák-buó ùng-ciŏng",
+       "publishchanges": "Huák-buó siŭ-gāi",
        "preview": "預覽",
        "showpreview": "顯示預覽",
        "showdiff": "看改變其部分",
        "permissionserrorstext-withaction": "因為下底其{{PLURAL:$1|原因}},汝無能耐 $2 :",
        "recreate-moveddeleted-warn": "'''注意:汝敆𡅏重新創建舊底已經乞刪唻其頁面。'''\n\n汝應該考慮蜀下繼續去編輯茲蜀頁到底是伓是合適其。茲蜀頁其刪除記錄共移動記錄都敆嚽塊:",
        "edit-conflict": "編輯衝突",
+       "postedit-confirmation-saved": "Nṳ̄ gì siŭ-gāi ī-gĭng bō̤-còng.",
        "content-model-wikitext": "維基文本",
        "content-model-text": "純文本",
        "content-model-javascript": "JavaScript",
index 9d4f46f..007f9ef 100644 (file)
        "rcfilters-filter-editsbyself-description": "Vaše vlastní příspěvky.",
        "rcfilters-filter-editsbyother-label": "Změny ostatních",
        "rcfilters-filter-editsbyother-description": "Všechny změny kromě vašich.",
-       "rcfilters-filtergroup-userExpLevel": "Úroveň zkušeností (pouze registrovaných uživatelů)",
+       "rcfilters-filtergroup-userExpLevel": "Registrace a zkušenost uživatelů",
        "rcfilters-filter-user-experience-level-registered-label": "Registrovaní",
        "rcfilters-filter-user-experience-level-registered-description": "Přihlášení editoři.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistrovaní",
        "rcfilters-typeofchange-conflicts-hideminor": "Tento filtr podle typu změny je v konfliktu s filtrem „Malé editace“. Určité typy změn nelze označit jako malé.",
        "rcfilters-filtergroup-lastRevision": "Aktuální verze",
        "rcfilters-filter-lastrevision-label": "Aktuální verze",
-       "rcfilters-filter-lastrevision-description": "Poslední změna stránky.",
+       "rcfilters-filter-lastrevision-description": "Jen poslední změna stránky.",
        "rcfilters-filter-previousrevision-label": "Dřívější verze",
        "rcfilters-filter-previousrevision-description": "Všechny změny, které nejsou nejnovější úpravou stránky.",
        "rcfilters-view-tags": "Označené editace",
        "delete-warning-toobig": "Tato stránka má velkou historii editací, přes $1 {{PLURAL:$1|verzi|verze|verzí}}. Mazání takových stránek může narušit databázové operace {{grammar:2sg|{{SITENAME}}}}; postupujte opatrně.",
        "deleteprotected": "Tuto stránku nemůžete smazat, protože je zamčena.",
        "deleting-backlinks-warning": "<strong>Upozornění:</strong> Stránka, kterou se chystáte smazat, je [[Special:WhatLinksHere/{{FULLPAGENAME}}|na jiných stránkách]] odkazována nebo je do nich vložena.",
+       "deleting-subpages-warning": "<strong>Upozornění:</strong> Stránka, kterou se chystáte smazat, má [[Special:PrefixIndex/{{FULLPAGENAME}}|{{PLURAL:$1|podstránku|$1 podstránky|$1 podstránek|51=více než 50 podstránek}}]].",
        "rollback": "Vrátit zpět editace",
        "rollbacklink": "vrácení zpět",
        "rollbacklinkcount": "vrácení $1 {{PLURAL:$1|editace|editací}} zpět",
index f604e6a..29c3805 100644 (file)
        "viewsourcetext": "Zdrojowi tekst starnë mòże przezérac ë kòpiérowac.",
        "editinginterface": "'''ÒSTRZÉGA:''' Editëjesz starnã, jakô zamëkô w se tekst interfejsu softwôrë. Wszëtczé zmianë tu zrobioné bãdze widzec na interfejse jinszëch brëkòwników.\nPrzemëszlë dolmaczënié na [https://translatewiki.net/wiki/Main_Page?setlang=csb translatewiki.net], ekstra ùdbie lokalizacëji softwôrë MediaWiki.",
        "exception-nologin": "Nie jes wlogòwôny/a",
-       "logouttext": "'''Jes wëlogòwóny.'''\nMòżesz robic dali na {{SITENAME}} jakno anonimòwi brëkòwnik abò sã <span class='plainlinks'>[$1 wlogòwac]</span> znowa jakno równy, a bò jinszi brëkòwnik.\nBôczë, że do czasu wëczëszczenia pòdrãczny pamiãcë przezérnika, niejedné starnë bãdą wëzdrzëc jakbë të bëł wlogòwóny.",
+       "logouttext": "<strong>Jes terô wëlogòwóny.</strong>\n\nBôczë, że do czasu wëczëszczeniô pòdrãczny pamiãcë przezérnika, niejedné starnë bãdą wëzdrzëc jakbë të bëł wlogòwóny.",
        "welcomeuser": "Witôj, $1!",
        "yourname": "Miono brëkòwnika",
        "userlogin-yourname": "Miono brëkòwnika",
        "passwordremindertitle": "Nowô doczasnô parola dlô {{SITENAME}}",
        "passwordremindertext": "Chtos (gwës Të, z adresë $1) pòprosëł ò wësłanié nowi\nparolë dlô {{SITENAME}} ($4). Aktualnô parola dlô brëkòwnika\n\"$2\" òsta ùsôdzonô ë nastôwionô jakno \"$3\". Jeżlë to bëło twòją\njintencëją, mùszisz sã terô wlogòwac ë zmienic swòją parolã.\nNowô parola je wôznô {{PLURAL:$5|dzéń|$5 dni}}.\nJeżlë chto jinszi wësłôł to zapëtanié, abò pamiãtôsz swòją parolã\në chcesz jã dali bez zmianë brëkòwac, zjignorëje to wiadło ë\nrobi dali ze starną parolą.",
        "noemail": "W baze ni ma email-adresë dlô brëkòwnika \"$1\".",
-       "acct_creation_throttle_hit": "Môsz ùsôdzoné ju {{PLURAL:$1|1 kònto|$1 kontów}}.\nNi mòżesz miec ju wicy.",
+       "acct_creation_throttle_hit": "Z adresë IP chtërny brëkùjesz òstało, w slédnych $2 ùsôdzonych {{PLURAL:$1|1 kònto|$1 kontów}}, co je maksymalną wielëną, \nBrëkòwnicy ti IP-adresë ni mògą terôczasno ùsôdzac wicy kòntów.",
        "emailauthenticated": "Twój adres e-mail òstôł pòcwierdzóny $2 ò $3.",
        "accountcreated": "Konto założone",
        "accountcreatedtext": "Kònto brëkòwnika dlô [[{{ns:User}}:$1|$1]], [[{{ns:User talk}}:$1|talk]] òstało ùsadzóné.",
        "showdiff": "Wëskrzëni zjinaczi",
        "anoneditwarning": "<strong>Bôczë:</strong> Të nie jes wlogòwóny. Jeżlë wëkònôsz jakąs zmianã, twòja adresa IP mdze widocznô dlô wszëtczich. Jeżlë <strong>[$1 wlogùjesz sã]</strong> abò <strong>[$2 ùsadzysz kònto]</strong>twòje zjinaczi òstóną przëpisóné do kònta, co wicy mającë kònto dobëjesz rozmajité ùdogòdnienia.",
        "anonpreviewwarning": "Të nie jes wlogòwóny. Jeżlë wprowadzysz jaczés zjinaczi, twòja adresa IP mdze ùmieszczónô w historie edicji starnë.",
-       "summary-preview": "Pòdzérk òpisënka:",
+       "summary-preview": "Pòdzérk òpisënka zjinaków:",
        "blockedtitle": "Brëkòwnik je zascëgóny",
        "blockedtext": "<strong>Twòje kònto abò ë IP-adresa òstałë zablokòwóné.</strong>\n\nZablokòwôł je $1.\nPòdónô przëczëna to:<em>$2</em>.\n\n * Zôczątk blokadë: $8\n * Kùńc blokadë: $6\n * Cél blokadë: $7\n\n\nBë zgwësnic sprawã zablokòwaniô mòżesz skòntaktowac sã z $1 abò jińszim [[{{MediaWiki:Grouppage-sysop}}|administratorã]].\nBoczë, że të ni mòżesz stądka sélac e-mailów, jeżlë nié môsz jesz zaregisterowóné e-mailowé adresë w [[Special:Preferences|nastôwach]].\nTwòjô aktualnô adresa IP to $3, a zablokòwónô adresa ID to #$5.\nProszëmë pòdac wëższé pòdôłczi przë wszëtczich pëtaniach.",
        "loginreqlink": "Wlogùjë",
        "yourdiff": "Zjinaczi",
        "copyrightwarning": "Bôczë, że wszëtczé edicëje w {{SITENAME}} są wprowadzané pòd zastrzégą $2 (òb. $1 dlô detalów). Jeżlë nie chcesz bë to co napiszesz bëło editowóné czë kòpijowóné, tedë nie zacwierdzôj nëch edicëjów.<br />Zacwierdzając zmianë dôwôsz parolã, że to co môsz napisóné je Twòjégò aùtorstwa, abò skòpijowóné z dostónków public domain abò jinëch wòlnëch licencëjów. '''NIE DODÔWÔJ CËZËCH TEKSTÓW BEZ ZEZWÒLENIÔ!'''",
        "copyrightwarning2": "Bôczë, że wszëtczé edicëje w {{SITENAME}} mògą bëc editowóné, zmienióné abò rëmniãté bez jinëch brëkòwników.\nJeżlë nie chcesz bë Twòja robòta bëła editowónô, tedë nie dodôwôj ji tuwò.<br />\nZacwierdzając zmianë dôwôsz zgòdã na to, że to co môsz napisóné je Twòjégò aùtorstwa, abò skòpijowóné z dostónków public domain abò jinëch wòlnëch licencëjów (zdrzë za detalama na $1).\n'''NIE DODÔWÔJ ROBÒTË CHRONIONY ÙSÔDZKÒWIMA PRAWAMA BEZ ZEZWÒLENIÔ!'''",
-       "readonlywarning": "'''BÔCZËNK: Pòdôwkòwô baza òsta sztërkòwô zablokòwónô dlô administracjowich célów. Ni mòże tej timczasã zapisac nowi wersëji artikla.\nBédëjemë przeniesc ji tekst do priwatnégò lopka (wëtnij/wstôw) ë ùchòwac na pózni.'''\n\nAdministrator, chtëren jã zablokòwôł, pòdôł przëczënã: $1",
+       "readonlywarning": "<strong>Bôczënk: Pòdôwkòwô baza òsta sztërkòwô zablokòwónô dlô administracjowich célów. Ni mòże tej timczasã zapisac nowi wersëji artikla.Jeżlë chcesz, mòżesz skòpirowac jã do lopka, abë móc jã pòzdze zapisac</strong>\nSprôwnik, chtëren jã zablokòwôł, pòdôł nôslédną ji przëczënã: $1",
        "titleprotectedwarning": "'''Czó! Starna ò ti pòzwie òsta zazychrowónô. Dlô ùsadzeniô ti starnë pòtrzébné są [[Special:ListGroupRights|apartné ùdowierzenia]].'''\nNiżi  je widzec slédny wpisënk z registru:",
        "templatesused": "{{PLURAL:$1|Ùżëtô szablona|Ùżëté szablónë}} w tim artiklu:",
        "templatesusedpreview": "{{PLURAL:$1|Szablóna ùżëtô|Szablónë użëté}} w tim pòdzérkù:",
        "page_last": "kùńc",
        "histlegend": "Legenda: (aktualnô) = różnice w przërównanim do aktualny wersëje,\n(wczasniészô) = różnice w przërównanim do wczasniészi wersëje, D = drobné edicëje",
        "history-fieldset-title": "Szëkôj za wersëją",
-       "history-show-deleted": "Leno rëmniãté",
+       "history-show-deleted": "Blós rëmniãté edicëje",
        "histfirst": "òd nôstarszich",
        "histlast": "òd nônowszich",
        "history-feed-title": "Historëjô wersëji",
        "search-section": "(dzél $1)",
        "search-file-match": "(pasëje do zamkłoscë lopka)",
        "search-suggest": "Të mëszlôł ò: $1",
-       "search-interwiki-caption": "Sosterné ùdbë",
+       "search-interwiki-caption": "Skùtczi ze sostrnych ùdbów",
        "search-interwiki-default": "Wëniczi òd $1:",
        "search-interwiki-more": "(wicy)",
        "searchall": "wszëtczé",
        "saveprefs": "Zapiszë",
        "prefs-editing": "Edicëjô",
        "searchresultshead": "Szëkba",
-       "stub-threshold": "Greńca dlô fòrmatowaniô <a href=\"#\" class=\"stub\">lënków stubów</a>:",
+       "stub-threshold": "Fòrmat lënka dlô mniszich starnów ($1):",
        "recentchangesdays": "Kùli dni pòkazëwac w slédnëch edicëjach:",
        "recentchangescount": "Domëslnô wielëna wëskrzëniónych edicëjów",
        "savedprefs": "Twòjé nastôwë òstałë zapisóné.",
        "gender-female": "Białka",
        "email": "E-mail",
        "prefs-help-realname": "Prôwdzëwé miono je òptacjowé, a czej je dôsz, òstanié ùżëté do pòdpisaniô Twòjégò wkładu",
-       "prefs-help-email": "Adresa e-mail je òptacëjnô, zezwôlô równak sélac do ce nową parolã jak tã zabëjesz.\nMòżesz zezwòlëc jinszim brëkòwniką na łączbã z Tobą przez Twòją starnã abò starnã diskùsëji, bez mùszebnotë wëskrzënianiô swòjich pòdôwków.",
-       "editinguser": "Zmiana praw brëkòwnika '''[[User:$1|$1]]''' ([[User talk:$1|{{int:talkpagelinktext}}]]{{int:pipe-separator}}[[Special:Contributions/$1|{{int:contribslink}}]])",
+       "prefs-help-email": "Adresa e-mail je òptacjowô, zezwôlô równak na zresetowanié zabëti przez ce parolë.",
+       "editinguser": "Zmiana prawa przistãpù {{GENDER:$1|brëkòwnika|brëkòwniczczi}} <strong>[[User:$1|$1]]</strong> $2",
        "userrights-reason": "Przëczëna:",
        "group": "Karno:",
        "group-user": "Brëkòwnicë",
        "group-bot-member": "{{GENDER:$1|bòt}}",
        "group-sysop-member": "{{GENDER:$1|sprôwnik}}",
        "group-bureaucrat-member": "{{GENDER:$1|biórokrata|biórokratka}}",
-       "group-suppress-member": "rewizora",
+       "group-suppress-member": "{{GENDER:$1|rewizora|rewizorka}}",
        "grouppage-user": "{{ns:project}}:Brëkòwnicë",
        "grouppage-autoconfirmed": "{{ns:project}}:Aùtomatno zacwierdzeni brëkòwnicë",
        "grouppage-bot": "{{ns:project}}:Bòtë",
        "right-reupload-shared": "Môlowé nadpisëwanié egzystëjącegò lopka, we wespóldzelnych dostónkach",
        "right-upload_by_url": "Wladënk lopka z adresë URL",
        "right-purge": "Czëszczenié pòdrãczny pamiãcë starnë bez pëtaniô ò pòcwierdzenié",
-       "right-autoconfirmed": "Edicëjô dzélowò zazychrowónych starnów",
+       "right-autoconfirmed": "Bez ògrańczeniów przez òpiartë na adresë IP limitë",
        "right-bot": "Nacéchòwanié edicëjó jakno aùtomatnych",
        "right-writeapi": "Zapisënk przez jinterfejs API",
        "newuserlogpage": "Nowi brëkòwnicë",
        "newpageletter": "N",
        "boteditletter": "b",
        "rc-change-size-new": "$1 {{PLURAL:$1|bajt|bajtë|bajtów}} pò zjinace",
-       "rc-enhanced-expand": "Pòkażë detale (wëmôgô JavaScript)",
+       "rc-enhanced-expand": "Pòkażë detale",
        "rc-enhanced-hide": "Zatacë detale",
        "rc-old-title": "originalno ùsôdzoné jakno \"$1\"",
        "recentchangeslinked": "Zmianë w dolënkòwónëch",
        "uploadnologin": "Felënk logòwaniô",
        "uploadtext": "Brëkùjë negò fòrmùlara do wladënkù lopków.\nJeżlë chcesz przezdrzec abò szëkac w dotenczas wladowónëch lopkach, biéj do [[Special:FileList|lësta lopków]]. Kòżdi wladënk je registrowóny w [[Special:Log/upload|registrze wladënkù]], a rëmniãcé w [[Special:Log/delete|registrze rëmaniô]].\n\nAbë dodac lopk do starnë, ùżëjë ùniższegò lënka wedle nôslédnëch mùstrów:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Lopk.jpg]]</nowiki></code>''' wëskrzëni całi lopk\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Lopk.png|200px|thumb|left|pòdpisënk òbrôzka]]</nowiki></code>''' wëskrzëni z lewi starnë, przë ùbrzégù, miniaturkã w szérzë 200 pikslów w ramie, z nôdpisã 'pòdpisënk òbrôzka'\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Lopk.ogg]]</nowiki></code>''' òtemknie prosti lënk do lopka bez wëskrzënianiô sómegò lopka",
        "uploadlogpage": "Dołączoné",
-       "uploadlogpagetext": "Hewò je lësta slédno wladowónëch lopków.\nWszëtczé gòdzënë tikają conë ùniwersalnégò czasë.",
+       "uploadlogpagetext": "Lësta slédno wladowónëch lopków.\nBiéj do [[Special:NewFiles|galerëji nowich lopków]] abë òbôczëc jich miniaturczi.",
        "filename": "Miono lopka",
        "filedesc": "Òpisënk",
        "fileuploadsummary": "Pòdrechòwanié:",
        "statistics-edits-average": "Strzédnô lëczba edicji na starnã",
        "statistics-users": "Zaregistrowónëch [[Special:ListUsers|brëkòwników]]",
        "statistics-users-active": "Aktiwnëch brëkòwników",
-       "statistics-users-active-desc": "Brekòwnicë, jaczi bëlë aktiwni òb òstatné $1 dni",
+       "statistics-users-active-desc": "Brekòwnicë, chtërni bëlë aktiwny {{PLURAL:$1|slédnegò dnia|slédnych $1 dni}}",
        "doubleredirects": "Dëbeltné przeczérowania",
        "double-redirect-fixer": "Naprôwiôcz przeczérowaniów",
        "brokenredirects": "Zerwóné przeczerowania",
        "categories": "Kategòrëje",
        "deletedcontributions": "Rëmniãti wkłôd brëkòwnika",
        "deletedcontributions-title": "Rëmniãti wkłôd brëkòwnika",
-       "linksearch": "Bùtnowé lënczi",
+       "linksearch": "Szëkba bùtnowich lënków",
        "activeusers": "Lësta aktiwnëch brëkòwników",
        "listgrouprights-members": "(lësta nôlëżników karna)",
        "emailuser": "Wëslë e-maila do negò brëkòwnika",
-       "defemailsubject": "E-mail òd {{SITENAME}}",
+       "defemailsubject": "{{SITENAME}} – e‐mail òd brëkòwnika \"$1\"",
        "noemailtitle": "Felënk email-adresë",
        "emailusername": "Pòzwa brëkòwnika",
        "emailfrom": "Òd:",
        "mywatchlist": "Lësta ùzérónëch artiklów",
        "watchlistfor2": "Dlô $1 $2",
        "watchnologin": "Felënk logòwóniô",
-       "addedwatchtext": "Starna \"[[:$1]]\" òsta dodónô do twòji [[Special:Watchlist|lëstë ùzérónëch artiklów]].\nNa ti lësce są registre przińdnëch zjinak ti starne ë na ji starnie dyskùsëji, a samò miono starnë mdze '''wëtłëszczone''' na [[Special:RecentChanges|lësce slédnich edicëji]], bë të mògł to òbaczëc.\n\nCzej chcesz remôc starnã z lëste ùzéronëch artiklów, klikni ''Òprzestôj ùzérac''.",
-       "removedwatchtext": "Starna \"[[:$1]]\" òsta rëmniãtô z Twòji [[Special:Watchlist|lëstë ùzérónych]].",
+       "addedwatchtext": "Starna \"[[:$1]]\" òsta dodónô do twòji [[Special:Watchlist|lëstë ùzérónëch artiklów]].",
+       "removedwatchtext": "Starna \"[[:$1]]\" ze starną diskùsëji òsta rëmniãtô z Twòji [[Special:Watchlist|lëstë ùzérónych artiklów]].",
        "watch": "Ùzérôj",
        "watchthispage": "Ùzérôj ną starnã",
        "unwatch": "Òprzestôj ùzerac",
        "rollbackfailed": "Nie szło copnąc zmianë",
        "alreadyrolled": "Ni mòże copnąc slédny edicëji starnë [[:$1]], chtërny ùsôdzcą je [[User:$2|$2]] ([[User talk:$2|Diskùsëjô]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nchtos jiny ju zeditowôł starnã abò copnął zmianë.\n\nSlédnym ùsódzcą starnë bëł [[User:$3|$3]] ([[User talk:$3|Diskùsëjô]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "revertpage": "Edicje brëkòwnika [[Special:Contributions/$2|$2]] ([[User talk:$2|diskùsjô]]) òstałë òdrzucóné. Aùtorã przëwrócóny wersji je [[User:$1|$1]].",
-       "rollback-success": "Edicje brëkòwnika $1 òstałë òdrzucóné; \nòsta przëwrócónô òstatnô wersjô, aùtorã chtërny je $2.",
+       "rollback-success": "Copniãto edicëje{{GENDER:$3|brëkòwnmika|brëkòwniczczi}} $1;\ndoprowpdzono nazôd slédną wersëjã ùsôdzcë {{GENDER:$4|$2}}.",
        "rollback-success-notify": "Edicje brëkòwnika $1 òstałë òdrzucóné; \nòsta przëwrócónô òstatnô wersjô, aùtorã chtërny je $2. [$3 Pòkażë zjinaczi]",
        "protectlogpage": "Zazychrowóné",
        "protectedarticle": "zazychrowónô [[$1]]",
        "modifiedarticleprotection": "zmienionô léga zazychrowaniô [[$1]]",
-       "unprotectedarticle": "òdzychrowóny [[$1]]",
+       "unprotectedarticle": "òdzychrowôÅ\82(wa) \"[[$1]]\"",
        "protectedarticle-comment": "{{GENDER:$2|Zazychrowôł|Zazychrowała}} „[[$1]]”",
        "prot_1movedto2": "$1 przeniesłé do $2",
        "protect-legend": "Pòcwierdzë zazychrowanié",
        "protect_expiry_old": "Czas wëgasniãcô leżi w przińdnocë.",
        "protect-text": "Mòżesz tuwò sprôwdzëc ë zjinaczëc légã zazychrowaniô starnë '''$1'''.",
        "protect-locked-access": "Ni môsz dosc prawa do zjinaczi lédżi zazychrowaniô starnë. Aktualny nastôw dlô starnë '''$1''':",
-       "protect-cascadeon": "Na starna je zazychrowónô przed edicëją, dlôte że je brëkòwónô przez {{PLURAL:$1|nôslédną starnã, chtërnô òsta zazychrowónô|nôslédné starnë, chtërné òstałe zazychrowóné}} z aktiwną kaskadową òpatcëją zazychrowëwaniô.\nMòżesz zmienic légã zazychrowaniô, nie bãdze to równak miało cëskù na kaskadowé zazychrowanié.",
+       "protect-cascadeon": "Na starna je zazychrowónô przed edicëją, dlôte że je brëkòwónô przez {{PLURAL:$1|nôslédną starnã, chtërnô òsta zazychrowónô|nôslédné starnë, chtërné òstałe zazychrowóné}} z aktiwną kaskadową òpatcëją zazychrowëwaniô.\nZmiana miarë zazychrowaniô ni mô cëskù na kaskadowé zazychrowanié.",
        "protect-default": "Zezwòlë wszëtczim brëkòwnikòm",
-       "protect-fallback": "Wëmôgô prawów \"$1\"",
-       "protect-level-autoconfirmed": "Blokùjë nowich ë nieregistrowónëch brëkòwników",
-       "protect-level-sysop": "blós sprôwnicë (sysopë)",
+       "protect-fallback": "Zezwòlë blós brëkòwnikòm z prawama \"$1\"",
+       "protect-level-autoconfirmed": "Zezwòlë blós aùtomatno zacwierdzonym brëkòwnikòm",
+       "protect-level-sysop": "Zezwòlë blós sprôwnikòm",
        "protect-summary-cascade": "kaskadowanié",
        "protect-expiring": "wëgasô $1 (UTC)",
        "protect-expiry-indefinite": "na wiedno",
        "sp-contributions-newbies": "Pòkażë edicëjã blós nowich brëkòwników",
        "sp-contributions-newbies-sub": "Dlô nowich brëkòwników",
        "sp-contributions-blocklog": "historëjô blokòwaniô",
-       "sp-contributions-deleted": "rëmniãti wkłôd brëkòwnika",
+       "sp-contributions-deleted": "rëmniãtô robòta {{GENDER:$1|brëkòwnika|brëkòwniczczi}}",
        "sp-contributions-uploads": "Wësłóné lopczi",
        "sp-contributions-logs": "Rejestr logòwaniô",
        "sp-contributions-talk": "diskùsjô",
        "whatlinkshere-hidelinks": "$1 lënczi",
        "whatlinkshere-hideimages": "$1 lënk z lopków",
        "whatlinkshere-filters": "Filtrë",
-       "blockip": "Zascëgôj IP-adresã",
+       "blockip": "Blokùjë {{GENDER:$1|brëkòwnika|brëkòwniczkã}}",
        "blockiptext": "Brëkùje formùlarza niżi abë zascëgòwac prawò zapisënkù spòd gwësny adresë IP. To robi sã blós dlôte abë zascëgnąc wandalëznom, a bëc w zgòdze ze [[{{MediaWiki:Policy-url}}|wskôzama]]. Pòdôj przëczënã (np. dając miona starn, na chtërnëch dopùszczono sã wandalëzny).",
        "ipbreason": "Przëczëna:",
        "ipboptions": "2 gòdzënë:2 hours,1 dzéń:1 day,3 dni:3 days,1 tidzéń:1 week,2 tigòdnie:2 weeks,1 ksãżëc:1 month,3 ksãżëcë:3 months,6 ksãżëców:6 months,1 rok:1 year,na wiedno:infinite",
        "badipaddress": "IP-adresa nie je richtich pòdónô.",
        "blockipsuccesssub": "Zascëgónié dało sã",
        "blockipsuccesstext": "Brëkòwnik [[Special:Contributions/$1|$1]] òstał zascëgóny.<br />\nBiéj do [[Special:BlockList|lëstë zascëgónëch adresów IP]] abë òbaczëc zascëdżi.",
-       "ipblocklist": "Lësta zablokòwónëch adresów IP ë mionów brëkòwników",
+       "ipblocklist": "Zablokòwóni brëkòwnicë",
        "blocklist-timestamp": "Czasowô sygnatura",
        "blocklist-target": "Cél",
        "blocklist-expiry": "Ùpłiwô",
        "unblocklink": "òdblokùjë",
        "change-blocklink": "zmieni blokòwanié",
        "contribslink": "wkłôd",
-       "autoblocker": "Zablokòwóno ce aùtomatnie, ga brëkùjesz ti sami adresë IP co brëkòwnik \"[[User:$1|$1]]\". Przëczënô blokòwóniô $1 to: \"'''$2'''\".",
+       "autoblocker": "Zablokòwóno ce aùtomatno bò brëkùjesz ti sómy adresë IP co brëkòwnik \"[[User:$1|$1]]\". \nPrzëczënô blokòwaniô $1 to: \"$2\"",
        "blocklogpage": "Historëjô blokòwaniô",
        "blocklogentry": "zablokòwôł [[$1]], czas blokadë: $2 $3",
        "reblock-logentry": "{{GENDER:$2|zjinacził|zjinacziła}} unastôw blokadë dlô [[$1]], czas blokadë: $2 $3",
        "proxyblocker": "Blokòwanié proxy",
        "lockbtn": "Zascëgôj bazã pòdôwków",
        "move-page-legend": "Przeniesë starnã",
-       "movepagetext": "Z pòmòcą ùiższegò fòrmùlôra zjinaczisz miono starnë, przenosząc równoczasno ji historëjã.\nPòd stôrim titlã bãdze ùsôdzonô przeczérowùjącô starna.\nMòżesz aùtomatno zaktualniac przeczérowania wskazëwôjące titel przed zjinaką.\nJeżlë nie wëbiérzesz ti òptacëji, ùgwësni sã pò przenieseniu starnë, czë nie òstałé ùsôdzoné [[Special:DoubleRedirects|dëbeltné]] abò [[Special:BrokenRedirects|zerwóné przeczérowania]].\nJes òdpòwiedzalny za to, abë lënczi dali robiłë tam dze mają.\n\nStarna '''ni''' bãdze przeniosłô, jeżlë starna ò nowim mionie ju je, chòba że je òna pùstô abò je przeczérowaniém ë mô pùstą historëjã edicëji.\nTo òznôczô, że lëchą òperacëjã zjinaczi miona mòże doprowôdzëc bezpieczno nazôd, zjinaczając nowé miono starnë nawczasniészą, ë że ni mòże nadpisac stranë chtërną ju dô.\n\n'''BÔCZËNK!'''\nTo mòże bëc drasticznô abò nieprzewidëwólnô zjinaka w przëtrôfkù pòpùlarnych starnów.\nÙgwësni sã co do skùtków ti òperacëji, niglë to zrobisz.",
+       "movepagetext": "Z pòmòcą ùiższegò fòrmùlôra zjinaczisz miono starnë, przenosząc równoczasno ji historëjã.\nPòd stôrim titlã bãdze ùsôdzonô przeczérowùjącô starna.\nMòżesz aùtomatno zaktualniac przeczérowania wskazëwôjące titel przed zjinaką.\nJeżlë nie wëbiérzesz ti òptacëji, ùgwësni sã pò przenieseniu starnë, czë nie òstałé ùsôdzoné [[Special:DoubleRedirects|dëbeltné]] abò [[Special:BrokenRedirects|zerwóné przeczérowania]].\nJes òdpòwiedzalny za to, abë lënczi dali robiłë tam dze mają.\n\nStarna <strong>ni</strong> bãdze przeniosłô, jeżlë starna ò nowim mionie ju je, chòba że je òna pùstô abò je przeczérowaniém ë mô pùstą historëjã edicëji.\nTo òznôczô, że lëchą òperacëjã zjinaczi miona mòże doprowôdzëc bezpieczno nazôd, zjinaczając nowé miono starnë nawczasniészą, ë że ni mòże nadpisac stranë chtërną ju dô.\n\n<strong>BÔCZËNK!</strong>\nTo mòże bëc drasticznô abò nieprzewidëwólnô zjinaka w przëtrôfkù pòpùlarnych starnów.\nÙgwësni sã co do skùtków ti òperacëji, niglë to zrobisz.",
        "movepagetalktext": "Sparłãczonô starna diskùsëji, jeżlë ju je, to bãdze przeniosłô aùtomatno, chòba że:\n*niepùstô starna diskùsëji ju je z nowim mionã\n*rëmniész nacéchòwanié z niższegò pòla wëbiérkù\n\nW taczich przëtrôfkach zamkłosc diskùsëji mòże przeniesc blós rãczno.",
        "newtitle": "Nowi titel:",
        "move-watch": "Ùzérôj tã starnã",
        "tooltip-summary": "Wpiszë wãzłowati òpisënk",
        "anonymous": "Anonimòwi {{PLURAL:$1|brëkòwnik|brëkòwnicë}} na {{SITENAME}}",
        "siteuser": "Brëkòwnik {{SITENAME}} $1",
-       "lastmodifiedatby": "Na starna bëła slédno editowónô $2, $1 przez $3.",
+       "lastmodifiedatby": "Slédno edicëjô ti starnë: $2, $1, ùsôdzca: $3.",
        "othercontribs": "Òpiarté na prôcë $1.",
        "others": "jiné",
        "spamprotectiontitle": "Anti-spamòwi filter",
        "patrol-log-page": "Log patrolowaniô",
        "previousdiff": "← Pòprzédnô edicëjô",
        "nextdiff": "Nôslédnô edicëjô →",
-       "imagemaxsize": "Ògrańczë na starnie òpisënkù òbrôzków jich miarã do:",
+       "imagemaxsize": "Ograńczenié wielgòscë òbrôzków:<br /><em>(na starnach òpisënkù lopków)</em>",
        "thumbsize": "Miara miniaturków:",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|starna|starnë|starnów}}",
        "file-info-size": "$1 × $2 pikslów, miara lopka: $3, ôrt MIME: $4",
        "imgmultigo": "Biéj!",
        "imgmultigoto": "Biéj do starnë $1",
        "autoredircomment": "Przeczérowanié do [[$1]]",
-       "autosumm-new": "Pòwsta nowô starna:",
+       "autosumm-new": "Ùsôdzonô nowô starna \"$1\"",
        "watchlisttools-clear": "Wëczësczë ùzérówną lëstã",
        "watchlisttools-view": "Òbaczë wôżnészé zmianë",
        "watchlisttools-edit": "Òbaczë a editëjë lëstã ùzérónëch artiklów",
index 207f478..0778133 100644 (file)
        "rcfilters-filter-editsbyself-description": "Deine eigenen Beiträge.",
        "rcfilters-filter-editsbyother-label": "Änderungen von anderen",
        "rcfilters-filter-editsbyother-description": "Alle Änderungen außer deine eigenen.",
-       "rcfilters-filtergroup-userExpLevel": "Anmeldung und Erfahrung",
+       "rcfilters-filtergroup-userExpLevel": "Benutzeranmeldung und -erfahrung",
        "rcfilters-filter-user-experience-level-registered-label": "Angemeldet",
        "rcfilters-filter-user-experience-level-registered-description": "Angemeldete Autoren.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Unangemeldet",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Der Filter „Kleine Bearbeitungen“ kollidiert mit einem oder mehreren Änderungstypfiltern, da bestimmte Änderungstypen nicht als „klein“ festgelegt werden können. Die kollidierenden Filter sind oben im Bereich der aktiven Filter markiert.",
        "rcfilters-hideminor-conflicts-typeofchange": "Bestimmte Änderungstypen können nicht als „klein“ festgelegt werden, so dass dieser Filter mit den folgenden Änderungstypfiltern kollidiert: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Dieser Änderungstypfilter kollidiert mit dem Filter „Kleine Bearbeitungen“. Bestimmte Änderungstypen können nicht als „klein“ festgelegt werden.",
-       "rcfilters-filtergroup-lastRevision": "Letzte Version",
-       "rcfilters-filter-lastrevision-label": "Letzte Version",
-       "rcfilters-filter-lastrevision-description": "Die aktuellste Änderung an einer Seite.",
-       "rcfilters-filter-previousrevision-label": "Frühere Versionen",
-       "rcfilters-filter-previousrevision-description": "Alle Änderungen, die nicht die aktuellste Änderung an einer Seite sind.",
+       "rcfilters-filtergroup-lastRevision": "Aktuellste Versionen",
+       "rcfilters-filter-lastrevision-label": "Aktuellste Version",
+       "rcfilters-filter-lastrevision-description": "Nur die aktuellste Änderung an einer Seite.",
+       "rcfilters-filter-previousrevision-label": "Nicht die aktuellste Version",
+       "rcfilters-filter-previousrevision-description": "Alle Änderungen, die nicht die „aktuellste Version“ sind.",
        "rcfilters-filter-excluded": "Ausgeschlossen",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:nicht</strong> $1",
        "rcfilters-exclude-button-off": "Ausgewählte ausschließen",
        "delete-warning-toobig": "Diese Seite hat mit mehr als $1 {{PLURAL:$1|Version|Versionen}} eine sehr lange Versionsgeschichte. Das Löschen kann zu Störungen im Datenbankbetrieb führen.",
        "deleteprotected": "Du kannst diese Seite nicht löschen, da sie geschützt wurde.",
        "deleting-backlinks-warning": "<strong>Warnung:</strong> Es verweisen noch [[Special:WhatLinksHere/{{FULLPAGENAME}}|andere Seiten]] auf diese zu löschende Seite oder sie ist noch an anderer Stelle eingebunden.",
+       "deleting-subpages-warning": "<strong>Warnung:</strong> Die Seite, die du löschen möchtest, hat [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|eine Unterseite|$1 Unterseiten|51=über 50 Unterseiten}}]].",
        "rollback": "Zurücksetzen der Änderungen",
        "rollbacklink": "Zurücksetzen",
        "rollbacklinkcount": "{{PLURAL:$1|Eine Version|$1 Versionen}} zurücksetzen",
index b9b8980..a937a7a 100644 (file)
        "oct": "Pthi",
        "nov": "Ptht",
        "dec": "Pthr",
-       "pagecategories": "{{PLURAL:$1|bekätakthook|bekätakthuɔk}}",
+       "pagecategories": "{{PLURAL:$1|Bekätakthook|Bekätakthuɔk}}",
        "category_header": "Apääm në bekätakthook \"$1\"ic",
        "subcategories": "Bekätakthuɔkkor",
-       "category-media-header": "Kuat në bekätakthook  $1 yic",
+       "category-media-header": "Kuat në bekätakthook \"$1\" yic",
        "hidden-categories": "{{PLURAL:$1|Bekätakthook cï thiaan|Bekätakthuɔk cï thiaan}}",
        "category-subcat-count": "{{PLURAL:$2|Bekätakthookë anɔŋ bekätakthookkorkɛ̈ kepɛ̈c.|Bekätakthookë anɔŋ {{PLURAL:$1|bekätakthookkorë|$1 bekätakthuɔkkorkɛ̈}}, në $2 yic̈;}}",
        "category-article-count": "{{PLURAL:$2|Bekätakthookë anɔŋic yärë yetök.|{{PLURAL:$1|Yärë atɔ̈|$1 yɔ̈rkɛ̈ aatɔ̈}} bekätakthook thiöökë yic, në $2 yic.}}",
        "recentchangeslinked-toolbox": "Kaceyiicwar nɔŋ kar",
        "recentchangeslinked-title": "Weer thöŋ kekë \"$1\"",
        "recentchangeslinked-summary": "Kän areny de wɛ̈r cïloi wɛ̈ramɛn tënɔŋ apam nuɛtke apam nhic (nadëk ka nuɛtke kɔcakuut de bekätakthook nhic).\nApam tɔ̈ [[Special:Watchlist|abërtïtdu]] aa <strong>gɔ̈tdïtnyin</strong>.",
-       "recentchangeslinked-page": "Rin ë akap:",
+       "recentchangeslinked-page": "Rin ë apam:",
        "recentchangeslinked-to": "Nyuɔɔthë kä cï ke waar në apɛ̈m cï nuɛ̈ɛ̈t ke apam tiöökë, ku acie kä cï ke waar në yen apam thiöökë yic",
        "upload": "Wälë apamduööt",
        "filedesc": "Cuutyic",
index fd7921f..929042f 100644 (file)
        "rcfilters-hideminor-conflicts-typeofchange-global": "The \"Minor edits\" filter conflicts with one or more Type of change filters, because certain types of change cannot be designated as \"minor\". The conflicting filters are marked in the Active filters area, above.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certain types of change cannot be designated as \"minor\", so this filter conflicts with the following Type of Change filters: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "This Type of change filter conflicts with the \"Minor edits\" filter. Certain types of change cannot be designated as \"minor\".",
-       "rcfilters-filtergroup-lastRevision": "Last revision",
-       "rcfilters-filter-lastrevision-label": "Last revision",
-       "rcfilters-filter-lastrevision-description": "The most recent change to a page.",
-       "rcfilters-filter-previousrevision-label": "Earlier revisions",
-       "rcfilters-filter-previousrevision-description": "All changes that are not the most recent change to a page.",
+       "rcfilters-filtergroup-lastRevision": "Latest revisions",
+       "rcfilters-filter-lastrevision-label": "Latest revision",
+       "rcfilters-filter-lastrevision-description": "Only the most recent change to a page.",
+       "rcfilters-filter-previousrevision-label": "Not the latest revision",
+       "rcfilters-filter-previousrevision-description": "All changes that are not the \"latest revision\".",
        "rcfilters-filter-excluded": "Excluded",
        "rcfilters-tag-prefix-namespace": ":$1",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:not</strong> $1",
index 30c00cb..cf4f5db 100644 (file)
        "rcfilters-filter-newpages-description": "Orri berriak egiten dituzten aldaketak",
        "rcfilters-filter-categorization-label": "Kategoria aldaketak",
        "rcfilters-filter-logactions-label": "Erregistratutako ekintzak",
-       "rcfilters-filtergroup-lastRevision": "Azken berrikuspena",
+       "rcfilters-filtergroup-lastRevision": "Azken berrikuspenak",
        "rcfilters-filter-lastrevision-label": "Azken berrikuspena",
        "rcfilters-filter-lastrevision-description": "Orrialde bati eginiko aldaketarik berriena.",
-       "rcfilters-filter-previousrevision-label": "Aurreko berrikuspenak",
+       "rcfilters-filter-previousrevision-label": "Ez da azken berrikuspena",
+       "rcfilters-filter-previousrevision-description": "\"Azken berrikuspena\" ez diren aldaketa guztiak.",
        "rcfilters-filter-excluded": "Baztertua",
        "rcfilters-exclude-button-off": "Baztertzea aukeratuta",
        "rcfilters-exclude-button-on": "Baztertzea aukeratuta",
index 3c9b3aa..4d9a785 100644 (file)
        "rcfilters-filter-editsbyself-description": "Vos propres contributions.",
        "rcfilters-filter-editsbyother-label": "Modifications faites par les autres.",
        "rcfilters-filter-editsbyother-description": "Toutes les modifications sauf les votres.",
-       "rcfilters-filtergroup-userExpLevel": "Enregistrement de l'expérience et expérience",
+       "rcfilters-filtergroup-userExpLevel": "Enregistrement des utilisateurs et expérience",
        "rcfilters-filter-user-experience-level-registered-label": "Connecté",
        "rcfilters-filter-user-experience-level-registered-description": "Éditeurs connectés.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non connecté",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Le filtre « Modifications mineures » est en conflit avec au moins un filtre de Type de modification, parce que certains types de modification ne peuvent être marqués comme « mineurs ». Les filtres en conflit sont marqués dans la zone Filtres actifs ci-dessus.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certains types de modification ne peuvent pas être qualifiés de « mineurs », donc ce filtre est en conflit avec les filtres de Type de modification suivants : $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ce filtre de Type de modification est en conflit avec le filtre « Modifications mineures ». Certains type sde modification ne peuvent pas être indiqués comme « mineurs ».",
-       "rcfilters-filtergroup-lastRevision": "Version actuelle",
-       "rcfilters-filter-lastrevision-label": "Version actuelle",
-       "rcfilters-filter-lastrevision-description": "Dernière modification apportée à une page.",
-       "rcfilters-filter-previousrevision-label": "Versions précédentes",
-       "rcfilters-filter-previousrevision-description": "Toutes les modifications apportées à une page et qui ne sont pas la dernière.",
+       "rcfilters-filtergroup-lastRevision": "Dernières révisions",
+       "rcfilters-filter-lastrevision-label": "Dernière révision",
+       "rcfilters-filter-lastrevision-description": "Uniquement la dernière modification apportée à une page.",
+       "rcfilters-filter-previousrevision-label": "Pas la dernière révision",
+       "rcfilters-filter-previousrevision-description": "Toutes les modifications apportées à une page et qui ne sont pas la « dernière révision ».",
        "rcfilters-filter-excluded": "Exclu",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:not</strong> $1",
        "rcfilters-exclude-button-off": "Exclure les sélectionnés",
        "delete-warning-toobig": "Cette page possède un historique important de modifications, dépassant $1 version{{PLURAL:$1||s}}.\nLa supprimer peut perturber le fonctionnement de la base de données de {{SITENAME}} ;\nveuillez procéder avec prudence.",
        "deleteprotected": "Vous ne pouvez pas supprimer cette page car elle a été protégée.",
        "deleting-backlinks-warning": "<strong>Attention :</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|D’autres pages]] ont un lien vers ou incorporent la page que vous allez supprimer.",
+       "deleting-subpages-warning": "<strong>Attention :</strong> la page que vous essayez de supprimer possède  [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|une sous-page|$1 sous-pages|51=plus de 50 sous-pages}}]].",
        "rollback": "Révoquer les modifications",
        "rollbacklink": "révoquer",
        "rollbacklinkcount": "révoquer $1 {{PLURAL:$1|modification|modifications}}",
index c811a1b..2f8a9ab 100644 (file)
        "errorpagetitle": "Diar as wat skiaf gingen",
        "returnto": "Turag tu sidj $1.",
        "tagline": "Faan {{SITENAME}}",
-       "help": "Halep",
+       "help": "MediaWiki Halep",
        "search": "Schük",
        "search-ignored-headings": " #<!-- Detdiar rä ei feranre --> <pre>\n# Auerskraften, diar bi't schüken ei beaachtet wurd.\n# Jodiar feranrangen wurd seekert, wan det sidj mä det auerskraft indeksiaret wurden as.\n# Dü könst det sidjenindeksiarang föörtji, wan dü en nul-edit maagest.\n# Syntax:\n#   * Ales, wat bääft en dobelkrüs („#“) stäänt, as en komentaar.\n#   * Arke rä, wat ei leesag as, as di akeroot tiitel, diar ei beaachtet woort.\nFutnuuten\nFerwisangen\nLuke uk diar\n #</pre> <!-- Detdiar rä ei feranre -->",
        "searchbutton": "Schük",
index 2be194e..7f040a0 100644 (file)
        "rcfilters-legend-heading": "<strong>Lista de abreviaturas:</strong>",
        "rcfilters-activefilters": "Filtros activos",
        "rcfilters-advancedfilters": "Filtros avanzados",
+       "rcfilters-limit-title": "Modificacións a amosar",
+       "rcfilters-limit-shownum": "Amosar as últimas $1 modificacións",
+       "rcfilters-days-title": "Últimos días",
+       "rcfilters-hours-title": "Últimas horas",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|día|días}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|hora|horas}}",
        "rcfilters-quickfilters": "Filtros gardados",
        "rcfilters-quickfilters-placeholder-title": "Aínda non se gardou ningunha ligazón",
        "rcfilters-quickfilters-placeholder-description": "Para gardar a configuración dos seus filtros e reutilizala máis tarde, prema na icona do marcador na área de Filtro activo que se atopa a abaixo.",
        "rcfilters-invalid-filter": "Filtro no válido",
        "rcfilters-empty-filter": "Non hai filtros activos. Móstranse tódalas contribucións.",
        "rcfilters-filterlist-title": "Filtros",
-       "rcfilters-filterlist-whatsthis": "Que é isto?",
+       "rcfilters-filterlist-whatsthis": "Como funciona isto?",
        "rcfilters-filterlist-feedbacklink": "Deixar comentarios sobre os novos filtros (en fase beta)",
        "rcfilters-highlightbutton-title": "Resaltar resultados",
        "rcfilters-highlightmenu-title": "Seleccione unha cor",
        "rcfilters-filter-editsbyself-description": "As súas contribucións",
        "rcfilters-filter-editsbyother-label": "Modificacións doutros.",
        "rcfilters-filter-editsbyother-description": "Tódolos cambios, excepto os seus.",
-       "rcfilters-filtergroup-userExpLevel": "Nivel de experiencia (só para usuarios rexistrados)",
-       "rcfilters-filter-user-experience-level-registered-label": "Rexistrado",
+       "rcfilters-filtergroup-userExpLevel": "Rexistro de usuarios e experiencia",
+       "rcfilters-filter-user-experience-level-registered-label": "Rexistrados",
        "rcfilters-filter-user-experience-level-registered-description": "Editores autenticados.",
-       "rcfilters-filter-user-experience-level-unregistered-label": "Non rexistrado",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Non rexistrados",
        "rcfilters-filter-user-experience-level-unregistered-description": "Editores que non están autenticados.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Chegados recentemente",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Menos de 10 edicións e 4 días de actividade.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Editores rexistrados con menos de 10 edicións e 4 días de actividade.",
        "rcfilters-filter-user-experience-level-learner-label": "Aprendices",
-       "rcfilters-filter-user-experience-level-learner-description": "Máis experimentado que os \"usuarios novatos\" pero menos que os \"usuarios experimentados\".",
+       "rcfilters-filter-user-experience-level-learner-description": "Editores rexistrados cuxa experiencia está entre os \"usuarios novatos\" e os \"usuarios experimentados\".",
        "rcfilters-filter-user-experience-level-experienced-label": "Usuarios experimentados",
-       "rcfilters-filter-user-experience-level-experienced-description": "Máis de 30 días de actividade e 500 edicións.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Editores rexistrados con máis de 500 edicións e 30 días de actividade.",
        "rcfilters-filtergroup-automated": "Contribucións automatizadas",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-bots-description": "Edicións realizadas por ferramentas automatizadas.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "O filtro \"edicións menores\" está en conflito con un ou máis filtros Tipo de modificación, porque certos tipos de modificación non poden designarse como \"menores\". Os filtros en conflito están marcados na zona Filtros activos, arriba.",
        "rcfilters-hideminor-conflicts-typeofchange": "Certos tipos de modificación non poden designarse como \"menores\", polo que este filtro entra en conflito cos seguintes filtros Tipo de modificaciónː $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro Tipo de modificación entra en conflito co filtro \"Modificacións menores\". Certos tipos de modificación non poden designarse como \"menores\".",
-       "rcfilters-filtergroup-lastRevision": "Versión actual",
-       "rcfilters-filter-lastrevision-label": "Versión actual",
-       "rcfilters-filter-lastrevision-description": "A última modificación a unha páxina.",
-       "rcfilters-filter-previousrevision-label": "Versións anteriores",
-       "rcfilters-filter-previousrevision-description": "Tódolos cambios realizados nunha páxina e que non son os máis recentes.",
+       "rcfilters-filtergroup-lastRevision": "Últimas revisións",
+       "rcfilters-filter-lastrevision-label": "Últimas revisións",
+       "rcfilters-filter-lastrevision-description": "Só a última modificación a unha páxina.",
+       "rcfilters-filter-previousrevision-label": "Non a última edición",
+       "rcfilters-filter-previousrevision-description": "Tódolos cambios realizados nunha páxina e que non son a \"última modificación\".",
        "rcfilters-filter-excluded": "Excluído",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:non</strong> $1",
+       "rcfilters-exclude-button-off": "Excluír os seleccionados",
+       "rcfilters-exclude-button-on": "Excluíndo os seleccionados",
        "rcfilters-view-tags": "Edicións marcadas",
        "rcfilters-view-namespaces-tooltip": "Filtrar resultados por espazo de nomes",
        "rcfilters-view-tags-tooltip": "Filtrar resultados usando etiquetas de edición",
        "delete-warning-toobig": "Esta páxina conta cun historial de edicións longo, de máis {{PLURAL:$1|dunha revisión|de $1 revisións}}.\nAo eliminala pódense provocar problemas de funcionamento nas operacións da base de datos de {{SITENAME}};\nproceda con coidado.",
        "deleteprotected": "Non pode borrar esta páxina porque está protexida.",
        "deleting-backlinks-warning": "<strong>Atención:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Outras páxinas]] conteñen unha ligazón ou unha transclusión da páxina que está a piques de borrar.",
+       "deleting-subpages-warning": "<strong>Aviso:</strong> A páxina que quere eliminar ten [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|unha subpáxina|$1 subpáxinas|51=máis de 50 subpáxinas}}]].",
        "rollback": "Reverter as edicións",
        "rollbacklink": "reverter",
        "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edición|edicións}}",
index a81f2df..889ed94 100644 (file)
        "accmailtext": "E zuefällig generiert Passwort fir [[User talk:$1|$1]] isch an $2 gschickt wore.\n\nS Passwort fir des nej Benutzerkonto cha uf dr Spezialsyte „[[Special:ChangePassword|Passwort ändere]]“ gänderet wäre.",
        "newarticle": "(Nej)",
        "newarticletext": "Du bisch eme Link nogange zuen ere Syte, wu s nid git.\nZum die Syte aalege, chasch do in däm Chaschte unte aafange schrybe (lueg [$1 Hilfe] fir meh Informatione).\nWänn do nid hesch welle aane goh, no druck in Dyynem Browser uf '''Zruck'''.",
-       "anontalkpagetext": "----''Des isch e Diskussionssyte vun eme anonyme Benutzer, wu kei Zuegang aagleit het oder wu ne nit bruucht. Sälleweg mien mir di numerisch IP-Adräss bruuche zum ihn oder si z identifiziere. So ne IP-Adräss cha au vu mehrere Benutzer teilt wäre. Wenn Du ne anonyme Benutzer bisch un s Gfiel hesch, ass do irrelevanti Kommentar an di grichtet wäre, derno [[Special:CreateAccount|leg e Konto aa]] oder [[Special:UserLogin|mäld di aa]] zum in Zuekumft Verwirrige mit andere anonyme Benutzer z vermyyde.''",
+       "anontalkpagetext": "----\n<em>Des isch e Diskussionssyte vun eme anonyme Benutzer, wu kei Zuegang aagleit het oder wu ne nit bruucht.</em>\nSälleweg mien mir di numerisch IP-Adräss bruuche zum ihn oder si z identifiziere. So ne IP-Adräss cha au vu mehrere Benutzer teilt wäre. Wenn Du ne anonyme Benutzer bisch un s Gfiel hesch, ass do irrelevanti Kommentar an di grichtet wäre, derno [[Special:CreateAccount|leg e Konto aa]] oder [[Special:UserLogin|mäld di aa]] zum in Zuekumft Verwirrige mit andere anonyme Benutzer z vermyyde.",
        "noarticletext": "Uf däre Syte het s no kei Täxt. \nDu chasch uf andere Syte [[Special:Search/{{PAGENAME}}|dä Yytrag sueche]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} dr Logbuechyytrag sueche, wo dezue ghert],\noder [{{fullurl:{{FULLPAGENAME}}|action=edit}} die Syte erstelle]</span>.",
        "noarticletext-nopermission": "In däre Syte het s zur Zyt no kei Text.\nDu chasch dää Titel uf andre Syte [[Special:Search/{{PAGENAME}}|sueche]]\noder <span class=\"plainlinks\">in dr zuegherige [{{fullurl:{{#special:Log}}|page={{FULLPAGENAMEE}}}} Logbiecher sueche].</span> Du derfsch aber die Syte nit aalege.",
        "missing-revision": "D Version $1 vu dr Syte mit Name „{{FULLPAGENAME}}“ git s nit.\n\nDää Fähler chunnt normalerwyys dur e veraltete Link zue dr Versionsgschicht vun ere Syte, wu in dr Zwischezyt glescht woren isch.\nEinzelheite chasch im [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Lesch-Logbuech] bschaue.",
        "userpage-userdoesnotexist": "S Benutzerkonto „<nowiki>$1</nowiki>“ git s nit. Bitte prief, eb Du die Syte wirkli wit aalege/bearbeite.",
        "userpage-userdoesnotexist-view": "S Benutzerkonto „$1“ isch nit registriert.",
        "blocked-notice-logextract": "Dää Benutzer isch zur Zyt gsperrt.\nAs Information chunnt do ne aktuälle Uuszug us em Benutzersperr-Logbuech:",
-       "clearyourcache": "'''Hiiwys:''' Noch em Spycheremuesch no dr Browser-Zwischespycher lääre go d Änderige sää.\n* '''Firefox/ Safari:''' ''Umschaltig'' drucken un glychzytig ''Aktualisiere'' aaklicken oder entwäder ''Strg+F5'' oder ''Strg+R'' (''Befehlstaste-R'' uf em Mac) drucke\n* '''Google Chrome:''' ''Umschaltig+Strg+R'' (''Befählstaschte-R'' uf em Mac) drucke\n* '''Internet Explorer:''' ''Strg+F5'' drucken oder ''Strg'' drucken un glychzytig ''Aktualisiere'' aaklicke\n* '''Opera:''' ''Extra → Internetspure lesche … → Individuäll Uuswahl → Dr komplett Cache lesche''",
+       "clearyourcache": "<strong>Hiiwys:</strong> Noch em Spycheremuesch no dr Browser-Zwischespycher lääre go d Änderige sää.\n* <strong>Firefox/ Safari:</strong> <em>Umschaltig</em> drucken un glychzytig <em>Aktualisiere</em> aaklicken oder entwäder <em>Strg+F5</em> oder <em>Strg+R</em> (<em>Befehlstaste-R</em> uf em Mac) drucke\n* <strong>Google Chrome:</strong> <em>Umschaltig+Strg+R</em> (<em>Befählstaschte-R</em> uf em Mac) drucke\n* <strong>Internet Explorer:</strong> <em>Strg+F5</em> drucken oder <em>Strg</em> drucken un glychzytig <em>Aktualisiere</em> aaklicke\n* <strong>Opera:</strong> Gang uff <em>Menü → Yystellige</em> (<em>Opera → Yystellige</em> uff eme Mac) un deno uff <em>Dateschutz & Sicherheit → Browserdate lösche → Gspyycherti Bilder un Dateie</em>.",
        "usercssyoucanpreview": "'''Tipp:''' Nimm dr „{{int:showpreview}}”-Chnopf, zum Dyy nej CSS vor em Spichere z teschte.",
        "userjsyoucanpreview": "'''Tipp:''' „Nimm dr {{int:showpreview}}”-Chnopf, zum Dyy nej JS vor em Spichere z teschte.",
        "usercsspreview": "== Vorschau vu Dyynem Benutzer-CSS. ==\n'''Wichtig:''' Noch em Spichere muesch Dyynem Browser sage, ass er die nej Version ladet:\n\n'''Mozilla:''' ''Strg-Shift-R'', '''IE:''' ''Strg-F5'', '''Safari:''' ''Cmd-Shift-R'', '''Konqueror:''' ''F5''.",
        "tooltip-feed-rss": "RSS-Feed für selli Syte",
        "tooltip-feed-atom": "Atom-Feed für selli Syte",
        "tooltip-t-contributions": "E Lischt vo de Byträg vo {{GENDER:$1|däm Benutzer}}",
-       "tooltip-t-emailuser": "Schick däm Benutzer e E-Bost",
+       "tooltip-t-emailuser": "Schigg e E-Mail aa {{GENDER:$1|de Benutzer|die Benutzeri}}",
        "tooltip-t-info": "Meh Informationen über die Syte",
        "tooltip-t-upload": "Dateien ufelade",
        "tooltip-t-specialpages": "Lischte vo allne Spezialsyte",
        "version-libraries-license": "Lizänz",
        "version-libraries-description": "Beschrybig",
        "version-libraries-authors": "Autor/inne",
-       "redirect": "Wyterleitig uf Benutzersyte, Syte, Syteversion oder Datei",
-       "redirect-summary": "Die Spezialsyte leitet wyter uf e Benutzersyte (numerischi Benutzerkännig aagee), Syte (Sytekännig aagee), Syteversion (Versionskännig aagee) oder Datei (Dateiname aagee). Benutzig: [[{{#Special:Redirect}}/user/101]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]] oder [[{{#Special:Redirect}}/file/Example.jpg]].",
+       "redirect": "Wyterleitig uf Datei, Benutzersyte, Syte, Syteversion oder Logbuechyytraag.",
+       "redirect-summary": "Die Spezialsyte leitet wyter uf e Benutzersyte (numerischi Benutzerkännig aagee), Syte (Sytekännig aagee), Syteversion (Versionskännig aagee), e Datei (Dateiname aagee) oder en Logbeuchyytrag (Logbuechkennig aagee). Benutzig: Usage: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], oder [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Gang",
        "redirect-lookup": "Sueche:",
        "redirect-value": "Wärt:",
        "htmlform-user-not-exists": "<strong>$1</strong> git’s nid.",
        "htmlform-user-not-valid": "<strong>$1</strong> isch ke gültige Name.",
        "logentry-delete-delete": "{{GENDER:$2|Dr|D|}} $1 het d Syte $3 glöscht",
-       "logentry-delete-restore": "{{GENDER:$2|Der $1|D $1|$1}} het d Syte $3 wider härgstellt",
+       "logentry-delete-restore": "{{GENDER:$2|Der $1|D $1|$1}} het d Syte $3 wider härgstellt ($4)",
        "logentry-delete-event": "{{GENDER:$2|Der $1|D $1|$1}} het d Sichtbarkeit {{PLURAL:$5|vumene Logbuechyytrag|vo $5 Logbuechyyträg}} gänderet uff $3: $4",
        "logentry-delete-revision": "{{GENDER:$2|Der $1|D $1|$1}} het d Sichtbarkeit {{PLURAL:$5|vunere Version|vo $5 Versione}} gänderet uff $3: $4",
        "logentry-delete-event-legacy": "{{GENDER:$2|Der $1|D $1|$1}} het d Sichtbarkeit vo Logbuechyyträg uff $3 gänderet",
index 03f044c..a46eebc 100644 (file)
        "anontalk": "Kâu-liù",
        "navigation": "Thô-hòng",
        "and": "&#32;lâu",
-       "qbfind": "Cháu-chhìm",
-       "qbbrowse": "Liù-lám",
-       "qbedit": "Phiên-siá",
-       "qbpageoptions": "Ya̍p-mien sién-hong",
-       "qbmyoptions": "Ngài-ke ya̍p-mien",
        "faq": "Sòng-kien mun-thì kié-tap",
-       "faqpage": "Project:Sòng-kien mun-thì kié-tap",
        "actions": "Thûng-chok",
        "namespaces": "Miàng-sṳ khûng-kiên",
        "variants": "Pien-von",
        "edit": "Phiên-siá",
        "create": "Kien-li̍p",
        "create-local": "Sîn-chen pún-thi sot-mìn",
-       "editthispage": "Phiên-siá liá ya̍p",
-       "create-this-page": "Kien-li̍p pún-ya̍p",
        "delete": "San-chhù",
-       "deletethispage": "San-chhù pún-ya̍p",
-       "undeletethispage": "Chhí-sêu san-chhù liá-ya̍p.",
        "undelete_short": "恢復$1隻分删除个编寫",
        "viewdeleted_short": "查看$1項已刪除个修訂",
        "protect": "Pó-fu",
        "protect_change": "Kiên-kói",
-       "protectthispage": "Pó-fu pún-ya̍p",
        "unprotect": "更改保護",
-       "unprotectthispage": "更改本頁保護",
        "newpage": "Sîn ya̍p-mien",
-       "talkpage": "Thó-lun pún-ya̍p",
        "talkpagelinktext": "kâu-liù",
        "specialpage": "Thi̍t-sû ya̍p-mien",
        "personaltools": "Sṳ̂-ngìn kûng-khí",
-       "articlepage": "Khon nui-yùng ya̍p",
        "talk": "Thó-lun",
        "views": "Chhà-khon-sú",
        "toolbox": "Kûng-khí-siông",
-       "userpage": "查看用戶頁面",
-       "projectpage": "查看項目頁面",
        "imagepage": "Chhà-khon vùn-khien ya̍p-mien",
        "mediawikipage": "Chhà-khon sêu-sit ya̍p-mien",
        "templatepage": "Chhà-khon mù-pán ya̍p-mien",
        "minoredit": "Liá-he yit-chak se-mì siû-kói",
        "watchthis": "Kâm-sṳ pún-ya̍p",
        "savearticle": "Pó-chhùn pún-ya̍p",
+       "publishpage": "Fat-péu vùn-chông",
+       "publishchanges": "Fat-péu siû-kói",
        "preview": "預覽",
        "showpreview": "Chán-sṳ yi-lám",
        "showdiff": "Chán-sṳ chhâ-phe̍t",
        "edit-gone-missing": "毋做得更新頁面。\n其可能正正分刪除。",
        "edit-conflict": "Phiên-siá chhûng-thu̍t.",
        "edit-no-change": "汝嘅編寫已經略過,因為文字無任何改動。",
+       "postedit-confirmation-saved": "Ngì ke siû-kói yí-kîn pó-chhùn.",
        "edit-already-exists": "毋做得建立一隻新頁面。\n其已經存在。",
        "defaultmessagetext": "Me̍t-ngin sêu-sit vùn-sṳ",
        "invalid-content-data": "無效嘅數據內容",
index 487d889..d9472a2 100644 (file)
        "rcfilters-filter-editsbyself-description": "תרומות שביצעת בעצמך.",
        "rcfilters-filter-editsbyother-label": "שינויים של אחרים",
        "rcfilters-filter-editsbyother-description": "כל השינויים מלבד אלה שלך.",
-       "rcfilters-filtergroup-userExpLevel": "ר×\9eת × ×\99ס×\99×\95×\9f (×\9c×\9eשת×\9eש×\99×\9d ×¨×©×\95×\9e×\99×\9d ×\91×\9c×\91×\93)",
+       "rcfilters-filtergroup-userExpLevel": "×\94רש×\9eת ×\9eשת×\9eש×\99×\9d ×\95ר×\9eת × ×\99ס×\99×\95×\9f",
        "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-newcomer-label": "חדשים",
        "rcfilters-filter-user-experience-level-newcomer-description": "עורכים רשומים עם פחות מ־10 עריכות ומ־4 ימים של פעילות.",
        "rcfilters-filter-user-experience-level-learner-label": "לומדים",
-       "rcfilters-filter-user-experience-level-learner-description": "×¢×\95ר×\9b×\99×\9d ×¨×©×\95×\9e×\99×\9d ×¢×\9d ×©×\94× ×\99ס×\99×\95×\9f ×©×\9c×\94×\9d ×\94×\95א בין \"חדשים\" לבין \"מנוסים\".",
+       "rcfilters-filter-user-experience-level-learner-description": "×¢×\95ר×\9b×\99×\9d ×¨×©×\95×\9e×\99×\9d ×©×¨×\9eת ×\94× ×\99ס×\99×\95×\9f ×©×\9c×\94×\9d ×\94×\99א בין \"חדשים\" לבין \"מנוסים\".",
        "rcfilters-filter-user-experience-level-experienced-label": "משתמשים מנוסים",
        "rcfilters-filter-user-experience-level-experienced-description": "עורכים רשומים עם יותר מ־500 עריכות ו־30 ימים של פעילות.",
        "rcfilters-filtergroup-automated": "תרומות אוטומטיות",
        "rcfilters-hideminor-conflicts-typeofchange-global": "מסנן \"עריכות משניות\" מתנגש עם מסנן סוג השינויים אחד או יותר, כי סוגים מסוימים של שינויים אינם יכולים להיות מסווגים בתור \"משניים\". המסננים המתנגשים מסומנים באזור המסננים הפעילים לעיל.",
        "rcfilters-hideminor-conflicts-typeofchange": "סוגים מסוימים של שינויים אינם יכולים להיות מסווגים כ\"משניים\", כך שמסנן זה מתנגש עם מסנן סוג השינויים הבא: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "מסנן סוג השינויים הזה מתנגש עם מסנן \"עריכות משניות\". סוגים מסוימים של שינויים אינם יכולים מסווגים כ\"משניים\".",
-       "rcfilters-filtergroup-lastRevision": "×\92רס×\94 ×\90×\97ר×\95× ×\94",
+       "rcfilters-filtergroup-lastRevision": "×\92רס×\90×\95ת ×\90×\97ר×\95× ×\95ת",
        "rcfilters-filter-lastrevision-label": "הגרסה האחרונה",
-       "rcfilters-filter-lastrevision-description": "השינוי האחרון בדף.",
-       "rcfilters-filter-previousrevision-label": "×\92רס×\90×\95ת ×§×\95×\93×\9e×\95ת",
-       "rcfilters-filter-previousrevision-description": "כל השינויים שאינם השינוי האחרון בדף.",
+       "rcfilters-filter-lastrevision-description": "רק ×\94ש×\99× ×\95×\99 ×\94×\90×\97ר×\95×\9f ×\91×\93×£.",
+       "rcfilters-filter-previousrevision-label": "×\9c×\90 ×\94×\92רס×\94 ×\94×\90×\97ר×\95× ×\94",
+       "rcfilters-filter-previousrevision-description": "כל השינויים שאינם \"הגרסה האחרונה\".",
        "rcfilters-filter-excluded": "מוחרג",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:לא</strong> $1",
        "rcfilters-exclude-button-off": "להחריג את המסומנים",
        "delete-warning-toobig": "דף זה כולל מעל {{PLURAL:$1|גרסה אחת|$1 גרסאות}} בהיסטוריית העריכות שלו. מחיקה שלו עלולה להפריע לפעולות בבסיס הנתונים; אנא שקלו שנית את המחיקה.",
        "deleteprotected": "אין {{GENDER:|באפשרותך|באפשרותך|באפשרותכם}} למחוק את הדף כי הוא מוגן.",
        "deleting-backlinks-warning": "<strong>אזהרה:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|דפים אחרים]] מקשרים לדף ש{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} למחוק או מכלילים אותו.",
+       "deleting-subpages-warning": "<strong>אזהרה:</strong> לדף ש{{GENDER:|אתה עומד|את עומדת|אתם עומדים}} למחוק יש [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|דף משנה|$1 דפי משנה|51=יותר מ־50 דפי משנה}}]].",
        "rollback": "שחזור עריכות",
        "rollbacklink": "שחזור",
        "rollbacklinkcount": "שחזור {{PLURAL:$1|עריכה אחת|$1 עריכות}}",
index 3fb2671..71d2828 100644 (file)
        "rcfilters-filterlist-noresults": "Nema filtera",
        "rcfilters-noresults-conflict": "Rezultati pretrage nisu pronađeni zbog sukoba kriterija pretrage",
        "rcfilters-state-message-fullcoverage": "Označavanje svih filtera u grupi je isto kao da nije označen niti jedan, tako da filter nema učinka. Grupa uključuje: $1",
-       "rcfilters-filtergroup-registration": "Registracija suradnika",
-       "rcfilters-filter-registered-label": "Prijavljeni",
-       "rcfilters-filter-registered-description": "Prijavljeni suradnici.",
-       "rcfilters-filter-unregistered-label": "Neprijavljeni",
-       "rcfilters-filter-unregistered-description": "Suradnici koji nisu prijavljeni.",
        "rcfilters-filtergroup-authorship": "Doprinosi prema autorima",
        "rcfilters-filter-editsbyself-label": "Uređivanja koja ste Vi napravili",
        "rcfilters-filter-editsbyself-description": "Vaša uređivanja.",
        "rcfilters-filter-editsbyother-label": "Promjene drugih suradnika",
        "rcfilters-filter-editsbyother-description": "Sve promjene osim Vaših.",
        "rcfilters-filtergroup-userExpLevel": "Napredna razina (samo za registrirane suradnike)",
+       "rcfilters-filter-user-experience-level-registered-label": "Prijavljeni",
+       "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni suradnici.",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Neprijavljeni",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Suradnici koji nisu prijavljeni.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Novopridošli",
        "rcfilters-filter-user-experience-level-newcomer-description": "Manje od 10 uređivanja i 4 dana aktivnosti.",
        "rcfilters-filter-user-experience-level-learner-label": "Početnici",
index 0008dc3..0d5f58a 100644 (file)
        "rcfilters-filter-editsbyself-description": "I tuoi contributi.",
        "rcfilters-filter-editsbyother-label": "Modifiche di altri",
        "rcfilters-filter-editsbyother-description": "Tutte le modifiche eccetto le tue.",
-       "rcfilters-filtergroup-userExpLevel": "Registrazione ed esperienza",
+       "rcfilters-filtergroup-userExpLevel": "Registrazione utente ed esperienza",
        "rcfilters-filter-user-experience-level-registered-label": "Registrato",
        "rcfilters-filter-user-experience-level-registered-description": "Contributori che hanno effettuato l'accesso.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Non registrato",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Il filtro \"Modifiche minori\" è in confitto con uno o più dei filtri \"Tipo di modifica\", perché certe modifiche non possono essere indicate come \"minori\". I filtri in conflitto sono indicati nell'area \"Filtri attivi\" qui sopra.",
        "rcfilters-hideminor-conflicts-typeofchange": "Alcuni tipi di modifiche non possono essere indicate come \"minori\", quindi questo filtro è in conflitto con i seguenti filtri \"Tipo di modifica\": $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Questo filtro \"Tipo di modifica\" è in conflitto con il filtro \"Modifiche minori\". Alcuni tipi di modifiche non possono essere indicati come \"minori\".",
-       "rcfilters-filtergroup-lastRevision": "Ultima versione",
-       "rcfilters-filter-lastrevision-label": "Ultima versione",
-       "rcfilters-filter-lastrevision-description": "Le ultime modifiche ad una pagina.",
-       "rcfilters-filter-previousrevision-label": "Versioni precedenti",
-       "rcfilters-filter-previousrevision-description": "Tutte le modifiche che non sono l'ultima modifica effettuata sulla voce.",
+       "rcfilters-filtergroup-lastRevision": "Ultime versioni",
+       "rcfilters-filter-lastrevision-label": "Versione attuale",
+       "rcfilters-filter-lastrevision-description": "Solo l'ultima modifica ad una pagina.",
+       "rcfilters-filter-previousrevision-label": "Non l'ultima versione",
+       "rcfilters-filter-previousrevision-description": "Tutte le modifiche che non sono la \"versione attuale\".",
        "rcfilters-filter-excluded": "Escluso",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:non</strong> $1",
        "rcfilters-exclude-button-off": "Escludi selezionato",
        "delete-warning-toobig": "La cronologia di questa pagina è molto lunga (oltre $1 {{PLURAL:$1|versione|versioni}}). La sua cancellazione può creare dei problemi di funzionamento al database di {{SITENAME}}; procedere con cautela.",
        "deleteprotected": "Non puoi cancellare questa pagina perché è stata protetta.",
        "deleting-backlinks-warning": "<strong>Attenzione:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|altre pagine]] contengono collegamenti o inclusioni alla pagina che stai per cancellare.",
+       "deleting-subpages-warning": "<strong>Attenzione:</strong> la pagina che stai per cancellare ha [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|una sotto-pagina|$1 sotto-pagine|51=più di 50 sotto-pagine}}]].",
        "rollback": "Annulla le modifiche",
        "rollbacklink": "rollback",
        "rollbacklinkcount": "rollback di {{PLURAL:$1|una modifica|$1 modifiche}}",
index 4fd7a36..5ba16e7 100644 (file)
        "rcfilters-legend-heading": "<strong>약어 목록:</strong>",
        "rcfilters-activefilters": "사용 중인 필터",
        "rcfilters-advancedfilters": "고급 필터",
+       "rcfilters-limit-shownum": "최근 $1개의 변경사항 표시",
        "rcfilters-days-show-days": "$1{{PLURAL:$1|일}}",
        "rcfilters-days-show-hours": "$1{{PLURAL:$1|시간}}",
        "rcfilters-quickfilters": "저장된 필터",
        "rcfilters-filter-editsbyself-description": "당신의 기여.",
        "rcfilters-filter-editsbyother-label": "다른 사용자의 변경사항",
        "rcfilters-filter-editsbyother-description": "당신을 제외한 모든 변경사항.",
-       "rcfilters-filtergroup-userExpLevel": "경험 수준 (등록된 사용자만)",
+       "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-hideminor-conflicts-typeofchange-global": "특정한 유형의 변경사항을 \"사소한 편집\"으로 지정할 수 없기 때문에 \"사소한 편집\" 필터는 하나 이상의 변경사항 유형 필터와 충돌합니다. 충돌되는 필터들은 위의 사용 중인 필터 영역에 표시됩니다.",
        "rcfilters-hideminor-conflicts-typeofchange": "특정한 종류의 변경사항은 \"사소한 편집\"으로 지정할 수 없으므로 이 필터는 다음 유형의 변경사항 필터와 충돌합니다: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "이 유형의 변경사항 필터는 \"사소한 편집\" 필터와 충돌합니다. 특정한 종류의 변경사항은 \"사소한 편집\"으로 지정할 수 없습니다.",
-       "rcfilters-filtergroup-lastRevision": "마지막 판",
-       "rcfilters-filter-lastrevision-label": "마지막 판",
-       "rcfilters-filter-lastrevision-description": "문서의 최근 변경사항입니다.",
-       "rcfilters-filter-previousrevision-label": "ì\9d´ì \84 í\8c\90",
-       "rcfilters-filter-previousrevision-description": "문서에 대한 최근 변경사항이 아닌 모든 변경사항입니다.",
+       "rcfilters-filtergroup-lastRevision": "최신판",
+       "rcfilters-filter-lastrevision-label": "최신판",
+       "rcfilters-filter-lastrevision-description": "문서의 최근 변경사항입니다.",
+       "rcfilters-filter-previousrevision-label": "ìµ\9cì\8b í\8c\90ì\9d´ ì\95\84ë\8b\98",
+       "rcfilters-filter-previousrevision-description": "\"최신판\"이 아닌 모든 변경사항입니다.",
        "rcfilters-filter-excluded": "제외됨",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:아님</strong> $1",
        "rcfilters-view-tags": "태그된 편집",
        "delete-warning-toobig": "이 문서에는 {{PLURAL:$1|편집 역사}}가 $1개 있습니다.\n편집 역사가 긴 문서를 삭제하면 {{SITENAME}} 데이터베이스 동작에 큰 영향을 줄 수 있습니다.\n주의해 주세요.",
        "deleteprotected": "이 문서가 보호되어 있기 때문에 삭제할 수 없습니다.",
        "deleting-backlinks-warning": "<strong>경고:</strong> 삭제하려는 문서가 [[Special:WhatLinksHere/{{FULLPAGENAME}}|다른 문서]]에 링크되어 있거나 끼워져 있습니다.",
+       "deleting-subpages-warning": "<strong>경고:</strong> 삭제하려는 문서에 [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|하나의 하위 문서|$1개의 하위 문서|51=50개 이상의 하위 문서}}]]가 있습니다.",
        "rollback": "편집 되돌리기",
        "rollbacklink": "되돌리기",
        "rollbacklinkcount": "{{PLURAL:$1|편집}} $1회 되돌리기",
index 3718d88..4c61064 100644 (file)
        "rcfilters-legend-heading": "<strong>Lëscht vun Ofkierzungen:</strong>",
        "rcfilters-activefilters": "Aktiv Filteren",
        "rcfilters-advancedfilters": "Erweidert Filteren",
+       "rcfilters-limit-title": "Ännerunge fir ze weisen",
+       "rcfilters-limit-shownum": "Lescht $1 Ännerunge weisen",
+       "rcfilters-days-title": "Rezent Deeg",
+       "rcfilters-hours-title": "Rezent Stonnen",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|Dag|Deeg}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|Stonn|Stonnen}}",
        "rcfilters-quickfilters": "Gespäichert Filteren",
        "rcfilters-quickfilters-placeholder-title": "Nach keng Linke gespäichert",
        "rcfilters-quickfilters-placeholder-description": "Fir Är Filterastellungen z'änneren a méi spéit nees ze benotzen, klickt op d'Zeeche  fir Lieszeechen (bookmark) am Beräich vun den Aktive Filteren hei drënner.",
        "rcfilters-invalid-filter": "Net valabele Filter",
        "rcfilters-empty-filter": "Keen aktive Filter. All Kontributioune gi gewisen.",
        "rcfilters-filterlist-title": "Filteren",
-       "rcfilters-filterlist-whatsthis": "Wat ass dat?",
+       "rcfilters-filterlist-whatsthis": "Wéi geet dat?",
        "rcfilters-highlightbutton-title": "Resultater ervirhiewen",
        "rcfilters-highlightmenu-title": "Eng Faarf eraussichen",
        "rcfilters-filterlist-noresults": "Keng Filtere fonnt",
        "rcfilters-hideminor-conflicts-typeofchange": "Verschidden Type vu Ännerunge kënnen net als \"kleng\" markéiert ginn, dofir ass dëse Filter a Konflikt mat dësem Typ vun Ännerungsfilteren: $1",
        "rcfilters-filtergroup-lastRevision": "Lescht Versioun",
        "rcfilters-filter-lastrevision-label": "Lescht Versioun",
-       "rcfilters-filter-lastrevision-description": "Déi lescht Ännerung op enger Säit",
-       "rcfilters-filter-previousrevision-label": "Méi fréi Versiounen",
+       "rcfilters-filter-lastrevision-description": "Nëmmen déi lescht Ännerung op enger Säit.",
+       "rcfilters-filter-previousrevision-label": "Net déi lescht Versioun",
        "rcfilters-filter-previousrevision-description": "All Ännerungen, déi net déi rezenst Ännerung vun enger Säit sinn.",
        "rcfilters-filter-excluded": "Ausgeschloss",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:net</strong> $1",
index 96c2aa3..9a702b8 100644 (file)
        "changepassword-success": "Dien wachwaord is verangerd!",
        "changepassword-throttled": "Doe höbs te huifig geperbeerd aan te melje.\nDoe mós effe $1 wachte ierdets te 't obbenuuts kens perbere.",
        "botpasswords": "Botwachwäörd",
+       "botpasswords-summary": "<em>Botwachwäörd</em> zörge veur tougank tot de API via 'ne gebroeker zónger gebroek te make van aanmeljgegaeves van daen gebroeker. De gebroekersrechte die besjikbaar zint kónne aafwieke wen me is aangemeldj mit e botwachwaord.\n\nWen se neet wèts waat hie de gevölge van zeen den is 't henjiger dit neet te doon. Nemes huuert dich te vraoge e botwachwaord aan te make en dem aan hem door te gaeve.",
        "botpasswords-disabled": "Botwachwäörd zint oetgezatj.",
        "botpasswords-no-central-id": "Veur botwachwäörd te gebroeke mós se aangemeldj zeen mit 'ne gecentraliseerdje gebroeker.",
        "botpasswords-existing": "Bestaonde botwachwäörd",
        "botpasswords-updated-body": "'t Botwachwaord veur de botnaam \"$1\" van gebroeker \"$2\" is biegewirk.",
        "botpasswords-deleted-title": "Botwachwaord eweggesjaf",
        "botpasswords-deleted-body": "'t Botwachwaord veure botnaam \"$1\" vanne gebroeker \"$2\" is eweggesjaf.",
+       "botpasswords-newpassword": "'t Nuuj wachwaord veur aan te melje mit <strong>$1</strong> is <strong>$2</strong>. <em>Bewaar dit goed voor toekomstig gebruik.</em> <br> (Veur aaj bots die vereisje det de aameljnaam 'tzelfde is es d'n eventuele gebroekersnaam, kan ouch <strong>$3</strong> es gebroekersnaam en <strong>$4</strong> es wachwaord waere gebroek.)",
+       "botpasswords-no-provider": "BotPasswordsSessionProvider is neet besjikbaar.",
+       "botpasswords-restriction-failed": "Botwachwaordbepirkinge verkómme aanmelje.",
+       "botpasswords-invalid-name": "De gebroekersnaam bevatj neet 't sjeijingsteike van 't botwachwaord (\"$1\").",
+       "botpasswords-not-exist": "Gebroekers \"$1\" haet gei botwachwaord genaamp \"$2\".",
        "resetpass_forbidden": "Wachwäörd kónne neet verangerd waere",
+       "resetpass_forbidden-reason": "Wachwäörd kónne neet verangerd waere: $1",
        "resetpass-no-info": "Doe moos aangemeld zien ierdets doe dees pagina gebroeke kens.",
        "resetpass-submit-loggedin": "Wachwaord wiezige",
        "resetpass-submit-cancel": "Aafbraeke",
        "resetpass-wrong-oldpass": "'t Hujig of tiedelik wachwaord is ongeljig.\nMeugelik höbs doe dien wachwaord al gewiezig of 'n nuuj tiedelik wachwaord aangevraog.",
+       "resetpass-recycled": "Veranger die wachwaord nao get anges es 't hujig wachwaord.",
+       "resetpass-temp-emailed": "Doe bös aangemeldj mit 'n tiejelike code die se per e-mail höbs gekrege.\nVeur 't aanmelje aaf te make mós se hie e nuuj wachwaord instèlle:",
        "resetpass-temp-password": "Tiedelik wachwaord:",
+       "resetpass-abort-generic": "De wachwaordverangering is aafgebraoke door 'n oetbreijing.",
+       "resetpass-expired": "Die wachwaord is verloupe. Stèl e nuuj wachwaord in veur dich aan te melje.",
+       "resetpass-expired-soft": "Die wachwaord is verloupe en mót oppernuuj waeren ingestèldj.\nKees noe e nuuj wachwaord of klik op \"{{int:authprovider-resetpass-skip-label}}\" veur dit spaejer te doon.",
+       "resetpass-validity-soft": "Die wachwaord is neet geljig: $1\n\nKees noe e nuuj wachwaord of klik op \"{{int:authprovider-resetpass-skip-label}}\" veur dit spaejer oppernuuj in te stèlle.",
        "passwordreset": "Wachwaord obbenuuts insjtèlle",
+       "passwordreset-text-one": "Völ dit formeleer in veur die wachwaord oppernuuj in te stèlle (doe kriegs e berich via de e-mail).",
+       "passwordreset-text-many": "{{PLURAL:$1|Völ ei van de gegaevesveljer in veur per e-mail e tiedelijk wachwaord te kriege.}}",
        "passwordreset-disabled": "'t Is hie neet meugelik óm die wachwaord óbbenuits in te sjtelle.",
+       "passwordreset-emaildisabled": "E-mailmeugelikheje staon oet op deze wiki.",
        "passwordreset-username": "Gebroekersnaam:",
        "passwordreset-domain": "Domein:",
        "passwordreset-email": "E-mailadres:",
        "passwordreset-emailtitle": "Gebroekersgegaeves óp {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Emes, wersjienlik doe, vanaaf 't IP-adres $1, haet dien gebroekersgegaeves veur {{SITENAME}} ($4) ópgevraog.\nDe volgende {{PLURAL:$3|gebroeker is|gebroekers zint}} gekoppeld aan dit e-mailadres:\n\n$2\n\n{{PLURAL:$3|Dit tiedelik wachwaord vervilt|Dees tiedelike wachweurd vervallen}} euver {{PLURAL:$5|einen daag|$5 daag}}.\nMel dich aan en veranger 't wachwaord noe. Es se dit verzeuk neet zelf hes gedaon, of es se 't oorspronkelik wachwaord nog kins en 't neet anges wils, laot dit berich den en blief dien aad wachwaord gebroeke.",
-       "passwordreset-emailtext-user": "Gebroeker $1 op de site {{SITENAME}} haet dien gebroekersgegaeves veur {{SITENAME}} ($4) ópgevraog.\nDe volgende {{PLURAL:$3|gebroeker is|gebroekers zint}} gekoppeld aan dit e-mailadres:\n\n$2\n\n{{PLURAL:$3|Dit tiedelik wachwaord vervilt|Dees tiedelike wachweurd vervallen}} euver {{PLURAL:$5|einen daag|$5 daag}}.\nMel dich aan en veranger 't wachwaord noe. Es se dit verzeuk neet zelf hes gedaon, of es se 't oorspronkelik wachwaord nog kins en 't neet anges wils, laot dit berich den en blief dien aad wachwaord gebroeke.",
+       "passwordreset-emailtext-ip": "Emes, wersjienlik doe, vanaaf 't IP-adres $1, haet dien gebroekersgegaeves veur {{SITENAME}} ($4) ópgevraog veur 't wachwaord oppernuuj in te stèlle.\nDe volgende {{PLURAL:$3|gebroeker is|gebroekers zint}} gekoppeld aan dit e-mailadres:\n\n$2\n\n{{PLURAL:$3|Dit tiedelik wachwaord vervilt|Dees tiedelike wachweurd vervallen}} euver {{PLURAL:$5|einen daag|$5 daag}}.\nMel dich aan en veranger 't wachwaord noe. Es se dit verzeuk neet zelf hes gedaon, of es se 't oorspronkelik wachwaord nog kins en 't neet anges wils, laot dit berich den en blief dien aad wachwaord gebroeke.",
+       "passwordreset-emailtext-user": "Gebroeker $1 op de site {{SITENAME}} haet dien gebroekersgegaeves veur {{SITENAME}} ($4) ópgevraog veur die wachwaord oppernuuj in te stèlle.\nDe volgende {{PLURAL:$3|gebroeker is|gebroekers zint}} gekoppeld aan dit e-mailadres:\n\n$2\n\n{{PLURAL:$3|Dit tiedelik wachwaord vervilt|Dees tiedelike wachweurd vervallen}} euver {{PLURAL:$5|einen daag|$5 daag}}.\nMel dich aan en veranger 't wachwaord noe. Es se dit verzeuk neet zelf hes gedaon, of es se 't oorspronkelik wachwaord nog kins en 't neet anges wils, laot dit berich den en blief dien aad wachwaord gebroeke.",
        "passwordreset-emailelement": "Gebroekersnaam: \n$1\n\nTiedelik wachwaord: \n$2",
-       "passwordreset-emailsentemail": "d'r Is per mail 'n herinnering versjik.",
+       "passwordreset-emailsentemail": "Es dit e-mailadres aan diene gebroeker is gekoppeldj, den weurt 'nen e-mail gesjik veur die wachwaord oppernuuj in te stèlle.",
+       "passwordreset-emailsentusername": "Wen 'n e-mailadres is geregistreerd veur daen gebroekersnaam, den weurt 'nen e-mail gesjik veur die wachwaord oppernuuj in te stèlle.",
+       "passwordreset-nocaller": "'nen Aanroper mót waeren opgegaove",
        "passwordreset-nosuchcaller": "Aanroper besteit neet: $1",
-       "changeemail": "Veranger dien e-mailadres",
-       "changeemail-header": "Veranger 't e-mailadres van miene gebroekersnaam",
+       "passwordreset-ignored": "'t Oppernuuj instèlle van 't wachwaord is neet aafgehanjeldj gewaore.\nMesjiens steit geine provider geconfigureerdj?",
+       "passwordreset-invalidemail": "Óngeljig e-mailadres",
+       "passwordreset-nodata": "Zowaal geine gebroekersnaam es 'n e-mailadres is opgegaove gewaore",
+       "changeemail": "Veranger of haol dien e-mailadres eweg",
+       "changeemail-header": "Völ dit formeleer in veur dien e-mailadres te verangere. Wens se 't e-mailadres wils óntkoppele van diene gebroeker, laot 't e-mailadres den laeg wens se 't formeleer opsleis.",
        "changeemail-no-info": "Doe moos aangemeld zien ierdets doe dees pagina gebroeke kens.",
        "changeemail-oldemail": "Hujig mailadres:",
        "changeemail-newemail": "Nuuj mailadres:",
+       "changeemail-newemail-help": "Laot dit veldj laeg wens se dien e-mailadres eweg wils haole. Nao 't ewegsjaffe kóns se nimmieë e vergaete wachwaord oppernuuj instèlle en kriegs se gein e-mails mieë van deze wiki.",
        "changeemail-none": "(gein)",
+       "changeemail-password": "Die wachwaord veur {{SITENAME}}:",
        "changeemail-submit": "Veranger e-mail",
+       "changeemail-throttled": "Doe höbs te huifig geperbeerd dit aan te melje.\nDoe mós effe $1 wachte ierdets te 't obbenuuts kens perbere.",
+       "changeemail-nochange": "Veur 'n anger e-mailadres in.",
+       "resettokens": "Stèl teikes oppernuuj in",
+       "resettokens-no-tokens": "'t Geuf gein teikes veur oppernuuj in te stèlle.",
+       "resettokens-tokens": "Teikes:",
+       "resettokens-token-label": "$1 (hujige waerd: $2)",
+       "resettokens-watchlist-token": "Teike veur webfeed van [[Special:Watchlist|dien volglies]] (Atom/RSS)",
+       "resettokens-done": "Teikes oppernuuj ingestèldj.",
+       "resettokens-resetbutton": "Stèl gesillekteerde teikes oppernuuj in",
        "bold_sample": "Vètten teks",
        "bold_tip": "Vetten teks",
        "italic_sample": "Sjuunsen tèks",
        "sig_tip": "Dien handjteikening mit datum en tied",
        "hr_tip": "Horizontaal lien (gebroek spaarzaam)",
        "summary": "Samevatting:",
-       "subject": "Ongerwerp/kop:",
+       "subject": "Óngerwirp:",
        "minoredit": "Dit is 'n klein verangering",
        "watchthis": "Volg dees pagina",
-       "savearticle": "Pagina opsjlaon",
+       "savearticle": "Sjlaon pagina op",
+       "savechanges": "Slaon verangeringe op",
        "publishpage": "Pagina publicere",
        "publishchanges": "Verangeringe publicere",
        "preview": "Naokieke",
        "showpreview": "Betrach dees bewirking",
        "showdiff": "Toen verangeringe",
+       "blankarticle": "<strong>Waorsjoewing:</strong> de pagina die se wils aanmake is laeg.\nWens se oppernuuj op \"$1\" kliks, wuuertj de pagina aangemaak zónger welchen inhawd den ouch.",
        "anoneditwarning": "<strong>Waorsjoewing:</strong> Doe bös neet aangemeldj.\nDien IP-adres wuuertj opgeslage wen se verangeringe maaks op dees pagina. Wens doe <strong>[$1 dich aanmeljs]</strong> of <strong>[$2 'ne gebroeker aanmaaks]</strong> versjiene dien bewirkinge ónger diene gebroekersnaam, naeve anges veurdeiler.",
        "anonpreviewwarning": "''Doe bös neet aangemeldj.''\n''Door dien bewèrking op te slaon wört dien IP-adres opgeslagen in de paginagesjiedenis.''",
        "missingsummary": "'''Herinnering:''' doe höbs gein samevatting opgegaeve veur dien bewirking. Es te weer op ''Pagina opslaon'' kliks weurt de bewirking zonger samevatting opgesjlage.",
+       "selfredirect": "<strong>Waorsjoewing:</strong> Doe höbs 'ne redirek gemaak nao dees pagina.\nMeugelik höbs se 'n verkieërdje bestumming veure redirek gebroek of bewirks se de verkieërdje pagina.\nDoor nans op \"$1\" te klikke wuuertj de redirek tonna gemaak.",
        "missingcommenttext": "Plaats dien opmèrking hiej onger, a.u.b.",
        "missingcommentheader": "'''Let op:''' Doe höbs gén ongerwerp/kop veur deze opmèrking opgegaeve. Esse oppernuuj op \"$1\" kliks, wörd dien verangering zonger ongerwerp/kop opgeslage.",
-       "summary-preview": "Naokieke samevatting:",
-       "subject-preview": "Naokieke ongerwerp/kop:",
+       "summary-preview": "Veurvertoeaning van de bewirkingssamevatting:",
+       "subject-preview": "Veurvertoeaning van 't óngerwirp:",
+       "previewerrortext": "'n Fout is opgetraoje tiejes 't waergaeve van dien verangeringe.",
        "blockedtitle": "Gebroeker is geblokkeerd",
        "blockedtext": "'''Dien gebroekersaccount of IP-adres is geblokkeerd.'''\n\nDe blokkade is oetgeveurd door $1. De opgegaeve raej is ''$2''.\n\n* Aanvang blokkade: $8\n* Ènj blokkade: $6\n* Bedoeld te blokkere: $7\n\nDe kèns contak opnumme mit $1 of 'ne angere [[{{MediaWiki:Grouppage-sysop}}|systeemwèrker]] óm de blokkade te besjpraeke.\nDe kèns gein gebroek make van de functie 'e-mail deze gebroeker', behauve es te 'n geldig e-mailadres höbs opgegaeve in dien [[Special:Preferences|veurkäöre]] en 't gebroek van deze fónksie neet geblokkeerd is.\nDien hujig IP-adres is $3 en 't nómmer van de blokkade is #$5. Vermeld beide gegaeves wens te örges op dees blokkade reageers.",
        "autoblockedtext": "Dien IP-adres is automatisch geblokkeerd omdet 't gebroek is door 'ne gebroeker, dae is geblokkeerd door $1.\nDe opgegaeve reje is:\n\n:''$2''\n\n* Aanvang blokkade: $8\n* Einde blokkade: $6\n* Blóksmeining: $7\n\nDoe kins deze blokkaasj bespraeke mèt $1 of 'ne angere [[{{MediaWiki:Grouppage-sysop}}|beheerder]]. Doe kins gén gebroek make van de functie 'e-mail deze gebroeker', tenzijse 'n geldig e-mailadres opgegaeve höbs in dien [[Special:Preferences|veurkeure]] en 't gebroek van deze functie neet is geblokkeerd.\n\nDien nömmer vanne blokkaasj is #$5 èn dien IP-adres is $3.\nVermeld det esse örges euver deze blokkaasj reageers.",
        "edit-gone-missing": "De pagina is neet biegewirk.\nZe lik eweggesjaf te zien.",
        "edit-conflict": "Bewirkingsconflik.",
        "edit-no-change": "Dien bewirking is genegeerd, ómdet d'r gein verangering in de teks is gemaak.",
+       "postedit-confirmation-created": "De pagina is aangemaak gewaore.",
+       "postedit-confirmation-restored": "De pagina is herstèldj gewaore.",
        "postedit-confirmation-saved": "Dien bewirking is opgeslage gewaore.",
        "edit-already-exists": "De pagina is neet aangemaak.\nZie besjteit al.",
        "defaultmessagetext": "Obligaten teks",
+       "invalid-content-data": "Óngeljige inhawdsgegaeves",
        "editwarning-warning": "Es se dees pagina verleets verluus se meugelik wieziginge die se haes gemaak.\nEs se bös aangemeld, kins se dees waorsjoewing oetzètten in 't bewerkingstabblaad in dien veurkäöre.",
+       "editpage-invalidcontentmodel-title": "Inhaadsmodel wuuertj neet óngersteund",
+       "editpage-invalidcontentmodel-text": "'t Inhawdsmodel \"$1\" weurt neet óngersteund",
+       "editpage-notsupportedcontentformat-title": "Inhawdsformaat neet óngersteund",
+       "editpage-notsupportedcontentformat-text": "'t Inhawdstype $1 weurt neet óngersteund door 't inhawdsmodel $2.",
        "content-model-wikitext": "wikiteks",
        "content-model-text": "teks zónger opmaak",
        "content-model-javascript": "JavaScript",
        "content-json-empty-object": "Laeg objek",
        "content-json-empty-array": "Laege rits",
+       "deprecated-self-close-category": "Pagina's mit óngeljige zelfsloetende HTML-tags",
        "expensive-parserfunction-warning": "'''Waarschuwing:''' dees pagina gebroek te väöl kosbare parserfuncties.\n\nNoe {{PLURAL:$1|is|zeen}} 't d'r $1, terwiel 't d'r minder es $2 {{PLURAL:$2|mótte|mótte}} zeen.",
        "expensive-parserfunction-category": "Pagina's die te väöl kosbare parserfuncties gebroeke",
        "post-expand-template-inclusion-warning": "Waorsjuwing: de maximaal transclusiegruudje veur sjablone is euversjri-jje.\nSommige sjablone waere neet getranscludeerd.",
        "revdelete-hide-user": "Verberg gebroekersnaam/IP van de gebroeker",
        "revdelete-hide-restricted": "Pas deze beperkinge toe op zowaal beheerders es angere",
        "revdelete-radio-same": "(anger neet)",
-       "revdelete-radio-set": "Jao",
-       "revdelete-radio-unset": "Nein",
+       "revdelete-radio-set": "Verstaoke",
+       "revdelete-radio-unset": "Zichbaar",
        "revdelete-suppress": "Ongerdruk gegaeves veur zowaal admins es angere",
        "revdelete-unsuppress": "Verwijder beperkinge op truuk gezatte wieziginge",
        "revdelete-log": "Reeje:",
        "revdelete-submit": "Pas toe op de geselecteerde {{PLURAL:$1|bewèrking|bewèrkinger}}",
-       "revdelete-success": "'''Wieziging zichbaarheid succesvol ingesteld.'''",
+       "revdelete-success": "Zichbaarheid van verangering biegewirk.",
        "revdelete-failure": "'''De zichbaarheid veur de versie kos neet ingesteld waere.'''\n$1",
-       "logdelete-success": "'''Zichbaarheid van de gebeurtenis succesvol ingesteld.'''",
+       "logdelete-success": "Zichbaarheid van gebäörtenis is ingestèldj gewaore.",
        "logdelete-failure": "'''De zichbaarheid van de logbookregel kos neet ingesteldj waere:'''\n$1",
        "revdel-restore": "Zichbaarheid verangere",
        "pagehist": "Paginagesjiedenis",
        "editundo": "maak óngedaon",
        "diff-empty": "(gei versjil)",
        "diff-multi-sameuser": "({{PLURAL:$1|Ein tösseligkendje versie|$1 tösseligkendje versies}} door dezelfdje gebroeker neet getoeandj)",
+       "diff-multi-otherusers": "({{PLURAL:$1|Ein tösseligkendje versie|$1 tösseligkendje versies}} door {{PLURAL:$2|einen angere gebroeker|$2 gebroekers}} neet getuind)",
        "diff-multi-manyusers": "($1 tösseligkende versies door mier es $2 gebroekers waere neet waergaeve)",
        "searchresults": "Zeukresultate",
        "searchresults-title": "Zeukresultate veur \"$1\"",
        "notextmatches": "Geen artikel gevonden met opgegeven zoekterm",
        "prevn": "veurige {{PLURAL:$1|$1}}",
        "nextn": "volgende {{PLURAL:$1|$1}}",
+       "prev-page": "veurige pazjena",
+       "next-page": "volgende pazjena",
        "prevn-title": "Vörge {{PLURAL:$1|resultaat|$1 resultate}}",
        "nextn-title": "Volgende {{PLURAL:$1|resultaat|$1 resultate}}",
        "shown-title": "$1 {{PLURAL:$1|resultaat|resultate}} per pagina weergaeve",
        "search-result-category-size": "{{PLURAL:$1|1 categorielid|$1 categorielede}} ({{PLURAL:$2|1 ongercategorie|$2 ongercategorieë}}, {{PLURAL:$3|1 bestandj|$3 bestenj}})",
        "search-redirect": "(redirek vanaaf $1)",
        "search-section": "(subkop $1)",
+       "search-category": "(categorie $1)",
        "search-file-match": "(kump euverein mit de bestandjsinhawd)",
        "search-suggest": "Meins te sóms: $1",
-       "search-interwiki-caption": "Zösterprojecte",
-       "search-interwiki-default": "$1 resultate:",
+       "search-rewritten": "De rizzeltaote veur $1 waere waergaeve. Zeuk inplaats nao $2.",
+       "search-interwiki-caption": "Rizzeltaote van zösterprojecte",
+       "search-interwiki-default": "Rizzeltaote van $1:",
        "search-interwiki-more": "(meer)",
+       "search-interwiki-more-results": "mieë rizzeltaote",
        "search-relatedarticle": "Gerelateerd",
        "searchrelated": "gerelateerd",
        "searchall": "alle",
        "showingresults": "Hieonger staon de <b>$1</b> {{PLURAL:$1|resultaat|resultaat}}, vanaaf #<b>$2</b>.",
        "search-showingresults": "{{PLURAL:$4|Rizzeltaot <strong>$1</strong> van <strong>$2</strong>|Rizzeltaote <strong>$1 - $2</strong> van <strong>$3</strong>}}",
        "search-nonefound": "D'r zien gein resultate veur diene zeukopdrach.",
+       "search-nonefound-thiswiki": "'t Goof gein rizzeltaote veur dien zeukopdrach op dees site.",
        "powersearch-legend": "Oetgebreid zeuke",
        "powersearch-ns": "Zeuke in naamruumdes:",
        "powersearch-togglelabel": "Conterleer:",
        "powersearch-toggleall": "Alle",
        "powersearch-togglenone": "Gein",
+       "powersearch-remember": "Ónthawt selectie veur toukumstige zeukopdrachte",
        "search-external": "Extern zeuke",
        "searchdisabled": "Zeuke op {{SITENAME}} is oetgesjakeld vanweige gebrek aan servercapaciteit.\nZoelang as de servers nog neet sjterk genog zunt kins e zeuke bie Google.\nMèrk op dat hun indexe van {{SITENAME}} content e bietje gedatierd kint zien.",
+       "search-error": "'n Fout is opgetraoje tiedes 't zeuke: $1",
+       "search-warning": "'n Waorsjoewing is opgetraoje tiedes 't zeuke: $1",
        "preferences": "Veurkäöre",
        "mypreferences": "Veurkäöre",
        "prefs-edits": "Aantal bewèrkinge:",
+       "prefsnologintext2": "Doe mós aanmelje veur dien veurkäöre in te stèlle.",
        "prefs-skin": "{{SITENAME}}-uterlik",
        "skin-preview": "Veurbesjouwing",
        "datedefault": "Gein veurkäör",
        "prefs-personal": "Gebroekersinfo",
        "prefs-rc": "Recènte verangeringe en weergaaf van sjtumpkes",
        "prefs-watchlist": "Volglies",
+       "prefs-editwatchlist": "Bewirk volglies",
+       "prefs-editwatchlist-label": "Bewirk items op dien volglies:",
+       "prefs-editwatchlist-edit": "Betrach en haol items op dien volglies eweg",
+       "prefs-editwatchlist-raw": "Bewirk roew volglies",
+       "prefs-editwatchlist-clear": "Maak dien volglies laeg",
        "prefs-watchlist-days": "Te tuine daag in de volglies:",
        "prefs-watchlist-days-max": "Maximaal $1 {{PLURAL:$1|daag|daag}}",
        "prefs-watchlist-edits": "Maximaal aantal bewirkinge in de oetgebreide volglies:",
        "prefs-watchlist-token": "Volgliessläötel:",
        "prefs-misc": "Anger insjtèllinge",
        "prefs-resetpass": "Wachwaord wiezige",
-       "prefs-changeemail": "Veranger e-mail",
+       "prefs-changeemail": "Veranger of haol dien e-mailadres eweg",
        "prefs-setemail": "Stel 'n e-mailadres in",
        "prefs-email": "E-mailopsjes",
        "prefs-rendering": "Oeterlik",
        "saveprefs": "Veurkäöre opsjlaon",
-       "restoreprefs": "Terug nao standaardinstellinge",
+       "restoreprefs": "Herstèl dien veurkäöre (veur alle instèllinge)",
        "prefs-editing": "Aafmeitinge tèksveld",
        "searchresultshead": "Insjtèllinge veur zeukresultate",
-       "stub-threshold": "Drempel veur markering <a href=\"#\" class=\"stub\">begske</a>:",
+       "stub-threshold": "Dörpel veur markering es sjtumpke ($1):",
+       "stub-threshold-sample-link": "veurbild",
        "stub-threshold-disabled": "Oetgezatj",
        "recentchangesdays": "Aantal daag te tuine in de recènte verangeringe:",
        "recentchangesdays-max": "(maximaal $1 {{PLURAL:$1|daag|daag}})",
        "timezoneregion-indian": "Indische Oceaan",
        "timezoneregion-pacific": "Stille Oceaan",
        "allowemail": "E-mail van anger gebroekers toesjtaon",
-       "prefs-searchoptions": "Zeukinstellinge",
+       "prefs-searchoptions": "Zeuke",
        "prefs-namespaces": "Naamruimte",
        "default": "sjtandaard",
        "prefs-files": "Bestenj",
        "prefs-reset-intro": "Gebroek dees functie om dien veurkäöre te herstelle nao de standaardinstellinge.\nDees hanjeling kin neet ongedaon gemaak waere.",
        "prefs-emailconfirm-label": "E-mailbevestiging:",
        "youremail": "Dien e-mailadres",
-       "username": "Gebroekersnaam:",
-       "prefs-memberingroups": "Lid van {{PLURAL:$1|gróp|gróppe}}:",
+       "username": "{{GENDER:$1|Gebroekersnaam}}:",
+       "prefs-memberingroups": "{{GENDER:$2|Lid}} van {{PLURAL:$1|gróp|gróppe}}:",
+       "group-membership-link-with-expiry": "$1 (toet $2)",
        "prefs-registration": "Registratiedatum:",
        "yourrealname": "Dienen echte naam*",
        "yourlanguage": "Taal van de gebroekersinterface",
        "badsiglength": "De handjteikening is te lank.\nZie maag neet mie es $1 {{PLURAL:$1|karakter|karakters}} bevatte.",
        "yourgender": "Geslach:",
        "gender-unknown": "Neet aangegaeve",
-       "gender-male": "Miensj",
-       "gender-female": "Vrów",
+       "gender-male": "Hae bewirk de wiki",
+       "gender-female": "Hèt bewirk de wiki",
        "prefs-help-gender": "Optioneel: dit wört gebroek om gebroekers correk aan te spraeke in de software.\nDeze informatie is zichbaar veur angere gebroekers.",
        "email": "E-mail",
-       "prefs-help-realname": "* Echte naam (opsjeneel): esse deze opgufs kin deze naam gebroek waere om dich erkinning te gaeve veur dien wèrk.",
+       "prefs-help-realname": "Echte naam is optioneel.\nEs se dezen opgeufs, kan deze naam waere gebroek veur dich erkènning te gaeve veur die werk.",
        "prefs-help-email": "E-mailadres is optioneel, mer maak 't muuëgelik óm dich e wachwaord te sjikke es s'n 't vergaete höbs.",
        "prefs-help-email-others": "Doe kans ouch angere in staat stelle per-email kóntak mit uch op te numme via 'n verwiezing op eur gebroekers- en euverlègkpazjena zónger det se diene identiteit luuëts weite.",
        "prefs-help-email-required": "Hiej veur is 'n e-mailadres neudig.",
        "prefs-signature": "Handjteikening",
        "prefs-dateformat": "Datumópmaak:",
        "prefs-timeoffset": "Tiedsversjèl",
-       "prefs-advancedediting": "Wiejer instèllinger",
+       "prefs-advancedediting": "Algemein instèllinge",
+       "prefs-editor": "Bewirker",
+       "prefs-preview": "Veurbesjouwing",
        "prefs-advancedrc": "Wiejer instèllinger",
        "prefs-advancedrendering": "Wiejer instèllinger",
        "prefs-advancedsearchoptions": "Wiejer instèllinger",
        "prefs-advancedwatchlist": "Wiejer instèllinger",
        "prefs-displayrc": "Toeaningsinstèllinger",
        "prefs-displaywatchlist": "Toeaningsinstèllinger",
+       "prefs-tokenwatchlist": "Teike",
        "prefs-diffs": "Vers",
-       "userrights": "Gebroekersrechtebeheer",
-       "userrights-lookup-user": "Beheer gebroekersgróppe",
+       "prefs-help-prefershttps": "Deze veurkäör weurt tougepas bie de volgendje aanmeljing",
+       "prefswarning-warning": "Doe höbs dees verangeringe gemaak in dien veurkäöre die nag neet zint opgeslage. Wen se de pagina verleuts zónger op \"$1\" te klikke waere dien veurkäöre neet biegewirk.",
+       "prefs-tabs-navigation-hint": "Hölp: doe kans de pielkesknuup nao links en rechs broeke veur te navigere tösse de tabblajer inne lies.",
+       "userrights": "Gebroekersrechte",
+       "userrights-lookup-user": "Selecteer 'ne gebroeker",
        "userrights-user-editname": "Veur 'ne gebroekersnaam in:",
-       "editusergroup": "Bewirk gebroekersgróppe",
-       "editinguser": "Bezig mit 't bewèrke van de gebroekersrechte van gebroeker '''[[User:$1|$1]]''' $2",
-       "userrights-editusergroup": "Bewirk gebroekersgróppe",
-       "saveusergroups": "Gebroekersgróppe opsjlaon",
+       "editusergroup": "Laaj gebroekersgruup",
+       "editinguser": "Bezig mit 't verangere van de gebroekersrechte van {{GENDER:$1|gebroeker}} '''[[User:$1|$1]]''' $2",
+       "viewinguserrights": "Gebroekersrechte betrachte van {{GENDER:$1|gebroeker}} <strong>[[User:$1|$1]]</strong> $2",
+       "userrights-editusergroup": "Bewirk {{GENDER:$1|gebroekersgruup}}",
+       "userrights-viewusergroup": "Toean {{GENDER:$1|gebroekersgruup}}",
+       "saveusergroups": "Slaon {{GENDER:$1|gebroekersgruup}} op",
        "userrights-groupsmember": "Leed van:",
        "userrights-groupsmember-auto": "Impliciet lid van:",
-       "userrights-groups-help": "De kèns de gróppe verangere woe deze gebroeker lid van is.\n* 'n Aangekruuts vinkvekske beteikent det de gebroeker lid is van de gróp.\n* 'n Neet aangekruuts vinkvekske beteikent det de gebroeker neet lid is van de gróp.\n* \"*\" Beteikent dets te 'ne gebroeker neet oet 'ne gróp eweg kèns haole naodets te die daobie höbs gedoon, of angersóm.",
+       "userrights-groups-help": "De kèns de gróppe verangere woe deze gebroeker lid van is.\n* 'n Aangekruuts vinkvekske beteikent det de gebroeker lid is van de gróp.\n* 'n Neet aangekruuts vinkvekske beteikent det de gebroeker neet lid is van de gróp.\n* \"*\" beteikent dets te 'ne gebroeker neet oet 'ne gróp eweg kèns haole naodets te die daobie höbs gedoon, of angersóm.\n* \"#\" beteikebt dets te dit grópslidmaotsjap allein kans verlinge. De kans 't neet verkorte.",
        "userrights-reason": "Reeje:",
        "userrights-no-interwiki": "Doe höbs gein rechte om gebroekersrechte op anger wiki's te wiezige.",
        "userrights-nodatabase": "Database $1 besteit neet of is gein plaatselike database.",
        "userrights-changeable-col": "Gróppe dies te kèns behere",
        "userrights-unchangeable-col": "Gróppe dies te neet kèns behere",
+       "userrights-expiry-current": "Verlöp $1",
+       "userrights-expiry-none": "Verlöp neet",
+       "userrights-expiry": "Verlöp:",
+       "userrights-expiry-existing": "Bestaonde verloupdatum: $2 $3",
+       "userrights-expiry-othertime": "Angere doer:",
+       "userrights-expiry-options": "1 daag:1 day,1 waek:1 week,1 maondj:1 month,3 maondj:3 months,6 maondj:6 months,1 jaor:1 year",
+       "userrights-invalid-expiry": "De verloiptied veure groep \"$1\" is óngeljig.",
+       "userrights-expiry-in-past": "De verlouptied veure groep \"$1\" is al gewaes.",
+       "userrights-cannot-shorten-expiry": "Doe kans de verlouptied van 't groepslidmaotsjap van groep \"$1\" neet verkorte. Allein gebroekers mit 't rech óm dees groep tou te veuge of eweg te sjaffe kónne de verlouptied verkorte.",
        "group": "Gróp:",
        "group-user": "Gebroekers",
        "group-autoconfirmed": "Geregistreerde gebroekers",
        "booksources-text": "Hiej onger stuit 'n lies met koppelinge nao anger websites die nuuje of gebroekde beuk verkoupe, en die wellich meer informatie euver 't book detse zeuks höbbe:",
        "booksources-invalid-isbn": "t Ingegaeve ISBN liek neet geldig te zeen.\nControleer of se wellich n fout höbs gemaak bie de inveur.",
        "specialloguserlabel": "Oetveurder:",
-       "speciallogtitlelabel": "Doel (pagina of gebroeker):",
+       "speciallogtitlelabel": "Doel (paginanaam of {{ns:user}}:gebroekersnaam veur gebroeker):",
        "log": "Logbeuk",
        "all-logs-page": "Alle aopenbaar logbeuk",
        "alllogstext": "Dit is 't gecombineerd logbook ven {{SITENAME}}. De kins ouch 'n bepaald logbook keze, of filtere op gebroekersnaam of  pazjena, beide huidlettergeveulig.",
        "watchlist-details": "D'r {{PLURAL:$1|sjteit ein pagina|sjtaon $1 pagina's}} op dien volglies mit oetzunjering van de euverlèkpagina's.",
        "wlheader-enotif": "Doe wörs per e-mail gewaarsjuwd",
        "wlheader-showupdated": "Pazjena's die verangerd zeen saers doe ze veur 't lètste bekeeks sjtaon '''vet'''",
-       "wlnote": "Hieónger {{PLURAL:$1|steit de lètste verangering|staon de lètste $1 verangeringe}} van {{PLURAL:$2|'t lètste oer|de lètste <b>$2</b> oer}} óp $3 óm $4.",
-       "wlshowlast": "Tuin lètste $1 ore $2 daag",
+       "wlnote": "Hieónger {{PLURAL:$1|steit de lètste verangering|staon de lètste <strong>$1</strong> verangeringe}} van {{PLURAL:$2|'t lètste oer|de lètste <strong>$2</strong> oer}} óp $3 óm $4.",
+       "wlshowlast": "Tuin lètste $1 oere $2 daag",
        "watchlist-options": "Opties veur volglies",
        "watching": "Bezig mit plaatse op de volglies...",
        "unwatching": "Oet de volglies aan 't haole...",
        "whatlinkshere-hideredirs": "$1 redireks",
        "whatlinkshere-hidetrans": "$1 transclusies",
        "whatlinkshere-hidelinks": "$1 links",
-       "whatlinkshere-hideimages": "$1 bestandjslinker",
+       "whatlinkshere-hideimages": "$1 bestandjslinke",
        "whatlinkshere-filters": "Filters",
        "autoblockid": "Autoblock #$1",
        "block": "Blok gebroeker",
        "tooltip-feed-rss": "RSS feed veur dees pagina",
        "tooltip-feed-atom": "Atom feed veur dees pagina",
        "tooltip-t-contributions": "Lies mit biedrages van {{GENDER:$1|deze gebroeker}}",
-       "tooltip-t-emailuser": "Sjtuur inne mail noa dizze gebroeker",
+       "tooltip-t-emailuser": "Sjtuur inne mail noa dizze {{GENDER:$1|gebroeker}}",
        "tooltip-t-upload": "Upload besjtande",
        "tooltip-t-specialpages": "Lies van alle speciaal pagina's",
        "tooltip-t-print": "Printvruntelike versie van deze pagina",
        "pageinfo-header-basic": "Basisgegaeves",
        "pageinfo-header-edits": "Bewirkingsgesjiechte",
        "pageinfo-header-restrictions": "Paginabesjirming",
+       "pageinfo-header-properties": "Pagina-eigesjappe",
        "pageinfo-display-title": "Toean paginanaam",
        "pageinfo-default-sort": "Standerd sortering",
        "pageinfo-length": "Paginalingdje (in bytes)",
        "pageinfo-language": "Spraok worin dees pagina steit",
        "pageinfo-content-model": "Paginainhawdmodel",
        "pageinfo-robot-policy": "Robot-indexering",
+       "pageinfo-robot-index": "Tougestange",
+       "pageinfo-robot-noindex": "Neet toegestange",
        "pageinfo-watchers": "Aantal paginavolgers",
+       "pageinfo-few-watchers": "Minder es  {{PLURAL:$1|eine volger|$1 volgers}}",
        "pageinfo-redirects-name": "Aantaal redireks nao dees pagina",
+       "pageinfo-subpages-name": "Subpagina's van dees pagina",
        "pageinfo-firstuser": "Aanmaker",
        "pageinfo-firsttime": "Datum vannen aanmaak",
        "pageinfo-lastuser": "Litste bewirker",
+       "pageinfo-lasttime": "Litste bewirking",
        "pageinfo-edits": "Aantal bewèrkinge",
        "pageinfo-authors": "Aantal versjillende sjrievers",
+       "pageinfo-recent-edits": "Recènte bewirkinge (binne de aafgeloupe $1)",
+       "pageinfo-recent-authors": "Recènte sjrievers",
        "pageinfo-magic-words": "{{PLURAL:$1|Magisch waord|Magische wäörd}} ($1)",
+       "pageinfo-templates": "{{PLURAL:$1|Gebroek sjebloon|Gebroekde sjeblone}} ($1)",
        "pageinfo-toolboxlink": "Pazjena-infermasie",
+       "pageinfo-contentpage": "Getèldj es pagina mit inhawd",
        "pageinfo-contentpage-yes": "Jao",
        "markaspatrolleddiff": "Markeer es gecontroleerd",
        "markaspatrolledtext": "Markeer deze pagina es gecontroleerd",
        "watchlistedit-raw-done": "Dien volglies is biegewirk.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 pazjena is|$1 pazjena's zeen}} toegevoog:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 pazjena is|$1 pazjena's zeen}} eweggesjaf:",
+       "watchlisttools-clear": "Maak de volglies laeg",
        "watchlisttools-view": "Volglies bekieke",
        "watchlisttools-edit": "Volglies bekieke en bewirke",
        "watchlisttools-raw": "Roew volglies bewirke",
        "version-entrypoints": "Ingang-URLs",
        "version-entrypoints-header-entrypoint": "Ingank",
        "version-entrypoints-header-url": "URL",
+       "redirect": "Redirek op bestandj, gebroeker, pagina, versie of log-ID",
+       "redirect-summary": "Dees speciaal pagina verwies door nao e bestandj (es 'ne bestandjsnaam weurt opgegaeve), 'n pagina (es e paginanómmer of versienómmer weurt opgegaeve), 'ne gebroekerspagina (es e gebroekersnómmer weurt opgegaeve) of 'ne logbookregel (es 'n logboekregel-ID weurt opgegaeve). Gebroek: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] of [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Gank",
        "redirect-lookup": "Zeuk op:",
        "redirect-value": "Waerd",
        "tags-description-header": "Volledige beschrieving van betekenis",
        "tags-hitcount-header": "Gelabelde bewerkinge",
        "tags-active-yes": "Jao",
+       "tags-active-no": "Nae",
        "tags-edit": "bewerking",
        "tags-hitcount": "$1 {{PLURAL:$1|wieziging|wieziginge}}",
        "comparepages": "Vergeliek pazjena's",
        "logentry-delete-delete": "$1 {{GENDER:$1|haet}} de pagina $3 gewösj",
        "logentry-delete-restore": "$1 haet de pagina $3 trögkgezat",
        "logentry-delete-event": "$1 haet de zichbaarheid van {{PLURAL:$5|'ne logbookregel|$5 logbookregels}} van $3 gewiezig: $4",
-       "logentry-delete-revision": "$1 haet de zichbaarheid van {{PLURAL:$5|'n versie|$5 versies}} van $3 gewiezig: $4",
+       "logentry-delete-revision": "$1 {{GENDER:$2|haet}} de zichbaarheid van {{PLURAL:$5|'n versie|$5 versies}} van de pagina $3 verangerdj: $4",
        "logentry-delete-event-legacy": "$1 haet de zichbaarheid van logbookregels van $3 gewiezig",
        "logentry-delete-revision-legacy": "$1 haet de zichbaarheid van versies van de pagina $3 gewiezig.",
        "logentry-suppress-delete": "$1 haet de pagina $3 ongerdrök",
        "logentry-move-move_redir": "$1 {{GENDER:$2|verplaatsde}} pagina $3 nao $4 euver 'ne redirek",
        "logentry-move-move_redir-noredirect": "$1 verplaatsde pagina $3 nao $4 euver 'ne redirek zonger 'n doorverwiezing achter te laote",
        "logentry-patrol-patrol": "$1 haet versie $4 van pagina $3 es gecontroleerd gemarkeerd",
-       "logentry-patrol-patrol-auto": "$1 haet versie $4 van pagina $3 autematis es gecontroleerd gemarkeerd",
+       "logentry-patrol-patrol-auto": "$1 {{GENDER:$2|haet}} versie $4 van pagina $3 autematis gemarkeerd es gecontroleerd",
        "logentry-newusers-newusers": "$1 haet 'ne gebroeker aangemaak",
        "logentry-newusers-create": "Gebroeker $1 {{GENDER:$2|is}} aangemaak gewaore",
        "logentry-newusers-create2": "$1 haet 'ne gebroeker $3 aangemaak",
-       "logentry-newusers-autocreate": "De gebroeker $1 is autematis aangemaak",
+       "logentry-newusers-autocreate": "De gebroeker $1 {{GENDER:$2|is}} autematis aangemaak gewaore",
        "logentry-upload-upload": "$1 {{GENDER:$2|loadje}} $3 up",
+       "logentry-upload-overwrite": "$1 {{GENDER:$2|haet}} 'n nuuj versie van $3 hoaggelaje",
        "rightsnone": "(gein)",
        "feedback-adding": "Feedback weurt aan pagina toegevoeg...",
        "feedback-bugcheck": "Good! Kónterleer ef of 't neet al ein vanne [$1 bekèndje bugs] is.",
        "special-characters-group-lao": "Lao",
        "special-characters-group-khmer": "Cambodzjaans",
        "mw-widgets-dateinput-placeholder-day": "JJJJ-MM-DD",
-       "mw-widgets-dateinput-placeholder-month": "JJJJ-MM"
+       "mw-widgets-dateinput-placeholder-month": "JJJJ-MM",
+       "randomrootpage": "Willekäörige wrootpagina"
 }
index 128694d..dbba31b 100644 (file)
        "rcfilters-legend-heading": "<strong>Список на кратенки:</strong>",
        "rcfilters-activefilters": "Активни филтри",
        "rcfilters-advancedfilters": "Напредни филтри",
+       "rcfilters-limit-title": "Промени за приказ",
+       "rcfilters-limit-shownum": "Прикажи ги последните $1 промени",
+       "rcfilters-days-title": "Последниве денови",
+       "rcfilters-hours-title": "Последниве часови",
+       "rcfilters-days-show-days": "{{PLURAL:$1|еден ден|$1 дена}}",
+       "rcfilters-days-show-hours": "{{PLURAL:$1|еден час|$1 часа}}",
        "rcfilters-quickfilters": "Зачувани филтри",
        "rcfilters-quickfilters-placeholder-title": "Засега нема зачувани врски",
        "rcfilters-quickfilters-placeholder-description": "За да ги зачувате вашите филтерски псотавки за да ги употребите другпат, стиснете на иконката за бележник во подрачјето „Активен филтер“ подолу.",
        "rcfilters-invalid-filter": "Неважечки филтер",
        "rcfilters-empty-filter": "Нема активни филтри. Прикажани се сите придонеси.",
        "rcfilters-filterlist-title": "Филтри",
-       "rcfilters-filterlist-whatsthis": "ШÑ\82о Ðµ ова?",
+       "rcfilters-filterlist-whatsthis": "Ð\9aако Ñ\80абоÑ\82и ова?",
        "rcfilters-filterlist-feedbacklink": "Дајте мислење за новите (бета) филтри",
        "rcfilters-highlightbutton-title": "Истакнување на исход",
        "rcfilters-highlightmenu-title": "Изберете боја",
        "rcfilters-filter-editsbyself-description": "Ваши сопствени придонеси.",
        "rcfilters-filter-editsbyother-label": "Туѓи промени",
        "rcfilters-filter-editsbyother-description": "Сите промени направени од други уредници",
-       "rcfilters-filtergroup-userExpLevel": "Корисничка искусност (само за регистрирани)",
+       "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": "Ð\9fомалку од 10 уредувања и 4 дена активност.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "РегиÑ\81Ñ\82Ñ\80иÑ\80ани Ñ\83Ñ\80едниÑ\86и Ñ\81о Ð¿омалку од 10 уредувања и 4 дена активност.",
        "rcfilters-filter-user-experience-level-learner-label": "Ученици",
-       "rcfilters-filter-user-experience-level-learner-description": "Ð\9fоиÑ\81кÑ\83Ñ\81ни Ð¾Ð´ â\80\9eноводоÑ\98денÑ\86иÑ\82еâ\80\9c, Ð½Ð¾ Ð¿Ð¾Ð¼Ð°Ð»ÐºÑ\83 Ð¾Ð´ â\80\9eиÑ\81кÑ\83Ñ\81ниÑ\82е корисници“.",
+       "rcfilters-filter-user-experience-level-learner-description": "РегиÑ\81Ñ\82Ñ\80иÑ\80ани Ñ\83Ñ\80едниÑ\86и Ñ\87ие Ð¸Ñ\81кÑ\83Ñ\81Ñ\82во Ðµ Ð½ÐµÐºÐ°Ð´Ðµ Ð¼ÐµÑ\88Ñ\83 â\80\9eноводоÑ\98денÑ\86иâ\80\9c Ð¸ â\80\9eиÑ\81кÑ\83Ñ\81ни корисници“.",
        "rcfilters-filter-user-experience-level-experienced-label": "Искусни корисници",
-       "rcfilters-filter-user-experience-level-experienced-description": "Ð\9fовеÑ\9cе Ð¾Ð´ 30 Ð´ÐµÐ½Ð° Ð°ÐºÑ\82ивноÑ\81Ñ\82 Ð¸ 500 Ñ\83Ñ\80едÑ\83ваÑ\9aа.",
+       "rcfilters-filter-user-experience-level-experienced-description": "РегиÑ\81Ñ\82Ñ\80иÑ\80ани Ñ\83Ñ\80едниÑ\86и Ñ\81о Ð¿Ð¾Ð²ÐµÑ\9cе Ð¾Ð´ 500 Ñ\83Ñ\80едÑ\83ваÑ\9aа Ð¸ 30 Ð´ÐµÐ½Ð° Ð°ÐºÑ\82ивноÑ\81Ñ\82.",
        "rcfilters-filtergroup-automated": "Автоматизирани придонеси",
        "rcfilters-filter-bots-label": "Ботовски",
        "rcfilters-filter-bots-description": "Уредувања со автоматизирани алатки.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Филтерот „Ситни уредувања“ е спротиставен на еден или повеќе од филтрите за видови измена, бидејќи извеси видови не можат да се означат како ситни. Спротиставените филтри се означени во делот Неактивни филтри погоре.",
        "rcfilters-hideminor-conflicts-typeofchange": "Извезни видови промени не можат да се означат како „ситни“, па затоа овој филтер е во спротиставеност со следниве филтри за видови промени: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Овој филтер за видови промени е во спротиставеност со филтерот „Ситни уредувања“. Извсни видови промени не можат да се означат како „ситни“.",
-       "rcfilters-filtergroup-lastRevision": "Ð\9fоÑ\81ледна Ð¿Ñ\80еÑ\80абоÑ\82ка",
+       "rcfilters-filtergroup-lastRevision": "Ð\9fоÑ\81ледни Ð¿Ñ\80еÑ\80абоÑ\82ки",
        "rcfilters-filter-lastrevision-label": "Последна преработка",
-       "rcfilters-filter-lastrevision-description": "Ð\9dаÑ\98нови Ð¿Ñ\80еÑ\80абоÑ\82ки Ð½Ð° страница.",
-       "rcfilters-filter-previousrevision-label": "Ð\9fÑ\80еÑ\82Ñ\85одни Ð¿Ñ\80еÑ\80абоÑ\82ки",
-       "rcfilters-filter-previousrevision-description": "Сите промени кои не се најнови преработки на страницата.",
+       "rcfilters-filter-lastrevision-description": "Само Ð½Ð°Ñ\98нови Ð¿Ñ\80еÑ\80абоÑ\82ки Ð²Ð¾ страница.",
+       "rcfilters-filter-previousrevision-label": "Ð\9dе Ð¿Ð¾Ñ\81леднаÑ\82а Ð¿Ñ\80еÑ\80абоÑ\82ка",
+       "rcfilters-filter-previousrevision-description": "Сите промени кои не се „последна преработка“.",
        "rcfilters-filter-excluded": "Исклучени",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:не</strong> $1",
+       "rcfilters-exclude-button-off": "Изземи избрано",
+       "rcfilters-exclude-button-on": "Изземи избрано",
        "rcfilters-view-tags": "Означени уредувања",
        "rcfilters-view-namespaces-tooltip": "Филтрирај исход по именски постор",
        "rcfilters-view-tags-tooltip": "Филтрирај исход по уредувачки ознаки",
        "delete-warning-toobig": "Оваа страница има долга историја на уредување, преку $1 {{PLURAL:$1|преработка|преработки}}.\nБришењето може да предизвика проблеми при работењето на базата на податоци на {{SITENAME}};\nпродолжете доколку сте сигруни дека треба тоа да го сторите.",
        "deleteprotected": "Не можете да ја избришете страницава бидејќи е заштитена.",
        "deleting-backlinks-warning": "<strong>Предупредување:</strong>  До страницата што сакате да ја избришете водат [[Special:WhatLinksHere/{{FULLPAGENAME}}|други страници]] или пак се превметнуваат во неа.",
+       "deleting-subpages-warning": "<strong>Предупредување:</strong> Страницата што сакате да ја избришете има [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|потстраница|$1 потстраници|51=преку 50 потстраници}}]].",
        "rollback": "Отповикај промени",
        "rollbacklink": "отповикај",
        "rollbacklinkcount": "отповикај $1 {{PLURAL:$1|уредување|уредувања}}",
index a3b47fb..f98e7f6 100644 (file)
        "minoredit": "Che sī sió siu-kái",
        "watchthis": "Kàm-sī chit ia̍h",
        "savearticle": "Pó-chûn chit ia̍h",
+       "publishpage": "Hoat-pò͘ bûn-chiuⁿ",
+       "publishchanges": "Hoat-pò͘ siu-kái",
        "preview": "Seng khoàⁿ-māi",
        "showpreview": "Seng khoàⁿ-māi",
        "showdiff": "Khòaⁿ kái-piàn ê pō·-hūn",
        "permissionserrorstext-withaction": "Lí bô ún-chún chò $2, in-ūi ē-kha\n{{PLURAL:$1|iân-kò͘|iân-kò͘}}:",
        "recreate-moveddeleted-warn": "'''Sè-jī: Lí taⁿ chún-pī beh khui ê ia̍h, chêng bat hō͘ lâng thâi tiāu koè.''' Lí tio̍h chim-chiok soà-chiap pian-chi̍p chit ia̍h ê pit-iàu-sèng. Chia ū chit ia̍h ê san-tû kì-lo̍k (deletion log) hō͘ lí chham-khó:",
        "edit-conflict": "Siu-kái sio-chhiong",
+       "postedit-confirmation-saved": "Lí ê siu-kái í-keng pó-chûn.",
        "defaultmessagetext": "Siat piān ê bûn-jī",
        "content-model-wikitext": "wikitext",
        "content-model-text": "sûn bûn-pún",
index 21533aa..c06af23 100644 (file)
        "rcfilters-highlightbutton-title": "Uthev resultat",
        "rcfilters-highlightmenu-title": "Vel ein farge",
        "rcfilters-filterlist-noresults": "Fann ingen filter",
-       "rcfilters-filtergroup-registration": "Brukarregistrering",
-       "rcfilters-filter-registered-label": "Registrerte",
-       "rcfilters-filter-registered-description": "Innlogga brukarar.",
-       "rcfilters-filter-unregistered-label": "Uregistrerte",
-       "rcfilters-filter-unregistered-description": "Brukarar som ikkje er innlogga.",
        "rcfilters-filtergroup-authorship": "Forfattar",
        "rcfilters-filter-editsbyself-label": "Endringar av deg",
        "rcfilters-filter-editsbyself-description": "Dine eigne bidrag.",
        "rcfilters-filter-editsbyother-label": "Endringar av andre",
        "rcfilters-filter-editsbyother-description": "Alle endringar utanom dine eigne.",
        "rcfilters-filtergroup-userExpLevel": "Røynslenivå (berre for registrerte brukarar)",
+       "rcfilters-filter-user-experience-level-registered-label": "Registrerte",
+       "rcfilters-filter-user-experience-level-registered-description": "Innlogga brukarar.",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Uregistrerte",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Brukarar som ikkje er innlogga.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Nykomarar",
        "rcfilters-filter-user-experience-level-newcomer-description": "Færre enn 10 endringar og 4 dagar med aktivitet.",
        "rcfilters-filter-user-experience-level-learner-label": "Nybyrjarar",
        "logentry-move-move_redir": "$1 {{GENDER:$2|flytte}} sida $3 til $4 over ei omdirigering",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|flytte}} sida $3 til $4 over ei omdirigering utan å lata etter ei omdirigering",
        "logentry-patrol-patrol": "$1 {{GENDER:$2|merkte}} versjon $4 av sida $3 som patruljert",
-       "logentry-patrol-patrol-auto": "$1{{GENDER:$2| merkte}} automatisk versjon $4 av sida $3 som patruljert",
+       "logentry-patrol-patrol-auto": "$1 {{GENDER:$2|merkte}} automatisk versjon $4 av sida $3 som patruljert",
        "logentry-newusers-newusers": "Brukarkontoen $1 vart {{GENDER:$2|oppretta}}",
        "logentry-newusers-create": "Brukarkontoen $1 vart {{GENDER:$2|oppretta}}",
        "logentry-newusers-create2": "Brukarkontoen $3 vart {{GENDER:$2|oppretta}} av $1",
index 9d1a356..45b8489 100644 (file)
        "rcfilters-legend-heading": "<strong>Wykaz skrótów:</strong>",
        "rcfilters-activefilters": "Aktywne filtry",
        "rcfilters-advancedfilters": "Zaawansowane filtry",
+       "rcfilters-limit-title": "Zmian do pokazania",
+       "rcfilters-limit-shownum": "Pokaż ostatnie $1 zmian",
+       "rcfilters-days-title": "Ostatnich dni",
+       "rcfilters-hours-title": "Ostatnich godzin",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|dzień|dni}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|godzina|godziny|godzin}}",
        "rcfilters-quickfilters": "Zapisane filtry",
        "rcfilters-quickfilters-placeholder-title": "Nie masz jeszcze zapisanych linków",
        "rcfilters-quickfilters-placeholder-description": "Aby zapisać ustawienia filtrów i używać ich później, kliknij ikonkę zakładki w polu aktywnych filtrów znajdującym się niżej.",
        "rcfilters-invalid-filter": "Nieprawidłowy filtr",
        "rcfilters-empty-filter": "Brak aktywnych filtrów. Wyświetlane są wszystkie zmiany.",
        "rcfilters-filterlist-title": "Filtry",
-       "rcfilters-filterlist-whatsthis": "Co to jest?",
+       "rcfilters-filterlist-whatsthis": "Jak działają?",
        "rcfilters-filterlist-feedbacklink": "Podziel się swoją opinią na temat tych nowych (beta) filtrów",
        "rcfilters-highlightbutton-title": "Podświetl wyniki",
        "rcfilters-highlightmenu-title": "Wybierz kolor",
        "rcfilters-filter-editsbyself-description": "Czynności dokonane przez Ciebie.",
        "rcfilters-filter-editsbyother-label": "Zmiany dokonane przez innych",
        "rcfilters-filter-editsbyother-description": "Wszystkie zmiany oprócz Twoich.",
-       "rcfilters-filtergroup-userExpLevel": "Poziom doświadczenia (tylko o zarejestrowanych użytkownikach)",
+       "rcfilters-filtergroup-userExpLevel": "Zarejestrowanie użytkownika i doświadczenie",
        "rcfilters-filter-user-experience-level-registered-label": "Zarejestrowani",
        "rcfilters-filter-user-experience-level-registered-description": "Zalogowani edytorzy.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Niezarejestrowani",
        "rcfilters-filter-user-experience-level-unregistered-description": "Niezalogowani",
        "rcfilters-filter-user-experience-level-newcomer-label": "Początkujący",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Mniej niż 10 edycji i 4 dni aktywności.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Zarejestrowani edytorzy z mniej niż 10 edycji i 4 dni aktywności.",
        "rcfilters-filter-user-experience-level-learner-label": "Uczący się",
-       "rcfilters-filter-user-experience-level-learner-description": "Większe doświadczenie niż „Nowicjusze”, ale mniejsze niż „Doświadczeni użytkownicy”.",
+       "rcfilters-filter-user-experience-level-learner-description": "Zarejestrowani edytujący, których doświadczenie plasuje się między „Nowicjuszami”, a „Doświadczonymi użytkownikami”.",
        "rcfilters-filter-user-experience-level-experienced-label": "Doświadczeni użytkownicy",
-       "rcfilters-filter-user-experience-level-experienced-description": "Ponad 30 dni aktywności i 500 edycji.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Zarejestrowani edytujący z ponad 500 edycji i 30 dni aktywności.",
        "rcfilters-filtergroup-automated": "Zmiany zautomatyzowane",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-bots-description": "Zmiany wykonane z użyciem zautomatyzowanych narzędzi.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtr „Drobne zmiany” koliduje z jednym lub wieloma filtrami Rodzaju zmian, ponieważ niektóre rodzaje zmian nie mogą być uznawane za  „drobne”. Kolidujące filtry zostały powyżej odpowiednio zaznaczone na pasku aktywnych filtrów.",
        "rcfilters-hideminor-conflicts-typeofchange": "Niektóre rodzaje zmian nie mogą być uznawane za „drobne”, dlatego ten filtr koliduje z następującymi filtrami Rodzaju zmian: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ten filtr Rodzaju zmian koliduje z filtrem „Drobne zmiany”. Nie wszystkie zmiany mogą być uznawane za „drobne”.",
-       "rcfilters-filtergroup-lastRevision": "Ostatnia wersja",
-       "rcfilters-filter-lastrevision-label": "Ostatnie wersje",
+       "rcfilters-filtergroup-lastRevision": "Ostatnie wersje",
+       "rcfilters-filter-lastrevision-label": "Najnowsza wersja",
        "rcfilters-filter-lastrevision-description": "Tylko najnowsze zmiany dla każdej ze stron.",
-       "rcfilters-filter-previousrevision-label": "Wcześniejsze wersje",
-       "rcfilters-filter-previousrevision-description": "Wszystkie edycje, które nie są najnowszą zmianą strony.",
+       "rcfilters-filter-previousrevision-label": "Wersje inne niż najnowsza",
+       "rcfilters-filter-previousrevision-description": "Wszystkie edycje, które nie są najnowszą wersją strony.",
        "rcfilters-filter-excluded": "Wykluczono",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:nie z</strong> $1",
+       "rcfilters-exclude-button-off": "Wyklucz zaznaczone",
+       "rcfilters-exclude-button-on": "Zaznaczone są wykluczone",
        "rcfilters-view-tags": "Edycje ze znacznikami zmian",
        "rcfilters-view-namespaces-tooltip": "Przefiltruj wyniki według przestrzeni nazw",
        "rcfilters-view-tags-tooltip": "Przefiltruj wyniki według znaczników zmian",
index c95d6f8..a13593a 100644 (file)
        "rcfilters-legend-heading": "<strong>Lista de abreviaturas:</strong>",
        "rcfilters-activefilters": "Filtros ativos",
        "rcfilters-advancedfilters": "Filtros avançados",
+       "rcfilters-limit-title": "Mudanças para mostrar",
+       "rcfilters-limit-shownum": "Mostrar as últimas $1 modificações",
+       "rcfilters-days-title": "Dias recentes",
+       "rcfilters-hours-title": "Horas recentes",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|dia|dias}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|hora|horas}}",
        "rcfilters-quickfilters": "Filtros salvos",
        "rcfilters-quickfilters-placeholder-title": "Ainda não foi gravado nenhum link",
        "rcfilters-quickfilters-placeholder-description": "Para gravar as suas configurações dos filtros e reutilizá-las mais tarde, clique o ícone do marcador de página, na área Filtro Ativo abaixo.",
        "rcfilters-invalid-filter": "Filtro inválido",
        "rcfilters-empty-filter": "Nenhum filtro ativo. Todas as contribuições são mostradas.",
        "rcfilters-filterlist-title": "Filtros",
-       "rcfilters-filterlist-whatsthis": "O que é isso?",
+       "rcfilters-filterlist-whatsthis": "Como funcionam estes?",
        "rcfilters-filterlist-feedbacklink": "Forneça feedback sobre os novos filtros (beta)",
        "rcfilters-highlightbutton-title": "Realçar os resultados",
        "rcfilters-highlightmenu-title": "Selecione uma cor",
        "rcfilters-filter-editsbyself-description": "Suas proprias contribuições.",
        "rcfilters-filter-editsbyother-label": "Mudanças de outros",
        "rcfilters-filter-editsbyother-description": "Todas as mudanças, exceto a sua.",
-       "rcfilters-filtergroup-userExpLevel": "Nível de experiência (apenas para usuário registados)",
+       "rcfilters-filtergroup-userExpLevel": "Registro e experiência do usuário",
        "rcfilters-filter-user-experience-level-registered-label": "Registrado",
-       "rcfilters-filter-user-experience-level-registered-description": "Editores conectados.",
-       "rcfilters-filter-user-experience-level-unregistered-label": "Não registrado",
-       "rcfilters-filter-user-experience-level-unregistered-description": "Editores que não estão conectados.",
+       "rcfilters-filter-user-experience-level-registered-description": "Editores registrados.",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Não registados",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Editores que não estão autenticados.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Recém-chegados",
        "rcfilters-filter-user-experience-level-newcomer-description": "Menos de 10 edições e 4 dias de atividade.",
        "rcfilters-filter-user-experience-level-learner-label": "Aprendizes",
        "rcfilters-hideminor-conflicts-typeofchange-global": "O filtro \"Edições menores\" conflita com um ou mais filtros de Tipo de Alteração, porque certos tipos de alteração não podem ser designadas como \"menores\". Os filtros em conflito estão marcados na área Filtros Ativos, acima.",
        "rcfilters-hideminor-conflicts-typeofchange": "Determinados tipos de alteração não podem ser designados como \"menor\", portanto, este filtro entra em conflito com os seguintes filtros de Tipo de Alteração: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro de Tipo de Alteração entra em conflito com o filtro \"Edições menores\". Certos tipos de mudança não podem ser designadas como \"menores\".",
-       "rcfilters-filtergroup-lastRevision": "Última revisão",
-       "rcfilters-filter-lastrevision-label": "Última revisão",
-       "rcfilters-filter-lastrevision-description": "A alteração mais recente para uma página.",
-       "rcfilters-filter-previousrevision-label": "Revisões anteriores",
-       "rcfilters-filter-previousrevision-description": "Todas as alterações que não são a alteração mais recente para uma página.",
+       "rcfilters-filtergroup-lastRevision": "Últimas revisões",
+       "rcfilters-filter-lastrevision-label": "Revisão atual",
+       "rcfilters-filter-lastrevision-description": "Somente a mudança mais recente para uma página.",
+       "rcfilters-filter-previousrevision-label": "Não é a última revisão",
+       "rcfilters-filter-previousrevision-description": "Todas as mudanças que não são as \"ultimas revisões\".",
        "rcfilters-filter-excluded": "Excluído",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:não</strong> $1",
+       "rcfilters-exclude-button-off": "Excluir selecionado",
+       "rcfilters-exclude-button-on": "Excluindo selecionados",
        "rcfilters-view-tags": "Edições marcadas",
        "rcfilters-view-namespaces-tooltip": "Filtrar resultados por namespace",
        "rcfilters-view-tags-tooltip": "Filtre os resultados usando edit tags",
        "delete-warning-toobig": "Esta página possui um longo histórico de edições, com mais de $1 {{PLURAL:$1|edição|edições}}.\nEliminá-la poderá causar problemas na base de dados de {{SITENAME}};\nprossiga com cuidado.",
        "deleteprotected": "Não é possível eliminar esta página porque foi protegida.",
        "deleting-backlinks-warning": "'''Cuidado:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|outras páginas]] ligam ou redirecionam para a página que você está prestes a eliminar.",
+       "deleting-subpages-warning": "<strong>Aviso:</strong> A página que você está prestes a excluir tem [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|uma subpágina|$1 subpáginas|51=mais de 50 subpáginas}}]].",
        "rollback": "Reverter edições",
        "rollbacklink": "reverter",
        "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edição|edições}}",
index 0b3888d..e771309 100644 (file)
        "rcfilters-filter-editsbyself-description": "As suas edições.",
        "rcfilters-filter-editsbyother-label": "Modificações de outros",
        "rcfilters-filter-editsbyother-description": "Todas as modificações, exceto as suas.",
-       "rcfilters-filtergroup-userExpLevel": "Nível de experiência (apenas para utilizadores registados)",
+       "rcfilters-filtergroup-userExpLevel": "Registo de utilizadores e experiência",
        "rcfilters-filter-user-experience-level-registered-label": "Registados",
        "rcfilters-filter-user-experience-level-registered-description": "Editores autenticados.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Não registados",
        "rcfilters-filter-user-experience-level-unregistered-description": "Editores que não estão autenticados.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Novatos",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Menos de 10 edições e de 4 dias de atividade.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Editores registados, com menos de 10 edições e de 4 dias de atividade.",
        "rcfilters-filter-user-experience-level-learner-label": "Aprendizes",
-       "rcfilters-filter-user-experience-level-learner-description": "Mais experiência do que \"Novatos\", mas menos do que \"Utilizadores experientes\".",
+       "rcfilters-filter-user-experience-level-learner-description": "Editores registados, com mais experiência do que \"Novatos\", mas menos do que \"Utilizadores experientes\".",
        "rcfilters-filter-user-experience-level-experienced-label": "Utilizadores experientes",
-       "rcfilters-filter-user-experience-level-experienced-description": "Mais de 30 dias de atividade e de 500 edições.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Editores registados, com mais de 500 edições e de 30 dias de atividade.",
        "rcfilters-filtergroup-automated": "Contribuições automatizadas",
        "rcfilters-filter-bots-label": "Robô",
        "rcfilters-filter-bots-description": "Edições efetuadas por ferramentas automatizadas.",
        "rcfilters-filter-humans-label": "Ser humano (não robô)",
-       "rcfilters-filter-humans-description": "Edições efetuadas por editores humanos.",
+       "rcfilters-filter-humans-description": "Edições efetuadas por pessoas.",
        "rcfilters-filtergroup-reviewstatus": "Estado da revisão",
        "rcfilters-filter-patrolled-label": "Patrulhadas",
        "rcfilters-filter-patrolled-description": "Edições marcadas como patrulhadas.",
        "delete-warning-toobig": "Esta página tem um histórico de edições longo, com mais de $1 {{PLURAL:$1|edição|edições}}.\nEliminá-la poderá causar problemas na base de dados da wiki {{SITENAME}};\nprossiga com precaução.",
        "deleteprotected": "Não é possível eliminar esta página porque foi protegida.",
        "deleting-backlinks-warning": "<strong>Aviso:</strong> Existem [[Special:WhatLinksHere/{{FULLPAGENAME}}|páginas]] que contêm ligações para a página que está prestes a eliminar ou que a transcluem.",
+       "deleting-subpages-warning": "<strong>Aviso:</strong> A página que está prestes a eliminar tem [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|uma subpágina|$1 subpáginas|51=mais de 50 subpáginas}}]].",
        "rollback": "Reverter edições",
        "rollbacklink": "reverter",
        "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edição|edições}}",
index fe2444a..8cffd2a 100644 (file)
        "minoredit": "Cangiaminde stuèdeche",
        "watchthis": "Condrolle sta pàgene",
        "savearticle": "Registre 'a vôsce",
+       "savechanges": "Reggistre le cangiaminde",
+       "publishpage": "Pubbleche 'a pàgene",
+       "publishchanges": "Pubbleche le cangiaminde",
        "preview": "Andeprime",
        "showpreview": "Vide l'andeprime",
        "showdiff": "Fa vedè le cangiaminde",
diff --git a/languages/i18n/skr-arab.json b/languages/i18n/skr-arab.json
new file mode 100644 (file)
index 0000000..1c38e4d
--- /dev/null
@@ -0,0 +1,563 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Saraiki"
+               ]
+       },
+       "sunday": "اتوار",
+       "monday": "سونوار",
+       "tuesday": "منگل",
+       "wednesday": "بدھ",
+       "thursday": "خمیس",
+       "friday": "جمعہ",
+       "saturday": "چھݨ چھݨ",
+       "sun": "اتوار",
+       "mon": "سونوار",
+       "tue": "منگل",
+       "wed": "بدھ",
+       "thu": "خمیس",
+       "fri": "جمعہ",
+       "sat": "چھݨ چھݨ",
+       "january": "جنوری",
+       "february": "فروری",
+       "march": "مارچ",
+       "april": "اپريل",
+       "may_long": "مئی",
+       "june": "جون",
+       "july": "جولائی",
+       "august": "اگست",
+       "september": "ستمبر",
+       "october": "اکتوبر",
+       "november": "نومبر",
+       "december": "دسمبر",
+       "january-gen": "جنوری",
+       "february-gen": "فروری",
+       "march-gen": "مارچ",
+       "april-gen": "اپريل",
+       "may-gen": "مئی",
+       "june-gen": "جون",
+       "july-gen": "جولائی",
+       "august-gen": "اگست",
+       "september-gen": "ستمبر",
+       "october-gen": "اکتوبر",
+       "november-gen": "نومبر",
+       "december-gen": "دسمبر",
+       "jan": "جنوری",
+       "feb": "فروری",
+       "mar": "مارچ",
+       "apr": "اپریل",
+       "may": "مئی",
+       "jun": "جون",
+       "jul": "جولائی",
+       "aug": "اگست",
+       "sep": "ستمبر",
+       "oct": "اکتوبر",
+       "nov": "نومبر",
+       "dec": "دسمبر",
+       "pagecategories": "{{PLURAL:$1|زمرہ|زمرہ جات}}",
+       "category_header": "زمرہ \"$1\" وچ ورقے",
+       "subcategories": "ذیلی زمرہ جات",
+       "category-media-header": "زمرہ \"$1\" وچ میڈیا",
+       "hidden-categories": "{{PLURAL:$1|پوشیدہ زمرہ|پوشیدہ زمرہ جات}}",
+       "listingcontinuesabbrev": "جاری۔",
+       "noindex-category": "غیر فہرست شدہ صفحات",
+       "broken-file-category": "ٹٹے ہوۓ جوڑاں آلے صفحے",
+       "about": "تعارف",
+       "newwindow": "(نویں ونڈو وچ کھولو)",
+       "cancel": "مکاؤ",
+       "mytalk": "ڳالھ مہاڑ",
+       "navigation": "رہنمائی",
+       "and": "&#32;تے",
+       "namespaces": "ناں دیاں جہاواں",
+       "variants": "قسماں",
+       "navigation-heading": "فہرست رہنمائی",
+       "returnto": "واپس $1 چلو",
+       "tagline": " {{SITENAME}} توں",
+       "help": "مدد",
+       "search": "کھوج",
+       "searchbutton": "کھوج",
+       "searcharticle": "ڄلو",
+       "history": "پچھلے کم",
+       "history_short": "تاریخچہ",
+       "printableversion": "چھپݨ جوگا ورقہ",
+       "permalink": "پکا جوڑ",
+       "view": "ݙکھالے",
+       "view-foreign": "$1 تے ݙیکھو",
+       "edit": "لکھو",
+       "create": "بݨاؤ",
+       "create-local": "آپنی لکھت رلاؤ",
+       "delete": "مٹاؤ",
+       "newpage": "نواں ورقہ",
+       "talkpagelinktext": "ڳالھ مہاڑ",
+       "personaltools": "ذاتی آوزار",
+       "talk": "ڳالھ مہاڑ",
+       "views": "ݙکھالے",
+       "toolbox": "آوزار",
+       "otherlanguages": "ٻنھاں زباناں وچ",
+       "redirectedfrom": "($1 کنوں ولدا رجوع )",
+       "redirectpagesub": "صفحہ ریڈائریکٹ کرو",
+       "redirectto": "اڳے کرو:",
+       "lastmodifiedat": "ایہ ورقہ چھیکڑی واری  $1 کوں $2 تے تبدیل تھیا ہائی۔",
+       "jumpto": "ٹپ مارو",
+       "jumptonavigation": "رہنمائی",
+       "jumptosearch": "ڳولو",
+       "aboutsite": "{{SITENAME}} دا تعارف",
+       "aboutpage": "Project:تعارف",
+       "copyrightpage": "{{ns:project}}:حقوق تصانیف",
+       "currentevents": "حالیہ واقعات",
+       "currentevents-url": "Project:حالیہ واقعات",
+       "disclaimers": "لاتعلقی اظہار",
+       "disclaimerpage": "Project:عام لاتعلقی اظہار",
+       "edithelp": "لکھݨ وچ مدد",
+       "mainpage": "وݙا ورقہ",
+       "mainpage-description": "پہلا ورقہ",
+       "portal": "بیٹھک",
+       "portal-url": "Project:دیوان عام",
+       "privacy": "پرائیویسی پالیسی",
+       "privacypage": "Project:پرائیویسی پالیسی",
+       "retrievedfrom": "\"$1\" توں گھدا",
+       "youhavenewmessages": "تہاݙے کیتے ہک $1 ہے۔ ($2)",
+       "newmessagesdifflinkplural": "چھیکڑی {{PLURAL:$1|تبدیلی|تبدیلیاں}}",
+       "editsection": "لکھو",
+       "editold": "لکھو",
+       "viewsourceold": "ماخذ ݙیکھو",
+       "editlink": "لکھو",
+       "viewsourcelink": "ماخذ ݙیکھو",
+       "editsectionhint": "حصہ لکھو: $1",
+       "toc": "حصے",
+       "site-atom-feed": "$1 اٹوم فیڈ",
+       "page-atom-feed": "$1 اٹوم فیڈ",
+       "red-link-title": "$1 (ایہ ورقہ اڄݨ تائیں کائنی بݨیا)",
+       "nstab-main": "ورقہ",
+       "nstab-user": "صفحۂ صارف",
+       "nstab-special": "خاص ورقہ",
+       "nstab-project": "پروجیکٹ ورقہ",
+       "nstab-image": "فائل",
+       "nstab-mediawiki": "سنیہہ",
+       "nstab-template": "سانچہ",
+       "nstab-category": "زمرہ",
+       "mainpage-nstab": "وݙا ورقہ",
+       "nosuchspecialpage": "اینجھا کوئی خاص ورقہ کائنی",
+       "badtitle": "بھیڑا عنوان",
+       "viewsource": "ماخذ ݙیکھو",
+       "userlogin-yourname": "صارف ناں",
+       "userlogin-yourname-ph": "آپݨا ورتݨ ناں صارف درج کرو",
+       "userlogin-yourpassword": "پاس ورڈ",
+       "userlogin-yourpassword-ph": "پاس ورڈ درج کرو",
+       "createacct-yourpassword-ph": "پاس ورڈ درج کرو",
+       "createacct-yourpasswordagain": "پاس ورڈ دی تصدیق کرو",
+       "createacct-yourpasswordagain-ph": "پاس ورڈ ولدا درج کرو",
+       "userlogin-remembermypassword": "میکوں لاگ ان رکھو",
+       "login": "لاگ ان تھیوو",
+       "userlogin-noaccount": "تہاݙا کھاتہ کائنی؟",
+       "userlogin-joinproject": "جُڑ ونڄو {{SITENAME}} نال",
+       "createaccount": "کھاتہ کھولو",
+       "userlogin-resetpassword-link": "پاسورڈ بھل ڳئے ہو؟",
+       "userlogin-helplink2": "لاگ ان تھیوݨ کیتے مدد دی لوڑ ہے؟",
+       "createacct-emailoptional": "(ای-میل پتہ(مرضی نال",
+       "createacct-email-ph": "اپنا ای-میل پتہ لکھو",
+       "createacct-submit": "اپݨاں کھاتا کھولو",
+       "createacct-benefit-heading": "{{SITENAME}} تہاݙے وانگوں علم دوست افراد دا مرہون منت ہے۔",
+       "createacct-benefit-body1": "$1 {{PLURAL:$1|تبدیلی|تبدیلیاں}}",
+       "createacct-benefit-body2": "\n$1 {{PLURAL:$1|ورقہ|ورقے}}",
+       "createacct-benefit-body3": "ہݨ دے {{PLURAL:$1|کم|کماں}}",
+       "loginlanguagelabel": "زبان: $1",
+       "pt-login": "لاگ ان تھیوو",
+       "pt-login-button": "لاگ ان تھیوو",
+       "pt-createaccount": "کھاتہ کھولو",
+       "pt-userlogout": "لاگ آؤٹ",
+       "passwordreset": "نواں پاس ورڈ بݨاؤ",
+       "bold_sample": "موٹی لکھائی",
+       "bold_tip": "موٹی لکھائی",
+       "italic_sample": "ترچھا متن",
+       "italic_tip": "ترچھی لکھائی",
+       "link_sample": "جوڑ",
+       "link_tip": "اندرونی جوڑ",
+       "extlink_sample": "http://www.example.com جوڑ دا ناں",
+       "extlink_tip": "باہرلے جوڑ (remember http:// prefix)",
+       "headline_sample": "شہ سرخی",
+       "headline_tip": "ݙوجھے درجے دی سرخی",
+       "nowiki_sample": "فارمیٹ نہ تھئی ہوئی لکھائی اتھ درج کرو",
+       "nowiki_tip": "ویکی فارمیٹ کوں نظرانداز کرو",
+       "image_tip": "پیوستہ فائل",
+       "media_tip": "فائل دا جوڑ",
+       "sig_tip": "تہاݙے دستخط ویلے دے نال",
+       "hr_tip": "اُفقی لکیر (زیادہ استعمال نہ کریں)",
+       "summary": "خلاصہ",
+       "minoredit": "ایہ ہک چھوٹی تبدیلی ہے",
+       "watchthis": "ایں ورقے تے اکھ رکھو",
+       "savearticle": "محفوظ",
+       "preview": "نمائش",
+       "showpreview": "نمائش",
+       "showdiff": "تبدیلیاں ݙکھاؤ",
+       "loginreqlink": "لاگ ان",
+       "userpage-userdoesnotexist-view": "صارف کھاتہ \"$1\" رجسٹرڈ کائنی۔",
+       "continue-editing": "خانہ ترمیم وچ ونڄو",
+       "editing": "تساں \"$1\" لکھدے پئے ہو",
+       "creating": "زیر تخلیق $1",
+       "editingsection": "«$1» دے قطعہ دی ترمیم",
+       "templatesused": "ایں ورقے تے  ورتے ڳئے {{PLURAL:$1|سانچے|سانچہ}}:",
+       "template-protected": "(بچایا گیا)",
+       "template-semiprotected": "(نیم محفوظ)",
+       "hiddencategories": "ایہ ورقہ {{PLURAL:$1|1 لُکے زمریاں|$1 لکا زمرہ }} وچ شامل ہے:",
+       "permissionserrors": "خطائے اجازت",
+       "moveddeleted-notice": "ایہ ورقہ مٹایا ڳیا ہے۔ مٹاوݨ دا لاگ ہیٹھاں ݙتا ہویا ہے",
+       "content-model-wikitext": "ویکی متن",
+       "undo-failure": "متنازع تبدیلیاں پاروں ایہ تبدیلی واپس نی تھی سڳدی۔",
+       "viewpagelogs": "صفحے دے لاگ ݙیکھو",
+       "currentrev-asof": "حالیہ نسخہ بمطابق $1",
+       "revisionasof": "دی تبدیلیاں $1",
+       "previousrevision": "→ پراݨا نسخہ",
+       "nextrevision": "نویں تبدیلی →",
+       "currentrevisionlink": "موجودہ حالت",
+       "cur": " رائج",
+       "last": "پچھلا",
+       "history-fieldset-title": "دہرائی کیتے لبھت",
+       "histfirst": "قدیم ترین",
+       "histlast": "تازہ ترین",
+       "history-feed-title": "ریویژن رکارڈ",
+       "history-feed-item-nocomment": "$2 کوں $1",
+       "rev-delundel": "ݙکھاؤ/لکاؤ",
+       "mergelog": "لاگ رلاؤ",
+       "history-title": "\"$1\" دا ریکارڈ",
+       "difference-title": "\"$1\" دے نسخیاں دے درمیان فرق",
+       "lineno": "سطر $1:",
+       "editundo": "واپس",
+       "diff-empty": "(کوئی فرق کائنی)",
+       "searchresults": "کھوج دا نتارا",
+       "searchresults-title": "\"$1\" دے کھوج نتارے",
+       "prevn": "پچھلے {{PLURAL:$1|$1}}",
+       "nextn": "اگلے {{PLURAL:$1|$1}}",
+       "prevn-title": "پہلے $1 {{PLURAL:$1|نتیجے}}",
+       "nextn-title": "اگلے $1 {{PLURAL:$1|نتیجے}}",
+       "shown-title": "وکھاؤ $1 {{PLURAL:$1|نتیجے}}",
+       "viewprevnext": "($1 {{int:pipe-separator}} $2) ݙیکھو ($3)",
+       "searchprofile-articles": "لسٹ ورقے",
+       "searchprofile-images": "ملٹی میڈیا",
+       "searchprofile-everything": "سب کجھ",
+       "searchprofile-advanced": "اگلا",
+       "searchprofile-articles-tooltip": "$1 وچ ڳولو",
+       "searchprofile-images-tooltip": "فائلاں ڳولو",
+       "searchprofile-everything-tooltip": " سارا مواد ڳولو",
+       "searchprofile-advanced-tooltip": "کسٹم نانواں وچ ڳولو",
+       "search-result-size": "$1 ({{PLURAL:$2|1 لفظ|$2 الفاظ}})",
+       "search-redirect": "($1 کنوں ولدا رجوع )",
+       "search-section": "(قطعہ $1)",
+       "search-suggest": "بھلا تہاݙا مطلب ہائی: $1",
+       "searchall": "یکے",
+       "search-nonefound": "سوال دے نال رلدے ملدے نتارے کائنی۔",
+       "mypreferences": "ترجیحات",
+       "group-bot": "بوٹ",
+       "group-sysop": "منتظمین",
+       "grouppage-bot": "{{ns:project}}:بوٹ",
+       "grouppage-sysop": "{{ns:project}}:ایڈمنسٹریٹر",
+       "right-writeapi": "اے پی آئی تحریر دا استعمال",
+       "newuserlogpage": "یوزر بنݨاوݨ آلی لاگ",
+       "rightslog": "ورتݨ والے دے حقاں دی لاگ",
+       "action-edit": "ایں ورقے تے لکھو",
+       "action-createaccount": "ایہ ورتݨ آلا کھاتہ کھولو",
+       "enhancedrc-history": "پچھلا کم",
+       "recentchanges": "نویاں تبدیلیاں",
+       "recentchanges-legend": "اِختیاراتِ حالیہ تبدیلیاں",
+       "recentchanges-feed-description": "ایں فیڈ وچ وکی تے تھیوݨ آلیاں نویاں نکور تبدیلیاں ݙیکھو۔",
+       "recentchanges-label-newpage": "ایں تبدیلی نواں ورقہ بݨایا ہے",
+       "recentchanges-label-minor": "ایہ ہک چھوٹی تبدیلی ہے",
+       "recentchanges-label-bot": "ایہ تبدیلی  بوٹ نے کیتی ہے۔",
+       "recentchanges-label-unpatrolled": "ایہ تبدیلی اڄݨ تائیں واپس کائنی ولی۔",
+       "recentchanges-label-plusminus": "ورقے دا تبدیل شدہ حجم بلحاظ تعداد بائٹ",
+       "recentchanges-legend-heading": "<strong>اختصارات:</strong>",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (ایہ وی ݙیکھو [[Special:NewPages|نویں ورقیاں دی لسٹ]])",
+       "rclistfrom": "$3 $2 توں ہونے آلیاں نویاں تبدیلیاں ݙکھاؤ",
+       "rcshowhideminor": "$1 معمولی تبدیلیاں",
+       "rcshowhideminor-show": "ݙیکھاؤ",
+       "rcshowhideminor-hide": "لُکاؤ",
+       "rcshowhidebots": "$1 بوٹ",
+       "rcshowhidebots-show": "ݙیکھاؤ",
+       "rcshowhidebots-hide": "لُکاؤ",
+       "rcshowhideliu": "مندرج صارفین $1",
+       "rcshowhideliu-show": "ݙیکھاؤ",
+       "rcshowhideliu-hide": "لُکاؤ",
+       "rcshowhideanons": "گمنام صارف $1",
+       "rcshowhideanons-show": "ݙیکھاؤ",
+       "rcshowhideanons-hide": "لُکاؤ",
+       "rcshowhidepatr": "$1 مراجعت شدہ ترامیم",
+       "rcshowhidemine": "ذاتی ترامیم میݙے کم $1",
+       "rcshowhidemine-show": "ݙیکھاؤ",
+       "rcshowhidemine-hide": "لُکاؤ",
+       "rclinks": "آخری $2 ݙینہ دیاں $1 تبدیلیاں ݙکھاؤ",
+       "diff": "فرق",
+       "hist": "پچھلا کم",
+       "hide": "لُکاؤ",
+       "show": "ݙیکھاؤ",
+       "minoreditletter": "چھوٹا کم",
+       "newpageletter": "نواں",
+       "boteditletter": " خودکار",
+       "rc-change-size-new": "تبدیلی دے بعد $1 {{PLURAL:$1|بائٹ}}",
+       "rc-old-title": "اصلاً «$1» دے عنوان نال تخلیق شدہ",
+       "recentchangeslinked": "رلدیاں ملدیاں تبدیلیاں",
+       "recentchangeslinked-feed": "رلدیاں ملدیاں تبدیلیاں",
+       "recentchangeslinked-toolbox": "رلدیاں ملدیاں تبدیلیاں",
+       "recentchangeslinked-title": "\"$1\" دے متعلقہ تبدیلیاں",
+       "recentchangeslinked-page": "ورقے دا ناں",
+       "recentchangeslinked-to": "کھلے ہوئے ورقے دی بجائے ایندے نال جُڑے ہوئے ورقے دیاں تبدیلیاں ݙکھاؤ",
+       "upload": "فائل چڑھاؤ",
+       "uploadlogpage": "اپلوڈ لاگ",
+       "filedesc": "خلاصہ",
+       "license-header": "اجازہ کاری",
+       "imgfile": "فائل",
+       "listfiles": "فائل لسٹ",
+       "file-anchor-link": "فائل",
+       "filehist": "فائل دا تاریخچہ",
+       "filehist-help": "کہیں خاص ویلے تے تاریخ کوں فائل کینویں  نظردی ہائی، ݙیکݨ کیتے اوں ویلے تے کلک کرو۔",
+       "filehist-revert": "واپس",
+       "filehist-current": "موجودہ",
+       "filehist-datetime": "تریخ/ویلہ",
+       "filehist-thumb": "تھمب نیل",
+       "filehist-thumbtext": "مورخہ $1 دا تھمب نیل",
+       "filehist-nothumb": "کوئی تھمبنیل کائنی۔",
+       "filehist-user": "ورتݨ والا",
+       "filehist-dimensions": "پاسے",
+       "filehist-comment": "رائے",
+       "imagelinks": "فائل ورتݨ",
+       "linkstoimage": "اِیں فائل نال ہیٹھاں درج  {{PLURAL:$1|ورقہ مربوط ہے|$1 صفحات مربوط ہن}}:",
+       "nolinkstoimage": "ایں فائل نال کوئی ورقہ کائنی ڄُڑیا ہویا۔",
+       "linkstoimage-redirect": "$1 (فائل وت رجوع) $2",
+       "sharedupload-desc-here": "ایہ فائل $1 توں ہے تے ݙوجھیاں منصوبیاں تے وی ورتی ویسی۔\nایندی وضاحت [$2 فائل دی وضاحت دا ورقہ]  تے تھلے ݙتی ڳئی۔",
+       "filepage-nofile": "ایں ناں دی کوئی فائل کائنی۔",
+       "upload-disallowed-here": "تساں ایں فائل تے لکھ نی سڳدے۔",
+       "randompage": "رلے ملے ورقے",
+       "statistics": "شماريات",
+       "double-redirect-fixer": "ریڈائرکٹ فکسر",
+       "nbytes": "$1 {{PLURAL:$1|بائٹ}}",
+       "nmembers": "{{PLURAL:$1|رکن|اراکین}}",
+       "prefixindex": "سارے ورقے بمع سابقہ",
+       "listusers": "ورتݨ والیاں دے ناں",
+       "newpages": "نویں ورقے",
+       "move": "ٹرو",
+       "pager-newer-n": "{{PLURAL:$1|newer 1|زیادہ نواں $1}}",
+       "pager-older-n": "{{PLURAL:$1|قدیم}} $1",
+       "booksources": "کتابی وسائل",
+       "booksources-search-legend": "ایں مضمون تے کتاباں لبھو",
+       "booksources-search": "ڳولو",
+       "specialloguserlabel": "کرݨ آلا :",
+       "log": "لاگز",
+       "all-logs-page": "سارےعوامی لاگ",
+       "logempty": "لاگ وچ رلدیاں ملدیاں چیزاں کائنی۔",
+       "allpages": "سارے مقالے",
+       "allarticles": "سارے مقالے",
+       "allpagessubmit": "ڄلو",
+       "allpages-hide-redirects": "رجوع مکررات لکاؤ",
+       "categories": "زمرہ",
+       "listgrouprights-members": "(رکناں دی لسٹ)",
+       "emailuser": "ایں ورتݨ والے کوں ای میل کرو",
+       "usermessage-editor": "نظامی پیغام رساں",
+       "watchlist": "زیرنظر فہرست",
+       "mywatchlist": "زیرنظر فہرست",
+       "watchlistfor2": "$1 تے $2 کیتے",
+       "watch": "اکھ تلے رکھو",
+       "unwatch": "اکھ ہیٹھوں ہٹاؤ",
+       "wlshowlast": "ݙیکھاؤ چھیکڑی $1 گھنٹے $2 ݙینہ",
+       "watchlist-options": "نظر تھلے رکھݨ دیاں راہواں",
+       "enotif_reset": "سارے ورقے ڈیکھ گھدن",
+       "dellogpage": "مٹاوݨ آلی لاگ",
+       "rollbacklink": "واپس",
+       "protectlogpage": "بچت لاگ",
+       "protectedarticle": "\"[[$1]]\" بچایا گیا اے",
+       "protect-default": "تمام صارفین کوں اجازت ہے",
+       "restriction-edit": "لکھو",
+       "restriction-move": "ٹرو",
+       "namespace": "ناں دی جگہ:",
+       "invert": "انتخاب معکوس",
+       "namespace_association": "رلدے ناں دی تھاں",
+       "blanknamespace": "(مکھ)",
+       "contributions": " $1 ورتن آلے دا حصہ",
+       "contributions-title": "صارف $1 دی شراکتاں",
+       "mycontris": "شراکتاں",
+       "anoncontribs": "شراکتاں",
+       "contribsub2": "{{GENDER:$3|$1}} ($2)",
+       "nocontribs": "ایں معیار دے مطابق کوئی تبدیلی نی لبھی۔",
+       "uctop": "(موجودہ)",
+       "month": "مہینے توں (تے پہلاں):",
+       "year": "سال توں (تے پہلاں):",
+       "sp-contributions-newbies": "صرف نویں ورتݨ آلیاں دے کم ݙکھاؤ",
+       "sp-contributions-blocklog": "لاگ روکو",
+       "sp-contributions-uploads": "اپلوڈ کردہ",
+       "sp-contributions-logs": "لاگز",
+       "sp-contributions-talk": "ڳالھ مہاڑ",
+       "sp-contributions-search": "حصے پاؤݨ آلیاں دی تلاش",
+       "sp-contributions-username": "آئی پی پتہ یا ورتݨ آلا ناں:",
+       "sp-contributions-toponly": "صرف اوہ تبدیلیاں ݙکھاؤ جیہڑیاں ہُݨے ہُݨے تھیاں ہن۔",
+       "sp-contributions-newonly": "صرف نویں ورقیاں بݨݨ آلیاں لکھتاں ݙیکھاؤ",
+       "sp-contributions-submit": "ڳولو",
+       "whatlinkshere": "مربوط ورقے",
+       "whatlinkshere-title": "«$1» دے نال جُڑے ہوے ورقے",
+       "whatlinkshere-page": "ورقہ",
+       "linkshere": "<strong>[[:$1]]</strong> نال درج ذیل ورقے مربوط ہن:",
+       "nolinkshere": "<strong>[[:$1]]</strong> نال کوئی ورقہ مربوط کائنی۔",
+       "isredirect": "صفحہ ریڈائریکٹ کرو",
+       "istemplate": "شامل شدہ",
+       "isimage": "فائل دا ربط",
+       "whatlinkshere-prev": "{{PLURAL:$1|پچھلا|پچھلے $1}}",
+       "whatlinkshere-next": "{{PLURAL:$1|اگلا|اگلے $1}}",
+       "whatlinkshere-links": "→ روابط",
+       "whatlinkshere-hideredirs": "رجوع مکررات $1",
+       "whatlinkshere-hidetrans": "استعمالات $1",
+       "whatlinkshere-hidelinks": "روابط $1",
+       "whatlinkshere-hideimages": "تصویر دے روابط $1",
+       "whatlinkshere-filters": "نتارے",
+       "infiniteblock": "بے انت",
+       "blocklink": "پابندی لاؤ",
+       "contribslink": "حصے داری",
+       "blocklogpage": "لاگ روکو",
+       "blocklogentry": "«[[$1]]» تے $2 کیتے پابندی عائد کی ڳئی ہے $3",
+       "reblock-logentry": "[[$1]] دی ترتیبات پابندی کوں تبدیل کیتاڳئے، ہݨ میعاد $2 $3 تے مُکسی",
+       "block-log-flags-nocreate": "کھاتا کھولݨ تے پابندی ہے",
+       "proxyblocker": "پراکسی روکݨ آلا",
+       "movelogpage": "ناں تبدیل کرݨ دا لاگ",
+       "export": "ورقے ٻاہر بھیجو",
+       "thumbnail-more": "وݙا کرو",
+       "importlogpage": "لاگ گھن آؤ",
+       "tooltip-pt-userpage": "تہاݙا صارف ورقہ",
+       "tooltip-pt-mytalk": "{{GENDER:|Your}} گالھ مہاڑ",
+       "tooltip-pt-preferences": "تہاݙیاں ترجیحاں",
+       "tooltip-pt-watchlist": " انہاں ورقیاں دی لسٹ جنہاں وچ تساں تبدیلیاں کرݨ کیتے ݙیہدے پئے ہو۔",
+       "tooltip-pt-mycontris": "میݙے کم",
+       "tooltip-pt-login": "لاگ ان تھیوو تاں چنگا ہے، ضروری کائنی۔",
+       "tooltip-pt-logout": "لاگ آؤٹ",
+       "tooltip-pt-createaccount": "ایہ تہاݙے کیتے چنگا ہے جو کھاتہ کھولو تے لاگ ان تھیوو، پر ایہ لازمی کائنی۔",
+       "tooltip-ca-talk": "مضمون بارے بحث",
+       "tooltip-ca-edit": "ایں ورقے تے لکھو",
+       "tooltip-ca-addsection": "نواں حصہ شروع کرو",
+       "tooltip-ca-viewsource": "ایہ ورقہ محفوظ تھیا ہویا ہے۔ \nتساں صرف ایندا ماخذ ݙیکھ سڳدے ہو۔",
+       "tooltip-ca-history": "ایں ورقے دا پراݨا روپ۔",
+       "tooltip-ca-protect": "ایہ ورقہ محفوظ کرو",
+       "tooltip-ca-delete": "ایں ورقے کوں مٹاؤ",
+       "tooltip-ca-move": "ایں ورقے کوں گھن ڄلو",
+       "tooltip-ca-watch": "ایں ورقے کوں آپݨی دید آلے ورقیاں وچ رکھو",
+       "tooltip-ca-unwatch": "ایں ورقے کوں آپݨی دید آلے ورقیاں وچ رکھو",
+       "tooltip-search": "ڳولو {{SITENAME}}",
+       "tooltip-search-go": "جے ایں عنوان دا ورقہ ہے تاں اتھ ونڄو",
+       "tooltip-search-fulltext": "ایں عبارت کوں ورقیاں وچ ڳولو",
+       "tooltip-p-logo": "پہلا ورقہ ݙیکھو",
+       "tooltip-n-mainpage": "پہلا ورقہ ݙیکھو",
+       "tooltip-n-mainpage-description": "پہلے ورقے تے ونڄو",
+       "tooltip-n-portal": "ایں مںصوبے بارے، تساں کیا کر سڳدو، ، چیزاں کتھوں ڳولوں",
+       "tooltip-n-currentevents": "موجودہ حالات وچ پچھلیاں معلومات ݙیکھو",
+       "tooltip-n-recentchanges": "وکی تے نویاں تبدیلیاں۔",
+       "tooltip-n-randompage": "کوئی صفہ کھولو۔",
+       "tooltip-n-help": "لبھݨ دی جاہ",
+       "tooltip-t-whatlinkshere": "ایں نال جڑے سارے وکی ورقے۔",
+       "tooltip-t-recentchangeslinked": "ایں ورقے توں جڑے ورقیاں وچ نویاں تبدیلیاں",
+       "tooltip-feed-atom": "اِیں ورقے دا اٹوم فیڈ",
+       "tooltip-t-upload": "فائل چڑھاؤ",
+       "tooltip-t-specialpages": "سارے خاص ورقیاں دی تندیر",
+       "tooltip-t-print": "ایں ورقے دا چھپݨ آلا انگ ݙیکھو",
+       "tooltip-t-permalink": "اس صفے دے ایں روپ نال پکا جوڑ",
+       "tooltip-ca-nstab-main": "مواد آلا صفہ ݙیکھو",
+       "tooltip-ca-nstab-user": "صارف دا ورقہ ݙیکھو",
+       "tooltip-ca-nstab-special": "ایہ ہک خاص ورقہ ہے، اینکوں تبدیل نسے کرسڳدے",
+       "tooltip-ca-nstab-project": "منصبے آلا ورقہ ݙیکھو",
+       "tooltip-ca-nstab-image": "فائل دا ورقہ ݙیکھو",
+       "tooltip-ca-nstab-mediawiki": "نظامی سنیہہ ݙیکھو",
+       "tooltip-ca-nstab-template": "سانچہ ݙیکھو",
+       "tooltip-ca-nstab-category": "کیٹاگری آلا ورقہ ݙیکھو",
+       "tooltip-save": "تبدیلیاں محفوظ کرو",
+       "tooltip-preview": "محفوظ کرݨ کنے پہلے تبدیلیاں ݙیکھو، مہربانی ہوسی۔",
+       "tooltip-diff": "ایں لکھت وچ کیتیاں ڳیاں تبدیلیاں ݙیکھاؤ",
+       "tooltip-rollback": "رول بیک\" ہک کلک وچ ورقے کوں پچھلی حالت وچ گھن ویسی\"",
+       "tooltip-undo": "واپس تے کلک کرݨ نال  پچھلی ترمیم تے پُڄ ویسو، نمائشی انداز وچ ترمیم دا خانہ کھلسی۔ تساں مختصر سسب وی بیان کر سڳدے ہو۔",
+       "tooltip-summary": "مختصر خلاصہ درج کرو",
+       "simpleantispam-label": "سپام روک پھاٹک\nاینکوں <strong>نہ</strong>  بھرو!",
+       "pageinfo-title": "«$1» دی معلومات",
+       "pageinfo-header-basic": "بنیادی معلومات",
+       "pageinfo-header-edits": "تاریخچۂ ترمیم",
+       "pageinfo-header-restrictions": "ورقے دی حفاظت",
+       "pageinfo-header-properties": "صفحہ دی خاصیتاں",
+       "pageinfo-display-title": "عنوان",
+       "pageinfo-default-sort": "کلید برائے ابتدائی ترتیب",
+       "pageinfo-length": "ورقے دی لمناݨ (بائٹ وچ)",
+       "pageinfo-article-id": "ورقے دی شناخت",
+       "pageinfo-language": "زبان",
+       "pageinfo-content-model": "انداز متن",
+       "pageinfo-robot-policy": "روبوٹ دی فہرست سازی",
+       "pageinfo-robot-index": "مجاز",
+       "pageinfo-robot-noindex": "ممنوع",
+       "pageinfo-watchers": "تعداد ناظرین",
+       "pageinfo-few-watchers": "$1 کنوں گھٹ {{PLURAL:$1|ناظر|ناظرین}}",
+       "pageinfo-redirects-name": "رجوعاں  دی تعداد",
+       "pageinfo-subpages-name": "ایں ورقے دے ذیلی ورقیاں دی تعداد",
+       "pageinfo-firstuser": "صفحہ ساز",
+       "pageinfo-firsttime": "صفحہ سازی دی تاریخ",
+       "pageinfo-lastuser": "چھیکڑی ترمیم کنندہ",
+       "pageinfo-lasttime": "چھیکڑی ترمیم دی تاریخ",
+       "pageinfo-edits": "ترامیم دی مجموعی تعداد",
+       "pageinfo-authors": "مختلف مصنفین دی  تعداد",
+       "pageinfo-recent-authors": "مختلف مصنفین دی حالیہ تعداد",
+       "pageinfo-magic-words": "جادوئی {{PLURAL:$1|لفظ|الفاظ}} ($1)",
+       "pageinfo-hidden-categories": "پوشیدہ {{PLURAL:$1|زمرہ|زمرہ جات}} ($1)",
+       "pageinfo-templates": "زیر استعمال {{PLURAL:$1|سانچہ|سانچے}} ($1)",
+       "pageinfo-toolboxlink": "معلومات صفحہ",
+       "pageinfo-contentpage": "شمار بطور ورقہ",
+       "pageinfo-contentpage-yes": "ڄیا",
+       "patrol-log-page": "گشت لاگ",
+       "previousdiff": "← پرانی لکھائی",
+       "nextdiff": "نویں لکھائی →",
+       "widthheightpage": "$1×$2، $3 {{PLURAL:$3|ورقہ|ورقے}}",
+       "file-info-size": "\n$1 × $2 پکسل، فائل دا حجم: $3، MIME قسم: $4",
+       "file-info-size-pages": "$1 × $2 پکسل، فائل دا حجم: $3، MIME قسم: $4، $5 {{PLURAL:$5|ورقہ|ورقے}}",
+       "file-nohires": "ایں توں زیادہ ریزولیوشن دستیاب کائنی۔",
+       "svg-long-desc": "ایس وی جی فائل، ابعاد $1 × $2 پکسل، فائل دا حجم: $3",
+       "show-big-image": "اصل فائل",
+       "show-big-image-preview": "ایں نمائش دا حجم:$1",
+       "show-big-image-other": "ٻیاں {{PLURAL:$2|قرارداد|قراردادیں}}: $1۔",
+       "show-big-image-size": "$1 × $2 پکسلز",
+       "metadata": "میٹا ڈیٹا",
+       "metadata-help": "ایں فائل وچ ٻیاں معلومات وی ہن۔ شاید او تہاݙے کیمرے یا سیکنر توں آیاں ہن، جیندے نال تساں ایہ فائل بݨائی ہائی۔\nجے ایہ فائل آپݨی اصل حالت وچ نہ ہووے تاں کجھ معلومات تبدیل تھئی ہوئی فائل دی پوری پوری عکاسی کائناں کریسی۔",
+       "metadata-fields": "تصویر دے میٹاڈیٹا دے او خانے جہڑے پیغام میں درج ہن او تصویر دے صفحے تے شامل ہوندے ہن۔ ایہ ااوں ویلے ظاہر تھیندن جڈݨ میٹاڈیٹا کوں ودھایا ونڄے۔\nٻئے خانے شروع وچ لُڳے ہوندن۔\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-orientation": "اورینٹیشن",
+       "exif-xresolution": "افقی ریزولوشن",
+       "exif-yresolution": "عمودی ریزولیشن",
+       "exif-datetime": "فائل بدلݨ دی تاریخ تے ویلا",
+       "exif-make": "کیمرہ ساز کمپنی",
+       "exif-model": "کیمرے دا ماڈل",
+       "exif-software": "مستعمل سافٹ ویئر",
+       "exif-exifversion": "اکزیف ورژن",
+       "exif-colorspace": "رنگ فضا",
+       "exif-datetimeoriginal": "ڈیٹا بݨاوݨ دی تاریخ تے ویلا",
+       "exif-datetimedigitized": "ڈجیٹائزنگ دا ویلہ تے تریخ",
+       "exif-orientation-1": "عام",
+       "namespacesall": "یکے",
+       "monthsall": "یکے",
+       "imgmultipagenext": "اگلا →",
+       "imgmultigo": "ونڄو!",
+       "imgmultigoto": "$1 تے ونڄو",
+       "watchlisttools-clear": "زیرنظر فہرست دی صفائی",
+       "watchlisttools-view": "متعلقہ تبدیلیاں ݙیکو",
+       "watchlisttools-edit": "زیرنظر فہرست  کوں ݙیکھو تے تبدیلی کرو",
+       "watchlisttools-raw": "کچی زیرِنظرفہرست وچ تبدیلی کرو",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|تبادلۂ خیال]])",
+       "redirect": "فائل، صارف، ورقہ،دہرائی یا آئی ڈی لاگ دے ذریعے ولدا واپس",
+       "redirect-submit": "ڄلو",
+       "redirect-lookup": "تلاش:",
+       "redirect-value": "قدر:",
+       "redirect-user": "صارف دی شناخت",
+       "redirect-page": "ورقے دی شناخت",
+       "redirect-revision": "ورقے دا رویژن",
+       "redirect-file": "فائل دا ناں",
+       "specialpages": "خاص ورقے",
+       "tag-filter": "[[Special:Tags|Tag]] نتارا:",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگز}}]]: $2)",
+       "tags-active-yes": "ڄیا",
+       "tags-active-no": "کو",
+       "tags-hitcount": "$1 {{PLURAL:$1|تبدیلی|تبدیلیاں}}",
+       "logentry-delete-delete": "$1 {{GENDER:$2|مٹایا ڳیا}} ورقہ $3",
+       "logentry-delete-restore": "$1 {{GENDER:$2|بحال تھی ڳیوہے}} page $3 ($4)",
+       "revdelete-content-hid": "مواد لکیا",
+       "logentry-move-move": "$1 {{جنس:$2|پلٹی}} صفہ $3 توں $4",
+       "logentry-newusers-create": "صارف کھاتہ $1 {{GENDER:$2|بݨایا ڳیا}}",
+       "logentry-newusers-autocreate": "صارف کھاتہ $1 خودکار طور  {{GENDER:$2|تخلیق تھیا}}",
+       "logentry-upload-upload": "$1 {{GENDER:$2|اپلوڈ}} $3",
+       "searchsuggest-search": "ڳولو",
+       "duration-days": "$1 {{PLURAL:$1|ݙینہ}}",
+       "randomrootpage": "بے ترتيب بنیادی صفحہ"
+}
index a20c372..ff1b21c 100644 (file)
        "rcfilters-legend-heading": "<strong>Seznam okrajšav:</strong>",
        "rcfilters-activefilters": "Dejavni filtri",
        "rcfilters-advancedfilters": "Napredni filtri",
+       "rcfilters-limit-title": "Spremembe za prikaz",
+       "rcfilters-limit-shownum": "Prikaži zadnjih $1 sprememb",
+       "rcfilters-days-title": "Pretekli dnevi",
+       "rcfilters-hours-title": "Pretekle ure",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|dan|dneva|dnevi|dni}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|ura|uri|ure|ur}}",
        "rcfilters-quickfilters": "Shranjeni filtri",
        "rcfilters-quickfilters-placeholder-title": "Shranjena ni še nobena povezava",
        "rcfilters-quickfilters-placeholder-description": "Da shranite svoje nastavitve filtrov in jih ponovno uporabite pozneje, kliknite na ikono za zaznamek v območju Dejavni filtri spodaj.",
        "rcfilters-invalid-filter": "Neveljaven filter",
        "rcfilters-empty-filter": "Ni dejavnih filtrov. Prikazani so vsi prispevki.",
        "rcfilters-filterlist-title": "Filtri",
-       "rcfilters-filterlist-whatsthis": "Kaj je to?",
+       "rcfilters-filterlist-whatsthis": "Kako to deluje?",
        "rcfilters-filterlist-feedbacklink": "Podajte povratne informacije o novih (preizkusnih) filtrih",
        "rcfilters-highlightbutton-title": "Označi rezultate",
        "rcfilters-highlightmenu-title": "Izberite barvo",
        "rcfilters-filter-editsbyself-description": "Vaša lastna urejanja.",
        "rcfilters-filter-editsbyother-label": "Spremembe drugih",
        "rcfilters-filter-editsbyother-description": "Vse spremembe razen vaše.",
-       "rcfilters-filtergroup-userExpLevel": "Stopnja izkušenosti (samo za registrirane uporabnike)",
+       "rcfilters-filtergroup-userExpLevel": "Registriranost in izkušenost uporabnika",
        "rcfilters-filter-user-experience-level-registered-label": "Registriran",
        "rcfilters-filter-user-experience-level-registered-description": "Prijavljeni uredniki.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Neregistriran",
        "rcfilters-filter-user-experience-level-unregistered-description": "Uredniki, ki niso prijavljeni.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Novinci",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Manj kot 10 urejanj in 4 dni dejavnosti.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Registrirani uredniki z manj kot 10 urejanji in 4 dnevi dejavnosti.",
        "rcfilters-filter-user-experience-level-learner-label": "Učenci",
-       "rcfilters-filter-user-experience-level-learner-description": "Več izkušenj kot »Novinci«, vendar manj kot »Izkušeni uporabniki«.",
+       "rcfilters-filter-user-experience-level-learner-description": "Registrirani uredniki, katerih izkušenost se uvršča med »Novince« in »Izkušene uporabnike«.",
        "rcfilters-filter-user-experience-level-experienced-label": "Izkušeni uporabniki",
-       "rcfilters-filter-user-experience-level-experienced-description": "Več kot 30 dni dejavnosti in 500 urejanj.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Registrirani uredniki z več kot 500 urejanji in 30 dnevi dejavnosti.",
        "rcfilters-filtergroup-automated": "Samodejni prispevki",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-bots-description": "Urejanja, narejena s samodejnimi orodji.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filter »Manjša urejanja« je v sporu z enim ali več filtri Vrsta spremembe, ker nekaterih vrst urejanj ni možno označiti kot »manjša«. Filtri v sporu so označeni v območju Dejavni filtri zgoraj.",
        "rcfilters-hideminor-conflicts-typeofchange": "Nekaterih vrst sprememb ni možno označiti kot »manjše«, zato je ta filter v sporu z naslednjimi filtri Vrsta spremembe: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Ta filter Vrsta spremembe je v sporu s filtrom »Manjše urejanje«. Nekaterih vrst sprememb ni možno označiti kot »manjše«.",
-       "rcfilters-filtergroup-lastRevision": "Zadnja redakcija",
-       "rcfilters-filter-lastrevision-label": "Zadnja redakcija",
-       "rcfilters-filter-lastrevision-description": "Najnovejša sprememba strani.",
-       "rcfilters-filter-previousrevision-label": "Zgodnejše redakcije",
-       "rcfilters-filter-previousrevision-description": "Vse spremembe, ki niso najnovejša sprememba strani.",
+       "rcfilters-filtergroup-lastRevision": "Najnovejše redakcije",
+       "rcfilters-filter-lastrevision-label": "Najnovejša redakcija",
+       "rcfilters-filter-lastrevision-description": "Samo najnovejša sprememba strani.",
+       "rcfilters-filter-previousrevision-label": "Nenajnovejša redakcija",
+       "rcfilters-filter-previousrevision-description": "Vse spremembe, ki niso »najnovejša redakcija«.",
        "rcfilters-filter-excluded": "Izključeno",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:ne</strong> $1",
+       "rcfilters-exclude-button-off": "Izključi izbrane",
+       "rcfilters-exclude-button-on": "Izključitev izbranih",
        "rcfilters-view-tags": "Označena urejanja",
        "rcfilters-view-namespaces-tooltip": "Filtriraj rezultate po imenskem prostoru",
        "rcfilters-view-tags-tooltip": "Filtriraj rezultate z uporabo oznak urejanj",
        "delete-warning-toobig": "Ta stran ima obsežno zgodovino urejanja, tj. čez $1 {{PLURAL:$1|redakcijo|redakciji|redakcije|redakcij}}.\nNjeno brisanje lahko zmoti obratovanje zbirke podatkov {{GRAMMAR:dative|{{SITENAME}}}};\nnadaljujte s previdnostjo.",
        "deleteprotected": "Strani ne morete izbrisati, ker jo je nekdo zaščitil.",
        "deleting-backlinks-warning": "<strong>Opozorilo:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Druge strani]] se povezujejo na ali vključujejo stran, ki jo nameravate izbrisati.",
+       "deleting-subpages-warning": "<strong>Opozorilo:</strong> Stran, ki jo nameravate izbrisati, ima [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|podstran|$1 podstrani|51=več kot 50 podstrani}}]].",
        "rollback": "Vrni spremembe",
        "rollbacklink": "vrni",
        "rollbacklinkcount": "vrni $1 {{PLURAL:$1|urejanje|urejanji|urejanja|urejanj}}",
index 1303239..191dd95 100644 (file)
        "rcfilters-legend-heading": "<strong>Lista över förkortningar:</strong>",
        "rcfilters-activefilters": "Aktiva filter",
        "rcfilters-advancedfilters": "Avancerade filter",
+       "rcfilters-limit-title": "Ändringar att visa",
+       "rcfilters-limit-shownum": "Visa de senaste $1 ändringarna",
+       "rcfilters-days-title": "Senaste dagarna",
+       "rcfilters-hours-title": "Senaste timmarna",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|dag|dagar}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|timme|timmar}}",
        "rcfilters-quickfilters": "Sparade filter",
        "rcfilters-quickfilters-placeholder-title": "Inga länkar har sparats ännu",
        "rcfilters-quickfilters-placeholder-description": "För att spara dina filterinställningar och återanvända dem senare, klicka på bokmärkesikonen under \"Aktiva filter\" nedan.",
        "rcfilters-invalid-filter": "Ogiltigt filter",
        "rcfilters-empty-filter": "Inga aktiva filter. Alla bidrag visas.",
        "rcfilters-filterlist-title": "Filter",
-       "rcfilters-filterlist-whatsthis": "Vad är detta?",
+       "rcfilters-filterlist-whatsthis": "Hur fungerar desse?",
        "rcfilters-filterlist-feedbacklink": "Ge återkoppling på nya (beta)filter",
        "rcfilters-highlightbutton-title": "Markera resultat",
        "rcfilters-highlightmenu-title": "Välj en färg",
        "rcfilters-filter-editsbyself-description": "Dina egna bidrag.",
        "rcfilters-filter-editsbyother-label": "Ändringar av andra",
        "rcfilters-filter-editsbyother-description": "Alla ändringar förutom dina egna.",
-       "rcfilters-filtergroup-userExpLevel": "Erfarenhetsnivå (endast för registrerade användare)",
+       "rcfilters-filtergroup-userExpLevel": "Användarregistrering och -erfarenhet",
        "rcfilters-filter-user-experience-level-registered-label": "Registrerade",
        "rcfilters-filter-user-experience-level-registered-description": "Inloggade redigerare.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Oregistrerade",
        "rcfilters-filter-user-experience-level-unregistered-description": "Redigerare som inte är inloggade.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Nykomlingar",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Färre än 10 redigeringar och 4 dagars aktivitet.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "Registrerade redigerare med färre än 10 redigeringar och 4 dagars aktivitet.",
        "rcfilters-filter-user-experience-level-learner-label": "Nybörjare",
-       "rcfilters-filter-user-experience-level-learner-description": "Mer erfarenhet än \"Nybörjare\" men mindre än \"Erfarna användare\".",
+       "rcfilters-filter-user-experience-level-learner-description": "Registrerade redigerare vars erfarenhet hamnar mellan \"Nybörjare\" och \"Erfarna användare\".",
        "rcfilters-filter-user-experience-level-experienced-label": "Erfarna användare",
-       "rcfilters-filter-user-experience-level-experienced-description": "Fler än 30 dagars aktivitet och 500 redigeringar.",
+       "rcfilters-filter-user-experience-level-experienced-description": "Registrerade redigerare med fler än 500 redigeringar och 30 dagars aktivitet.",
        "rcfilters-filtergroup-automated": "Automatiserade bidrag",
        "rcfilters-filter-bots-label": "Bot",
        "rcfilters-filter-bots-description": "Redigeringar gjorda av automatiserade verktyg.",
        "rcfilters-hideminor-conflicts-typeofchange-global": "Filtret \"Mindre redigering\" är i konflikt med en eller flera ändringstypfilter, eftersom vissa ändringstyper inte kan betecknas som \"mindre\". Filtren som är i konflikt är markerade i området med aktiva filter ovan.",
        "rcfilters-hideminor-conflicts-typeofchange": "Vissa ändringstyper kan inte betecknas som \"mindre\", så detta filter är i konflikt med följande ändringstypfilter: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Detta ändringstypfilter är i konflikt med filtret \"Mindre ändringar\". Vissa ändringstyper kan inte betecknas som \"mindre\".",
-       "rcfilters-filtergroup-lastRevision": "Senaste version",
+       "rcfilters-filtergroup-lastRevision": "Senaste versioner",
        "rcfilters-filter-lastrevision-label": "Senaste version",
-       "rcfilters-filter-lastrevision-description": "Den senaste ändringen av en sida.",
-       "rcfilters-filter-previousrevision-label": "Tidigare versioner",
-       "rcfilters-filter-previousrevision-description": "Alla ändringar som inte är den senaste ändringen av en sida.",
+       "rcfilters-filter-lastrevision-description": "Endast senaste ändringen av en sida.",
+       "rcfilters-filter-previousrevision-label": "Inte den senaste versionen",
+       "rcfilters-filter-previousrevision-description": "Alla ändringar som inte är den \"senaste versionen\".",
        "rcfilters-filter-excluded": "Exkluderad",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:not</strong> $1",
+       "rcfilters-exclude-button-off": "Exkludera markerade",
+       "rcfilters-exclude-button-on": "Exkluderar markerade",
        "rcfilters-view-tags": "Märkta redigeringar",
        "rcfilters-view-namespaces-tooltip": "Filtrera resultat efter namnrymder",
        "rcfilters-view-tags-tooltip": "Filtrera resultat med redigeringsmärken",
        "delete-warning-toobig": "Denna sida har en lång redigeringshistorik med mer än $1 {{PLURAL:$1|sidversion|sidversioner}}. Att radera sidan kan skapa problem med hanteringen av databasen på {{SITENAME}}; var försiktig.",
        "deleteprotected": "Du kan inte radera denna sida eftersom den är skyddad.",
        "deleting-backlinks-warning": "<strong>Varning:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Andra sidor]] länkar till eller inkluderar sidan som du är på väg att radera.",
+       "deleting-subpages-warning": "<strong>Varning:</strong> Sidan du håller på att radera har [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|en undersida|$1 undersidor|51=över 50 undersidor}}]].",
        "rollback": "Rulla tillbaka ändringar",
        "rollbacklink": "rulla tillbaka",
        "rollbacklinkcount": "rulla tillbaka $1 {{PLURAL:$1|redigering|redigeringar}}",
index fd2ac88..2e31c50 100644 (file)
        "recentchanges-legend-heading": "<strong>సూచిక :</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|కొత్త పేజీల జాబితా]]ను కూడా చూడండి)",
        "recentchanges-submit": "చూపించు",
+       "rcfilters-savedqueries-remove": "తొలగించు",
+       "rcfilters-savedqueries-new-name-label": "పేరు",
        "rcfilters-filterlist-title": "వడపోతలు",
        "rcfilters-highlightmenu-title": "ఒక రంగును ఎంచుకోండి",
        "rcfilters-filter-editsbyself-label": "మీ దిద్దుబాట్లు",
        "rcfilters-filter-editsbyother-label": "ఇతరుల దిద్దుబాట్లు",
        "rcfilters-filter-editsbyother-description": "మీరు చేసినవి కాకుండా మిగిలిన దిద్దుబాట్లన్నీ.",
        "rcfilters-filtergroup-userExpLevel": "అనుభవ స్థాయి (నమోదైన వాడుకరులకు మాత్రమే)",
+       "rcfilters-filter-user-experience-level-registered-label": "నమోదైనది",
        "rcfilters-filter-user-experience-level-newcomer-label": "కొత్తవారు",
        "rcfilters-filter-user-experience-level-newcomer-description": "10 కంటే తక్కువ దిద్దుబాట్లు, 4 రోజుల కంటే తక్కువ పని.",
        "rcfilters-filter-user-experience-level-learner-label": "నేర్చుకుంటున్నవారు",
index 05cf315..3d72f11 100644 (file)
        "page_first": "uluk",
        "page_last": "ikus",
        "histfirst": "sedu liu hotu",
-       "histlast": "Foun liu hotu",
+       "histlast": "foun liu hotu",
        "historyempty": "(mamuk)",
        "history-feed-item-nocomment": "$1 iha $2",
        "rev-delundel": "hatudu/subar",
index 1619bb5..25c0457 100644 (file)
@@ -13,7 +13,8 @@
                        "아라",
                        "Macofe",
                        "AryanSogd",
-                       "ToJack"
+                       "ToJack",
+                       "Vashgird"
                ]
        },
        "tog-underline": "Пайвандҳо хаткашида:",
        "tog-watchlisthideliu": "Пинҳон кардани вироишоти корбарони вурудшуда аз феҳристи пайгириҳо",
        "tog-watchlisthideanons": "Пинҳон кардани вироишоти корбарони гумном аз феҳристи пайгириҳо",
        "tog-watchlisthidepatrolled": "Пинҳони вироишҳои гаштхӯрда аз феҳристи пайгириҳо",
+       "tog-watchlisthidecategorization": "Пинҳон кардани гурӯҳбандии саҳифаҳо",
        "tog-ccmeonemails": "Нусхаҳои хатҳоро ба ман рои кунед, ман онҳоро ба корбарон рои мекунам",
        "tog-diffonly": "Муҳтавиёти саҳифаи зерин намоиш дода нашавад",
        "tog-showhiddencats": "Гурӯҳҳои пинҳонро намоиш бидеҳ",
-       "tog-norollbackdiff": "Баъд аз вогардони тафовутро нишон надеҳ",
+       "tog-norollbackdiff": "Баъд аз вогардонӣ тафовутро нишон надеҳ",
        "tog-useeditwarning": "Дар ҳолати тарки саҳифа вироиши тағйироти захиранашуда манро огаҳ кун",
-       "tog-prefershttps": "ҲамеÑ\88а Ð¿Ð°Ð¹Ð²Ð°Ñ\81Ñ\82Ñ\88авии Ð°Ð¼Ð½Ñ\80о Ð´Ð°Ñ\80 Ò³Ð¾Ð»Ð¸ Ð²Ñ\83Ñ\80Ñ\83д Ð¸Ñ\81Ñ\82иÑ\84ода Ð±Ð°Ñ\80",
+       "tog-prefershttps": "ҲамеÑ\88а Ð¸Ñ\81Ñ\82иÑ\84ода Ð±Ñ\83Ñ\80дани Ð¿Ð°Ð¹Ð²Ð°Ñ\81Ñ\82Ñ\88авии Ð°Ð¼Ð½ Ð´Ð°Ñ\80 Ò³Ð¾Ð»Ð¸ Ð²Ñ\83Ñ\80Ñ\83д",
        "underline-always": "Доимо",
        "underline-never": "Ҳеҷгоҳ",
        "underline-default": "Пӯст ё мурургари пешфарз",
        "october-date": "$1 октябр",
        "november-date": "$1 ноябр",
        "december-date": "$1 декабр",
+       "period-am": "АМ",
+       "period-pm": "РМ",
        "pagecategories": "{{PLURAL:$1|Гурӯҳ|Гурӯҳҳо}}",
        "category_header": "Мақолаҳо дар гурӯҳи \"$1\"",
        "subcategories": "Зергурӯҳҳо",
        "morenotlisted": "Ин феҳрист комил нест.",
        "mypage": "Саҳифа",
        "mytalk": "Баҳс",
-       "anontalk": "Баҳс бо ин IP",
+       "anontalk": "Баҳс",
        "navigation": "Гаштан",
        "and": "&#32;ва",
        "faq": "Саволҳои тез-тез пурсидашуда",
        "license": "Иҷозатнома:",
        "license-header": "Иҷозатнома",
        "nolicense": "Ҳеҷ яке интихоб нашудааст",
+       "licenses-edit": "Тағйири имконоти иҷозатнома",
        "license-nopreview": "(Пешнамоиш вуҷуд надорад)",
        "upload_source_url": "(як нишони интернетии мӯътабар ва оммавӣ)",
        "upload_source_file": " (парвандае дар компютери шумо)",
index d434d40..d415870 100644 (file)
@@ -36,7 +36,8 @@
                        "Xð",
                        "Nguyên Lê",
                        "Asmen",
-                       "Stephanecbisson"
+                       "Stephanecbisson",
+                       "Quoclinh94"
                ]
        },
        "tog-underline": "Gạch chân liên kết:",
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "Xem",
        "rcfilters-activefilters": "Bộ lọc hiện hành",
+       "rcfilters-days-title": "Những ngày gần đây",
        "rcfilters-savedqueries-setdefault": "Đặt làm mặc định",
        "rcfilters-savedqueries-unsetdefault": "Loại bỏ mặc định",
        "rcfilters-restore-default-filters": "Mặc định lại các bộ lọc",
        "rcfilters-highlightmenu-help": "Chọn màu để làm nổi bật thuộc tính này",
        "rcfilters-filterlist-noresults": "Không tìm thấy bộ lọc",
        "rcfilters-noresults-conflict": "Không tìm thấy kết quả nào do tiêu chí tìm kiếm đang bị mâu thuẫn",
-       "rcfilters-filtergroup-registration": "Trạng thái đăng ký thành viên",
-       "rcfilters-filter-registered-label": "Đã đăng ký",
-       "rcfilters-filter-registered-description": "Người dùng đã đăng nhập.",
-       "rcfilters-filter-unregistered-label": "Vô danh",
-       "rcfilters-filter-unregistered-description": "Người dùng chưa đăng nhập.",
        "rcfilters-filtergroup-authorship": "Người sửa đổi",
        "rcfilters-filter-editsbyself-label": "Sửa đổi của bạn",
        "rcfilters-filter-editsbyself-description": "Các sửa đổi do bạn tạo ra.",
        "rcfilters-filter-editsbyother-label": "Sửa đổi của người khác",
        "rcfilters-filter-editsbyother-description": "Các sửa đổi của người khác.",
        "rcfilters-filtergroup-userExpLevel": "Trình độ (chỉ người dùng đã đăng ký)",
+       "rcfilters-filter-user-experience-level-registered-label": "Đã đăng ký",
+       "rcfilters-filter-user-experience-level-registered-description": "Người dùng đã đăng nhập.",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Vô danh",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Người dùng chưa đăng nhập.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Người mới đến",
        "rcfilters-filter-user-experience-level-newcomer-description": "Chưa tới 10 sửa đổi và 4 ngày hoạt động.",
        "rcfilters-filter-user-experience-level-learner-label": "Người đang tập",
index 4001765..7c26085 100644 (file)
        "rcfilters-filterlist-whatsthis": "וואס איז דאס?",
        "rcfilters-highlightmenu-title": "אויסקלויבן א קאליר",
        "rcfilters-filterlist-noresults": "קיין פֿילטערס נישט געטראפֿן",
-       "rcfilters-filtergroup-registration": "באניצער איינשרייבונג",
-       "rcfilters-filter-registered-label": "אײַנגעשריבן",
        "rcfilters-filter-editsbyself-label": "ענדערונגען פון אייך",
        "rcfilters-filter-editsbyself-description": "אייערע אייגענע בײשטײערונגען.",
        "rcfilters-filter-editsbyother-label": "ענדערונגען פֿון אנדערע",
        "rcfilters-filter-editsbyother-description": "אלע ענדערונגען אחוץ אייערע אייגענע.",
+       "rcfilters-filter-user-experience-level-registered-label": "אײַנגעשריבן",
        "rcfilters-filter-user-experience-level-learner-label": "לערנער",
        "rcfilters-filter-bots-label": "באט",
        "rcfilters-filter-humans-label": "מענטש (נישט קיין באט)",
        "undeletecomment": "אורזאַך:",
        "cannotundelete": "טייל אדער גארע צוריקשטעלונג איז דורכגעפאלן: $1",
        "undeletedpage": "'''דער בלאט $1 איז געווארן צוריקגעשטעלט.'''\n\nזעט דעם [[Special:Log/delete| אויסמעקן לאג]] פֿאר א ליסטע פון די לעצטע אויסגעמעקטע און צוריקגעשטעלטע בלעטער.",
-       "undelete-header": "זעט [[Special:Log/delete|דעם אויסמעקונג זשורנאַל]] פֿאַר בלעטער וואָס זענען לעצטנס געווארן אויסגעמעקט recently deleted pages.",
+       "undelete-header": "זעט [[Special:Log/delete|דעם אויסמעקונג זשורנאַל]] פֿאַר בלעטער וואָס זענען לעצטנס געווארן אויסגעמעקט.",
        "undelete-search-title": "זוכן אויסגעמעקטע בלעטער",
        "undelete-search-box": "זוכן אויסגעמעקטע בלעטער",
        "undelete-search-prefix": "ווײַז בלעטער וואס הייבן אן מיט:",
index 8902585..7c9cd49 100644 (file)
        "grant-editmywatchlist": "改你嘅監視清單",
        "grant-editpage": "改已經有嘅版",
        "grant-editprotected": "改保護咗嘅版",
+       "grant-viewmywatchlist": "睇你嘅監視清單",
        "newuserlogpage": "使用者開戶記錄",
        "newuserlogpagetext": "呢個係一個使用者開戶嘅日誌",
        "rightslog": "用戶權限日誌",
index 9a579ca..1b5c014 100644 (file)
        "rcfilters-filter-editsbyself-description": "您自己的贡献。",
        "rcfilters-filter-editsbyother-label": "他人更改",
        "rcfilters-filter-editsbyother-description": "除了您的更改以外的所有更改。",
-       "rcfilters-filtergroup-userExpLevel": "体验水平(仅限注册用户)",
+       "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-hideminor-conflicts-typeofchange-global": "“小编辑”过滤器与一个或多个更改类型过滤器冲突,因为其中某种更改类型不可指定为“小编辑”。冲突过滤器已在上方活跃过滤器中被标记。",
        "rcfilters-hideminor-conflicts-typeofchange": "某种更改类型不可指定为“小编辑”,因此该过滤器与以下更改类型过滤器相冲突:$1",
        "rcfilters-typeofchange-conflicts-hideminor": "这种更改类型过滤器与“小编辑”过滤器相冲突。某种更改类型不可指定为“小编辑”。",
-       "rcfilters-filtergroup-lastRevision": "最新版本",
-       "rcfilters-filter-lastrevision-label": "最新版本",
-       "rcfilters-filter-lastrevision-description": "对页面的最近更改。",
-       "rcfilters-filter-previousrevision-label": "早期版本",
-       "rcfilters-filter-previousrevision-description": "除最近更改外,所有对某一页面的更改。",
+       "rcfilters-filtergroup-lastRevision": "最新修订版本",
+       "rcfilters-filter-lastrevision-label": "最新修订版本",
+       "rcfilters-filter-lastrevision-description": "å\8fªå\8c\85æ\8b¬å¯¹é¡µé\9d¢ç\9a\84æ\9c\80è¿\91æ\9b´æ\94¹ã\80\82",
+       "rcfilters-filter-previousrevision-label": "不是最新修订版本",
+       "rcfilters-filter-previousrevision-description": "所有不是“最新修订版本”的更改。",
        "rcfilters-filter-excluded": "已排除",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>:不是</strong>$1",
        "rcfilters-exclude-button-off": "排除选项",
        "delete-warning-toobig": "此页面有大量的编辑历史,超过$1个版本。删除它可能会破坏{{SITENAME}}的数据库操作;请谨慎考虑是否执行。",
        "deleteprotected": "您不能删除此页面因为它被保护。",
        "deleting-backlinks-warning": "<strong>警告:</strong>有[[Special:WhatLinksHere/{{FULLPAGENAME}}|其他页面]]链接至或包含您要删除的页面。",
+       "deleting-subpages-warning": "<strong>警告:</strong>您要删除的页面有[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|$1个子页面|51=超过50个子页面}}]]。",
        "rollback": "回退编辑",
        "rollbacklink": "回退",
        "rollbacklinkcount": "回退$1次编辑",
index 8a837d2..d273a6a 100644 (file)
@@ -140,9 +140,6 @@ class GenerateSitemap extends Maintenance {
         */
        private $identifier;
 
-       /**
-        * Constructor
-        */
        public function __construct() {
                parent::__construct();
                $this->addDescription( 'Creates a sitemap for the site' );
index cf0acde..9e9fd3e 100644 (file)
@@ -40,7 +40,6 @@ class CheckLanguageCLI {
        private $includeExif = false;
 
        /**
-        * Constructor.
         * @param array $options Options for script.
         */
        public function __construct( array $options ) {
@@ -557,7 +556,6 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
        private $extensions;
 
        /**
-        * Constructor.
         * @param array $options Options for script.
         * @param string $extension The extension name (or names).
         */
index 602bdab..dec0fe8 100644 (file)
@@ -8,24 +8,24 @@
 
 /**
  * Hide all the elements irrelevant for printing
+ * Skins however can and should override.
  */
 /* General hide-in-print class, please only use sparely */
 .noprint,
 /* Various content classes, in alphabetical order */
+.catlinks,
 .magnify,
 .mw-cite-backlink,
 .mw-jump,
 .mw-editsection,
 .mw-editsection-like,
 .mw-hidden-catlinks,
-.noexcerpt,
-.ns-0 .mw-redirectedfrom,
+.mw-indicators,
+.mw-redirectedfrom,
 .patrollink,
-.play-btn-large,
 .usermessage,
 /* Various content ids, in alphabetical order */
 #column-one,
-#coordinates .image,
 #footer-places,
 #jump-to-nav,
 #mw-navigation,
index 8bedd68..b6eda0f 100644 (file)
         */
        mw.rcfilters.dm.FilterGroup.prototype.onFilterItemUpdate = function ( item ) {
                // Update state
-               var active = this.areAnySelected();
+               var changed = false,
+                       active = this.areAnySelected();
 
                if (
                        item.isSelected() &&
                        this.currSelected.toggleSelected( false );
                }
 
+               // For 'single_option' groups, check if we just unselected all
+               // items. This should never be the result. If we did unselect
+               // all (like resetting all filters to false) then this group
+               // must choose its default item or the first item in the group
                if (
+                       this.getType() === 'single_option' &&
+                       !this.getItems().some( function ( filterItem ) {
+                               return filterItem.isSelected();
+                       } )
+               ) {
+                       // Single option means there must be a single option
+                       // selected, so we have to either select the default
+                       // or select the first option
+                       this.currSelected = this.getItemByParamName( this.defaultParams[ this.getName() ] );
+                       this.currSelected.toggleSelected( true );
+                       changed = true;
+               }
+
+               if (
+                       changed ||
                        this.active !== active ||
                        this.currSelected !== item
                ) {
index 8f318ef..a602c32 100644 (file)
                // Check if there are either any selected items or any items
                // that have highlight enabled
                return !this.getItems().some( function ( filterItem ) {
-                       return filterItem.isSelected() || filterItem.isHighlighted();
+                       return !filterItem.getGroupModel().isHidden() && ( filterItem.isSelected() || filterItem.isHighlighted() );
                } );
        };
 
index 6cd2d0b..9da3f8c 100644 (file)
@@ -39,6 +39,7 @@
 
                        // Set as ready
                        $( '.rcfilters-head' ).addClass( 'mw-rcfilters-ui-ready' );
+                       $( '.rcfilters-spinner' ).detach();
 
                        $( 'a.mw-helplink' ).attr(
                                'href',
index 6277fd9..305f3f9 100644 (file)
@@ -1,5 +1,5 @@
 // Corrections for the standard special page
-.client-js{
+.client-js {
        .rcoptions {
                border: 0;
                border-bottom: 1px solid #a2a9b1;
 
        .rcfilters-head {
                min-height: 310px;
-               &:not( .mw-rcfilters-ui-ready ) {
-                       /* @embed */
-                       background-image: url( ../images/pending.gif );
-                       margin: 0;
 
-                       * {
-                               visibility: hidden;
-                       }
+               &:not( .mw-rcfilters-ui-ready ) {
+                       opacity: 0.5;
+                       pointer-events: none;
                }
        }
 
                // message of our own
                display: none;
        }
+
+       .rcfilters-spinner {
+               margin: -2em auto 0;
+               width: 70px;
+               opacity: 0.8;
+               display: block;
+               white-space: nowrap;
+
+               & .rcfilters-spinner-bounce,
+               &:before,
+               &:after {
+                       content: '';
+                       display: inline-block;
+                       width: 12px;
+                       height: 12px;
+                       background-color: #c8ccd1;
+                       border-radius: 100%;
+                       animation: rcfiltersBouncedelay 1.5s infinite ease-in-out;
+                       animation-fill-mode: both;
+                       animation-delay: -0.16s;
+               }
+
+               &:before {
+                       animation-delay: -0.33s;
+               }
+
+               &:after {
+                       animation-delay: 0s;
+               }
+
+       }
 }
 
 .mw-rcfilters-staticfilters-selected {
        font-weight: bold;
 }
+
+@keyframes rcfiltersBouncedelay {
+       0%,
+       100%,
+       80% {
+               transform: scale( 0.7 );
+       }
+       40% {
+               transform: scale( 1 );
+               background-color: #a2a9b1;
+       }
+}
index e8f504a..04f4174 100644 (file)
@@ -7,6 +7,7 @@
                &:after {
                        content: '';
                        mix-blend-mode: screen;
+                       pointer-events: none;
                        position: absolute;
                        width: 1.875em;
                        height: 1.875em;
index 5678a80..51b9815 100644 (file)
@@ -9,12 +9,15 @@
 mediaWiki.widgets.visibleByteLimit = function ( textInputWidget, limit ) {
        limit = limit || +textInputWidget.$input.attr( 'maxlength' );
 
+       // Temporarily disabled whilst upstream bug is fixed; T169982
+       /*
        function updateCount() {
                textInputWidget.setLabel( ( limit - $.byteLength( textInputWidget.getValue() ) ).toString() );
        }
        textInputWidget.on( 'change', updateCount );
        // Initialise value
        updateCount();
+       */
 
        // Actually enforce limit
        textInputWidget.$input.byteLimit( limit );
index 017d9fb..dffa863 100644 (file)
@@ -10,7 +10,7 @@
        };
        OO.ui.isMobile = function () {
                if ( isMobile === undefined ) {
-                       isMobile = mw.config.get( 'skin' ) === 'minerva';
+                       isMobile = !!mw.config.get( 'wgMFMode' );
                }
                return isMobile;
        };
index a8a8f4d..d8f89fb 100644 (file)
@@ -94,6 +94,7 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
        protected $isKnownEmpty = false;
        protected $type = ResourceLoaderModule::LOAD_GENERAL;
        protected $targets = [ 'phpunit' ];
+       protected $shouldEmbed = null;
 
        public function __construct( $options = [] ) {
                foreach ( $options as $key => $value ) {
@@ -143,6 +144,10 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
                return $this->isKnownEmpty;
        }
 
+       public function shouldEmbedModule( ResourceLoaderContext $context ) {
+               return $this->shouldEmbed !== null ? $this->shouldEmbed : parent::shouldEmbedModule( $context );
+       }
+
        public function enableModuleContentVersion() {
                return true;
        }
index a2c0d39..d47481c 100644 (file)
@@ -526,6 +526,10 @@ class ApiErrorFormatterTest extends MediaWikiLangTestCase {
         * @param array $expect
         */
        public function testGetMessageFromException( $exception, $options, $expect ) {
+               if ( $exception instanceof UsageException ) {
+                       $this->hideDeprecated( 'UsageException::getMessageArray' );
+               }
+
                $result = new ApiResult( 8388608 );
                $formatter = new ApiErrorFormatter( $result, Language::factory( 'en' ), 'html', false );
 
@@ -571,6 +575,12 @@ class ApiErrorFormatterTest extends MediaWikiLangTestCase {
        }
 
        public static function provideGetMessageFromException() {
+               MediaWiki\suppressWarnings();
+               $usageException = new UsageException(
+                       '<b>Something broke!</b>', 'ue-code', 0, [ 'xxx' => 'yyy', 'baz' => 23 ]
+               );
+               MediaWiki\restoreWarnings();
+
                return [
                        'Normal exception' => [
                                new RuntimeException( '<b>Something broke!</b>' ),
@@ -591,7 +601,7 @@ class ApiErrorFormatterTest extends MediaWikiLangTestCase {
                                ]
                        ],
                        'UsageException' => [
-                               new UsageException( '<b>Something broke!</b>', 'ue-code', 0, [ 'xxx' => 'yyy', 'baz' => 23 ] ),
+                               $usageException,
                                [],
                                [
                                        'text' => '&#60;b&#62;Something broke!&#60;/b&#62;',
@@ -600,7 +610,7 @@ class ApiErrorFormatterTest extends MediaWikiLangTestCase {
                                ]
                        ],
                        'UsageException, wrapped' => [
-                               new UsageException( '<b>Something broke!</b>', 'ue-code', 0, [ 'xxx' => 'yyy', 'baz' => 23 ] ),
+                               $usageException,
                                [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
                                [
                                        'text' => '(&#60;b&#62;Something broke!&#60;/b&#62;)',
index ea33a9e..ad334e9 100644 (file)
@@ -500,6 +500,10 @@ class ApiMainTest extends ApiTestCase {
                        MWExceptionHandler::getRedactedTraceAsString( $dbex )
                )->inLanguage( 'en' )->useDatabase( false )->text();
 
+               MediaWiki\suppressWarnings();
+               $usageEx = new UsageException( 'Usage exception!', 'ue', 0, [ 'foo' => 'bar' ] );
+               MediaWiki\restoreWarnings();
+
                $apiEx1 = new ApiUsageException( null,
                        StatusValue::newFatal( new ApiRawMessage( 'An error', 'sv-error1' ) ) );
                TestingAccessWrapper::newFromObject( $apiEx1 )->modulePath = 'foo+bar';
@@ -545,7 +549,7 @@ class ApiMainTest extends ApiTestCase {
                                ]
                        ],
                        [
-                               new UsageException( 'Usage exception!', 'ue', 0, [ 'foo' => 'bar' ] ),
+                               $usageEx,
                                [ 'existing-error', 'ue' ],
                                [
                                        'warnings' => [
diff --git a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
deleted file mode 100644 (file)
index 3dc810c..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-<?php
-/**
- * Holds tests for DatabaseMysqlBase MediaWiki class.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @author Antoine Musso
- * @copyright © 2013 Antoine Musso
- * @copyright © 2013 Wikimedia Foundation and contributors
- */
-
-use Wikimedia\Rdbms\TransactionProfiler;
-use Wikimedia\Rdbms\DatabaseDomain;
-use Wikimedia\Rdbms\MySQLMasterPos;
-use Wikimedia\Rdbms\DatabaseMysqlBase;
-
-/**
- * Fake class around abstract class so we can call concrete methods.
- */
-class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
-       // From Database
-       function __construct() {
-               $this->profiler = new ProfilerStub( [] );
-               $this->trxProfiler = new TransactionProfiler();
-               $this->cliMode = true;
-               $this->connLogger = new \Psr\Log\NullLogger();
-               $this->queryLogger = new \Psr\Log\NullLogger();
-               $this->errorLogger = function ( Exception $e ) {
-                       wfWarn( get_class( $e ) . ": {$e->getMessage()}" );
-               };
-               $this->currentDomain = DatabaseDomain::newUnspecified();
-       }
-
-       protected function closeConnection() {
-       }
-
-       protected function doQuery( $sql ) {
-       }
-
-       // From DatabaseMysql
-       protected function mysqlConnect( $realServer ) {
-       }
-
-       protected function mysqlSetCharset( $charset ) {
-       }
-
-       protected function mysqlFreeResult( $res ) {
-       }
-
-       protected function mysqlFetchObject( $res ) {
-       }
-
-       protected function mysqlFetchArray( $res ) {
-       }
-
-       protected function mysqlNumRows( $res ) {
-       }
-
-       protected function mysqlNumFields( $res ) {
-       }
-
-       protected function mysqlFieldName( $res, $n ) {
-       }
-
-       protected function mysqlFieldType( $res, $n ) {
-       }
-
-       protected function mysqlDataSeek( $res, $row ) {
-       }
-
-       protected function mysqlError( $conn = null ) {
-       }
-
-       protected function mysqlFetchField( $res, $n ) {
-       }
-
-       protected function mysqlRealEscapeString( $s ) {
-       }
-
-       function insertId() {
-       }
-
-       function lastErrno() {
-       }
-
-       function affectedRows() {
-       }
-
-       function getServerVersion() {
-       }
-}
-
-class DatabaseMysqlBaseTest extends MediaWikiTestCase {
-       /**
-        * @dataProvider provideDiapers
-        * @covers DatabaseMysqlBase::addIdentifierQuotes
-        */
-       public function testAddIdentifierQuotes( $expected, $in ) {
-               $db = new FakeDatabaseMysqlBase();
-               $quoted = $db->addIdentifierQuotes( $in );
-               $this->assertEquals( $expected, $quoted );
-       }
-
-       /**
-        * Feeds testAddIdentifierQuotes
-        *
-        * Named per T22281 convention.
-        */
-       function provideDiapers() {
-               return [
-                       // Format: expected, input
-                       [ '``', '' ],
-
-                       // Yeah I really hate loosely typed PHP idiocies nowadays
-                       [ '``', null ],
-
-                       // Dear codereviewer, guess what addIdentifierQuotes()
-                       // will return with thoses:
-                       [ '``', false ],
-                       [ '`1`', true ],
-
-                       // We never know what could happen
-                       [ '`0`', 0 ],
-                       [ '`1`', 1 ],
-
-                       // Whatchout! Should probably use something more meaningful
-                       [ "`'`", "'" ],  # single quote
-                       [ '`"`', '"' ],  # double quote
-                       [ '````', '`' ], # backtick
-                       [ '`’`', '’' ],  # apostrophe (look at your encyclopedia)
-
-                       // sneaky NUL bytes are lurking everywhere
-                       [ '``', "\0" ],
-                       [ '`xyzzy`', "\0x\0y\0z\0z\0y\0" ],
-
-                       // unicode chars
-                       [
-                               self::createUnicodeString( '`\u0001a\uFFFFb`' ),
-                               self::createUnicodeString( '\u0001a\uFFFFb' )
-                       ],
-                       [
-                               self::createUnicodeString( '`\u0001\uFFFF`' ),
-                               self::createUnicodeString( '\u0001\u0000\uFFFF\u0000' )
-                       ],
-                       [ '`☃`', '☃' ],
-                       [ '`メインページ`', 'メインページ' ],
-                       [ '`Басты_бет`', 'Басты_бет' ],
-
-                       // Real world:
-                       [ '`Alix`', 'Alix' ],  # while( ! $recovered ) { sleep(); }
-                       [ '`Backtick: ```', 'Backtick: `' ],
-                       [ '`This is a test`', 'This is a test' ],
-               ];
-       }
-
-       private static function createUnicodeString( $str ) {
-               return json_decode( '"' . $str . '"' );
-       }
-
-       function getMockForViews() {
-               $db = $this->getMockBuilder( 'DatabaseMysqli' )
-                       ->disableOriginalConstructor()
-                       ->setMethods( [ 'fetchRow', 'query' ] )
-                       ->getMock();
-
-               $db->method( 'query' )
-                       ->with( $this->anything() )
-                       ->willReturn( new FakeResultWrapper( [
-                               (object)[ 'Tables_in_' => 'view1' ],
-                               (object)[ 'Tables_in_' => 'view2' ],
-                               (object)[ 'Tables_in_' => 'myview' ]
-                       ] ) );
-
-               return $db;
-       }
-       /**
-        * @covers DatabaseMysqlBase::listViews
-        */
-       function testListviews() {
-               $db = $this->getMockForViews();
-
-               $this->assertEquals( [ 'view1', 'view2', 'myview' ],
-                       $db->listViews() );
-
-               // Prefix filtering
-               $this->assertEquals( [ 'view1', 'view2' ],
-                       $db->listViews( 'view' ) );
-               $this->assertEquals( [ 'myview' ],
-                       $db->listViews( 'my' ) );
-               $this->assertEquals( [],
-                       $db->listViews( 'UNUSED_PREFIX' ) );
-               $this->assertEquals( [ 'view1', 'view2', 'myview' ],
-                       $db->listViews( '' ) );
-       }
-
-       /**
-        * @dataProvider provideComparePositions
-        */
-       function testHasReached( MySQLMasterPos $lowerPos, MySQLMasterPos $higherPos, $match ) {
-               if ( $match ) {
-                       $this->assertTrue( $lowerPos->channelsMatch( $higherPos ) );
-
-                       $this->assertTrue( $higherPos->hasReached( $lowerPos ) );
-                       $this->assertTrue( $higherPos->hasReached( $higherPos ) );
-                       $this->assertTrue( $lowerPos->hasReached( $lowerPos ) );
-                       $this->assertFalse( $lowerPos->hasReached( $higherPos ) );
-               } else { // channels don't match
-                       $this->assertFalse( $lowerPos->channelsMatch( $higherPos ) );
-
-                       $this->assertFalse( $higherPos->hasReached( $lowerPos ) );
-                       $this->assertFalse( $lowerPos->hasReached( $higherPos ) );
-               }
-       }
-
-       function provideComparePositions() {
-               return [
-                       // Binlog style
-                       [
-                               new MySQLMasterPos( 'db1034-bin.000976', '843431247' ),
-                               new MySQLMasterPos( 'db1034-bin.000976', '843431248' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
-                               new MySQLMasterPos( 'db1034-bin.000976', '1000' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
-                               new MySQLMasterPos( 'db1035-bin.000976', '1000' ),
-                               false
-                       ],
-                       // MySQL GTID style
-                       [
-                               new MySQLMasterPos( 'db1-bin.2', '1', '3E11FA47-71CA-11E1-9E33-C80AA9429562:23' ),
-                               new MySQLMasterPos( 'db1-bin.2', '2', '3E11FA47-71CA-11E1-9E33-C80AA9429562:24' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1-bin.2', '1', '3E11FA47-71CA-11E1-9E33-C80AA9429562:99' ),
-                               new MySQLMasterPos( 'db1-bin.2', '2', '3E11FA47-71CA-11E1-9E33-C80AA9429562:100' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1-bin.2', '1', '3E11FA47-71CA-11E1-9E33-C80AA9429562:99' ),
-                               new MySQLMasterPos( 'db1-bin.2', '2', '1E11FA47-71CA-11E1-9E33-C80AA9429562:100' ),
-                               false
-                       ],
-                       // MariaDB GTID style
-                       [
-                               new MySQLMasterPos( 'db1-bin.2', '1', '255-11-23' ),
-                               new MySQLMasterPos( 'db1-bin.2', '2', '255-11-24' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1-bin.2', '1', '255-11-99' ),
-                               new MySQLMasterPos( 'db1-bin.2', '2', '255-11-100' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1-bin.2', '1', '255-11-999' ),
-                               new MySQLMasterPos( 'db1-bin.2', '2', '254-11-1000' ),
-                               false
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideChannelPositions
-        */
-       function testChannelsMatch( MySQLMasterPos $pos1, MySQLMasterPos $pos2, $matches ) {
-               $this->assertEquals( $matches, $pos1->channelsMatch( $pos2 ) );
-               $this->assertEquals( $matches, $pos2->channelsMatch( $pos1 ) );
-       }
-
-       function provideChannelPositions() {
-               return [
-                       [
-                               new MySQLMasterPos( 'db1034-bin.000876', '44' ),
-                               new MySQLMasterPos( 'db1034-bin.000976', '74' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1052-bin.000976', '999' ),
-                               new MySQLMasterPos( 'db1052-bin.000976', '1000' ),
-                               true
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1066-bin.000976', '9999' ),
-                               new MySQLMasterPos( 'db1035-bin.000976', '10000' ),
-                               false
-                       ],
-                       [
-                               new MySQLMasterPos( 'db1066-bin.000976', '9999' ),
-                               new MySQLMasterPos( 'trump2016.000976', '10000' ),
-                               false
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideLagAmounts
-        */
-       function testPtHeartbeat( $lag ) {
-               $db = $this->getMockBuilder( 'DatabaseMysqli' )
-                       ->disableOriginalConstructor()
-                       ->setMethods( [
-                               'getLagDetectionMethod', 'getHeartbeatData', 'getMasterServerInfo' ] )
-                       ->getMock();
-
-               $db->method( 'getLagDetectionMethod' )
-                       ->willReturn( 'pt-heartbeat' );
-
-               $db->method( 'getMasterServerInfo' )
-                       ->willReturn( [ 'serverId' => 172, 'asOf' => time() ] );
-
-               // Fake the current time.
-               list( $nowSecFrac, $nowSec ) = explode( ' ', microtime() );
-               $now = (float)$nowSec + (float)$nowSecFrac;
-               // Fake the heartbeat time.
-               // Work arounds for weak DataTime microseconds support.
-               $ptTime = $now - $lag;
-               $ptSec = (int)$ptTime;
-               $ptSecFrac = ( $ptTime - $ptSec );
-               $ptDateTime = new DateTime( "@$ptSec" );
-               $ptTimeISO = $ptDateTime->format( 'Y-m-d\TH:i:s' );
-               $ptTimeISO .= ltrim( number_format( $ptSecFrac, 6 ), '0' );
-
-               $db->method( 'getHeartbeatData' )
-                       ->with( [ 'server_id' => 172 ] )
-                       ->willReturn( [ $ptTimeISO, $now ] );
-
-               $db->setLBInfo( 'clusterMasterHost', 'db1052' );
-               $lagEst = $db->getLag();
-
-               $this->assertGreaterThan( $lag - .010, $lagEst, "Correct heatbeat lag" );
-               $this->assertLessThan( $lag + .010, $lagEst, "Correct heatbeat lag" );
-       }
-
-       function provideLagAmounts() {
-               return [
-                       [ 0 ],
-                       [ 0.3 ],
-                       [ 6.5 ],
-                       [ 10.1 ],
-                       [ 200.2 ],
-                       [ 400.7 ],
-                       [ 600.22 ],
-                       [ 1000.77 ],
-               ];
-       }
-}
diff --git a/tests/phpunit/includes/db/DatabaseSQLTest.php b/tests/phpunit/includes/db/DatabaseSQLTest.php
deleted file mode 100644 (file)
index 2b587db..0000000
+++ /dev/null
@@ -1,1075 +0,0 @@
-<?php
-
-use Wikimedia\Rdbms\LikeMatch;
-
-/**
- * Test the abstract database layer
- * This is a non DBMS depending test.
- */
-class DatabaseSQLTest extends MediaWikiTestCase {
-       /** @var DatabaseTestHelper */
-       private $database;
-
-       protected function setUp() {
-               parent::setUp();
-               $this->database = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => true ] );
-       }
-
-       protected function assertLastSql( $sqlText ) {
-               $this->assertEquals(
-                       $sqlText,
-                       $this->database->getLastSqls()
-               );
-       }
-
-       protected function assertLastSqlDb( $sqlText, $db ) {
-               $this->assertEquals( $sqlText, $db->getLastSqls() );
-       }
-
-       /**
-        * @dataProvider provideSelect
-        * @covers Database::select
-        */
-       public function testSelect( $sql, $sqlText ) {
-               $this->database->select(
-                       $sql['tables'],
-                       $sql['fields'],
-                       isset( $sql['conds'] ) ? $sql['conds'] : [],
-                       __METHOD__,
-                       isset( $sql['options'] ) ? $sql['options'] : [],
-                       isset( $sql['join_conds'] ) ? $sql['join_conds'] : []
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideSelect() {
-               return [
-                       [
-                               [
-                                       'tables' => 'table',
-                                       'fields' => [ 'field', 'alias' => 'field2' ],
-                                       'conds' => [ 'alias' => 'text' ],
-                               ],
-                               "SELECT field,field2 AS alias " .
-                                       "FROM table " .
-                                       "WHERE alias = 'text'"
-                       ],
-                       [
-                               [
-                                       'tables' => 'table',
-                                       'fields' => [ 'field', 'alias' => 'field2' ],
-                                       'conds' => [ 'alias' => 'text' ],
-                                       'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
-                               ],
-                               "SELECT field,field2 AS alias " .
-                                       "FROM table " .
-                                       "WHERE alias = 'text' " .
-                                       "ORDER BY field " .
-                                       "LIMIT 1"
-                       ],
-                       [
-                               [
-                                       'tables' => [ 'table', 't2' => 'table2' ],
-                                       'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
-                                       'conds' => [ 'alias' => 'text' ],
-                                       'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
-                                       'join_conds' => [ 't2' => [
-                                               'LEFT JOIN', 'tid = t2.id'
-                                       ] ],
-                               ],
-                               "SELECT tid,field,field2 AS alias,t2.id " .
-                                       "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
-                                       "WHERE alias = 'text' " .
-                                       "ORDER BY field " .
-                                       "LIMIT 1"
-                       ],
-                       [
-                               [
-                                       'tables' => [ 'table', 't2' => 'table2' ],
-                                       'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
-                                       'conds' => [ 'alias' => 'text' ],
-                                       'options' => [ 'LIMIT' => 1, 'GROUP BY' => 'field', 'HAVING' => 'COUNT(*) > 1' ],
-                                       'join_conds' => [ 't2' => [
-                                               'LEFT JOIN', 'tid = t2.id'
-                                       ] ],
-                               ],
-                               "SELECT tid,field,field2 AS alias,t2.id " .
-                                       "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
-                                       "WHERE alias = 'text' " .
-                                       "GROUP BY field HAVING COUNT(*) > 1 " .
-                                       "LIMIT 1"
-                       ],
-                       [
-                               [
-                                       'tables' => [ 'table', 't2' => 'table2' ],
-                                       'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
-                                       'conds' => [ 'alias' => 'text' ],
-                                       'options' => [
-                                               'LIMIT' => 1,
-                                               'GROUP BY' => [ 'field', 'field2' ],
-                                               'HAVING' => [ 'COUNT(*) > 1', 'field' => 1 ]
-                                       ],
-                                       'join_conds' => [ 't2' => [
-                                               'LEFT JOIN', 'tid = t2.id'
-                                       ] ],
-                               ],
-                               "SELECT tid,field,field2 AS alias,t2.id " .
-                                       "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
-                                       "WHERE alias = 'text' " .
-                                       "GROUP BY field,field2 HAVING (COUNT(*) > 1) AND field = '1' " .
-                                       "LIMIT 1"
-                       ],
-                       [
-                               [
-                                       'tables' => [ 'table' ],
-                                       'fields' => [ 'alias' => 'field' ],
-                                       'conds' => [ 'alias' => [ 1, 2, 3, 4 ] ],
-                               ],
-                               "SELECT field AS alias " .
-                                       "FROM table " .
-                                       "WHERE alias IN ('1','2','3','4')"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideUpdate
-        * @covers Database::update
-        */
-       public function testUpdate( $sql, $sqlText ) {
-               $this->database->update(
-                       $sql['table'],
-                       $sql['values'],
-                       $sql['conds'],
-                       __METHOD__,
-                       isset( $sql['options'] ) ? $sql['options'] : []
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideUpdate() {
-               return [
-                       [
-                               [
-                                       'table' => 'table',
-                                       'values' => [ 'field' => 'text', 'field2' => 'text2' ],
-                                       'conds' => [ 'alias' => 'text' ],
-                               ],
-                               "UPDATE table " .
-                                       "SET field = 'text'" .
-                                       ",field2 = 'text2' " .
-                                       "WHERE alias = 'text'"
-                       ],
-                       [
-                               [
-                                       'table' => 'table',
-                                       'values' => [ 'field = other', 'field2' => 'text2' ],
-                                       'conds' => [ 'id' => '1' ],
-                               ],
-                               "UPDATE table " .
-                                       "SET field = other" .
-                                       ",field2 = 'text2' " .
-                                       "WHERE id = '1'"
-                       ],
-                       [
-                               [
-                                       'table' => 'table',
-                                       'values' => [ 'field = other', 'field2' => 'text2' ],
-                                       'conds' => '*',
-                               ],
-                               "UPDATE table " .
-                                       "SET field = other" .
-                                       ",field2 = 'text2'"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideDelete
-        * @covers Database::delete
-        */
-       public function testDelete( $sql, $sqlText ) {
-               $this->database->delete(
-                       $sql['table'],
-                       $sql['conds'],
-                       __METHOD__
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideDelete() {
-               return [
-                       [
-                               [
-                                       'table' => 'table',
-                                       'conds' => [ 'alias' => 'text' ],
-                               ],
-                               "DELETE FROM table " .
-                                       "WHERE alias = 'text'"
-                       ],
-                       [
-                               [
-                                       'table' => 'table',
-                                       'conds' => '*',
-                               ],
-                               "DELETE FROM table"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideUpsert
-        * @covers Database::upsert
-        */
-       public function testUpsert( $sql, $sqlText ) {
-               $this->database->upsert(
-                       $sql['table'],
-                       $sql['rows'],
-                       $sql['uniqueIndexes'],
-                       $sql['set'],
-                       __METHOD__
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideUpsert() {
-               return [
-                       [
-                               [
-                                       'table' => 'upsert_table',
-                                       'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
-                                       'uniqueIndexes' => [ 'field' ],
-                                       'set' => [ 'field' => 'set' ],
-                               ],
-                               "BEGIN; " .
-                                       "UPDATE upsert_table " .
-                                       "SET field = 'set' " .
-                                       "WHERE ((field = 'text')); " .
-                                       "INSERT IGNORE INTO upsert_table " .
-                                       "(field,field2) " .
-                                       "VALUES ('text','text2'); " .
-                                       "COMMIT"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideDeleteJoin
-        * @covers Database::deleteJoin
-        */
-       public function testDeleteJoin( $sql, $sqlText ) {
-               $this->database->deleteJoin(
-                       $sql['delTable'],
-                       $sql['joinTable'],
-                       $sql['delVar'],
-                       $sql['joinVar'],
-                       $sql['conds'],
-                       __METHOD__
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideDeleteJoin() {
-               return [
-                       [
-                               [
-                                       'delTable' => 'table',
-                                       'joinTable' => 'table_join',
-                                       'delVar' => 'field',
-                                       'joinVar' => 'field_join',
-                                       'conds' => [ 'alias' => 'text' ],
-                               ],
-                               "DELETE FROM table " .
-                                       "WHERE field IN (" .
-                                       "SELECT field_join FROM table_join WHERE alias = 'text'" .
-                                       ")"
-                       ],
-                       [
-                               [
-                                       'delTable' => 'table',
-                                       'joinTable' => 'table_join',
-                                       'delVar' => 'field',
-                                       'joinVar' => 'field_join',
-                                       'conds' => '*',
-                               ],
-                               "DELETE FROM table " .
-                                       "WHERE field IN (" .
-                                       "SELECT field_join FROM table_join " .
-                                       ")"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideInsert
-        * @covers Database::insert
-        */
-       public function testInsert( $sql, $sqlText ) {
-               $this->database->insert(
-                       $sql['table'],
-                       $sql['rows'],
-                       __METHOD__,
-                       isset( $sql['options'] ) ? $sql['options'] : []
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideInsert() {
-               return [
-                       [
-                               [
-                                       'table' => 'table',
-                                       'rows' => [ 'field' => 'text', 'field2' => 2 ],
-                               ],
-                               "INSERT INTO table " .
-                                       "(field,field2) " .
-                                       "VALUES ('text','2')"
-                       ],
-                       [
-                               [
-                                       'table' => 'table',
-                                       'rows' => [ 'field' => 'text', 'field2' => 2 ],
-                                       'options' => 'IGNORE',
-                               ],
-                               "INSERT IGNORE INTO table " .
-                                       "(field,field2) " .
-                                       "VALUES ('text','2')"
-                       ],
-                       [
-                               [
-                                       'table' => 'table',
-                                       'rows' => [
-                                               [ 'field' => 'text', 'field2' => 2 ],
-                                               [ 'field' => 'multi', 'field2' => 3 ],
-                                       ],
-                                       'options' => 'IGNORE',
-                               ],
-                               "INSERT IGNORE INTO table " .
-                                       "(field,field2) " .
-                                       "VALUES " .
-                                       "('text','2')," .
-                                       "('multi','3')"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideInsertSelect
-        * @covers Database::insertSelect
-        */
-       public function testInsertSelect( $sql, $sqlTextNative, $sqlSelect, $sqlInsert ) {
-               $this->database->insertSelect(
-                       $sql['destTable'],
-                       $sql['srcTable'],
-                       $sql['varMap'],
-                       $sql['conds'],
-                       __METHOD__,
-                       isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
-                       isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : [],
-                       isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'] : []
-               );
-               $this->assertLastSql( $sqlTextNative );
-
-               $dbWeb = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => false ] );
-               $dbWeb->forceNextResult( [
-                       array_flip( array_keys( $sql['varMap'] ) )
-               ] );
-               $dbWeb->insertSelect(
-                       $sql['destTable'],
-                       $sql['srcTable'],
-                       $sql['varMap'],
-                       $sql['conds'],
-                       __METHOD__,
-                       isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
-                       isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : [],
-                       isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'] : []
-               );
-               $this->assertLastSqlDb( implode( '; ', [ $sqlSelect, $sqlInsert ] ), $dbWeb );
-       }
-
-       public static function provideInsertSelect() {
-               return [
-                       [
-                               [
-                                       'destTable' => 'insert_table',
-                                       'srcTable' => 'select_table',
-                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
-                                       'conds' => '*',
-                               ],
-                               "INSERT INTO insert_table " .
-                                       "(field_insert,field) " .
-                                       "SELECT field_select,field2 " .
-                                       "FROM select_table WHERE *",
-                               "SELECT field_select AS field_insert,field2 AS field " .
-                               "FROM select_table WHERE *   FOR UPDATE",
-                               "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
-                       ],
-                       [
-                               [
-                                       'destTable' => 'insert_table',
-                                       'srcTable' => 'select_table',
-                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
-                                       'conds' => [ 'field' => 2 ],
-                               ],
-                               "INSERT INTO insert_table " .
-                                       "(field_insert,field) " .
-                                       "SELECT field_select,field2 " .
-                                       "FROM select_table " .
-                                       "WHERE field = '2'",
-                               "SELECT field_select AS field_insert,field2 AS field FROM " .
-                               "select_table WHERE field = '2'   FOR UPDATE",
-                               "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
-                       ],
-                       [
-                               [
-                                       'destTable' => 'insert_table',
-                                       'srcTable' => 'select_table',
-                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
-                                       'conds' => [ 'field' => 2 ],
-                                       'insertOptions' => 'IGNORE',
-                                       'selectOptions' => [ 'ORDER BY' => 'field' ],
-                               ],
-                               "INSERT IGNORE INTO insert_table " .
-                                       "(field_insert,field) " .
-                                       "SELECT field_select,field2 " .
-                                       "FROM select_table " .
-                                       "WHERE field = '2' " .
-                                       "ORDER BY field",
-                               "SELECT field_select AS field_insert,field2 AS field " .
-                               "FROM select_table WHERE field = '2' ORDER BY field  FOR UPDATE",
-                               "INSERT IGNORE INTO insert_table (field_insert,field) VALUES ('0','1')"
-                       ],
-                       [
-                               [
-                                       'destTable' => 'insert_table',
-                                       'srcTable' => [ 'select_table1', 'select_table2' ],
-                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
-                                       'conds' => [ 'field' => 2 ],
-                                       'selectOptions' => [ 'ORDER BY' => 'field', 'FORCE INDEX' => [ 'select_table1' => 'index1' ] ],
-                                       'selectJoinConds' => [
-                                               'select_table2' => [ 'LEFT JOIN', [ 'select_table1.foo = select_table2.bar' ] ],
-                                       ],
-                               ],
-                               "INSERT INTO insert_table " .
-                                       "(field_insert,field) " .
-                                       "SELECT field_select,field2 " .
-                                       "FROM select_table1 LEFT JOIN select_table2 ON ((select_table1.foo = select_table2.bar)) " .
-                                       "WHERE field = '2' " .
-                                       "ORDER BY field",
-                               "SELECT field_select AS field_insert,field2 AS field " .
-                               "FROM select_table1 LEFT JOIN select_table2 ON ((select_table1.foo = select_table2.bar)) " .
-                               "WHERE field = '2' ORDER BY field  FOR UPDATE",
-                               "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideReplace
-        * @covers Database::replace
-        */
-       public function testReplace( $sql, $sqlText ) {
-               $this->database->replace(
-                       $sql['table'],
-                       $sql['uniqueIndexes'],
-                       $sql['rows'],
-                       __METHOD__
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideReplace() {
-               return [
-                       [
-                               [
-                                       'table' => 'replace_table',
-                                       'uniqueIndexes' => [ 'field' ],
-                                       'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
-                               ],
-                               "DELETE FROM replace_table " .
-                                       "WHERE ( field='text' ); " .
-                                       "INSERT INTO replace_table " .
-                                       "(field,field2) " .
-                                       "VALUES ('text','text2')"
-                       ],
-                       [
-                               [
-                                       'table' => 'module_deps',
-                                       'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
-                                       'rows' => [
-                                               'md_module' => 'module',
-                                               'md_skin' => 'skin',
-                                               'md_deps' => 'deps',
-                                       ],
-                               ],
-                               "DELETE FROM module_deps " .
-                                       "WHERE ( md_module='module' AND md_skin='skin' ); " .
-                                       "INSERT INTO module_deps " .
-                                       "(md_module,md_skin,md_deps) " .
-                                       "VALUES ('module','skin','deps')"
-                       ],
-                       [
-                               [
-                                       'table' => 'module_deps',
-                                       'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
-                                       'rows' => [
-                                               [
-                                                       'md_module' => 'module',
-                                                       'md_skin' => 'skin',
-                                                       'md_deps' => 'deps',
-                                               ], [
-                                                       'md_module' => 'module2',
-                                                       'md_skin' => 'skin2',
-                                                       'md_deps' => 'deps2',
-                                               ],
-                                       ],
-                               ],
-                               "DELETE FROM module_deps " .
-                                       "WHERE ( md_module='module' AND md_skin='skin' ); " .
-                                       "INSERT INTO module_deps " .
-                                       "(md_module,md_skin,md_deps) " .
-                                       "VALUES ('module','skin','deps'); " .
-                                       "DELETE FROM module_deps " .
-                                       "WHERE ( md_module='module2' AND md_skin='skin2' ); " .
-                                       "INSERT INTO module_deps " .
-                                       "(md_module,md_skin,md_deps) " .
-                                       "VALUES ('module2','skin2','deps2')"
-                       ],
-                       [
-                               [
-                                       'table' => 'module_deps',
-                                       'uniqueIndexes' => [ 'md_module', 'md_skin' ],
-                                       'rows' => [
-                                               [
-                                                       'md_module' => 'module',
-                                                       'md_skin' => 'skin',
-                                                       'md_deps' => 'deps',
-                                               ], [
-                                                       'md_module' => 'module2',
-                                                       'md_skin' => 'skin2',
-                                                       'md_deps' => 'deps2',
-                                               ],
-                                       ],
-                               ],
-                               "DELETE FROM module_deps " .
-                                       "WHERE ( md_module='module' ) OR ( md_skin='skin' ); " .
-                                       "INSERT INTO module_deps " .
-                                       "(md_module,md_skin,md_deps) " .
-                                       "VALUES ('module','skin','deps'); " .
-                                       "DELETE FROM module_deps " .
-                                       "WHERE ( md_module='module2' ) OR ( md_skin='skin2' ); " .
-                                       "INSERT INTO module_deps " .
-                                       "(md_module,md_skin,md_deps) " .
-                                       "VALUES ('module2','skin2','deps2')"
-                       ],
-                       [
-                               [
-                                       'table' => 'module_deps',
-                                       'uniqueIndexes' => [],
-                                       'rows' => [
-                                               'md_module' => 'module',
-                                               'md_skin' => 'skin',
-                                               'md_deps' => 'deps',
-                                       ],
-                               ],
-                               "INSERT INTO module_deps " .
-                                       "(md_module,md_skin,md_deps) " .
-                                       "VALUES ('module','skin','deps')"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideNativeReplace
-        * @covers Database::nativeReplace
-        */
-       public function testNativeReplace( $sql, $sqlText ) {
-               $this->database->nativeReplace(
-                       $sql['table'],
-                       $sql['rows'],
-                       __METHOD__
-               );
-               $this->assertLastSql( $sqlText );
-       }
-
-       public static function provideNativeReplace() {
-               return [
-                       [
-                               [
-                                       'table' => 'replace_table',
-                                       'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
-                               ],
-                               "REPLACE INTO replace_table " .
-                                       "(field,field2) " .
-                                       "VALUES ('text','text2')"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideConditional
-        * @covers Database::conditional
-        */
-       public function testConditional( $sql, $sqlText ) {
-               $this->assertEquals( trim( $this->database->conditional(
-                       $sql['conds'],
-                       $sql['true'],
-                       $sql['false']
-               ) ), $sqlText );
-       }
-
-       public static function provideConditional() {
-               return [
-                       [
-                               [
-                                       'conds' => [ 'field' => 'text' ],
-                                       'true' => 1,
-                                       'false' => 'NULL',
-                               ],
-                               "(CASE WHEN field = 'text' THEN 1 ELSE NULL END)"
-                       ],
-                       [
-                               [
-                                       'conds' => [ 'field' => 'text', 'field2' => 'anothertext' ],
-                                       'true' => 1,
-                                       'false' => 'NULL',
-                               ],
-                               "(CASE WHEN field = 'text' AND field2 = 'anothertext' THEN 1 ELSE NULL END)"
-                       ],
-                       [
-                               [
-                                       'conds' => 'field=1',
-                                       'true' => 1,
-                                       'false' => 'NULL',
-                               ],
-                               "(CASE WHEN field=1 THEN 1 ELSE NULL END)"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideBuildConcat
-        * @covers Database::buildConcat
-        */
-       public function testBuildConcat( $stringList, $sqlText ) {
-               $this->assertEquals( trim( $this->database->buildConcat(
-                       $stringList
-               ) ), $sqlText );
-       }
-
-       public static function provideBuildConcat() {
-               return [
-                       [
-                               [ 'field', 'field2' ],
-                               "CONCAT(field,field2)"
-                       ],
-                       [
-                               [ "'test'", 'field2' ],
-                               "CONCAT('test',field2)"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideBuildLike
-        * @covers Database::buildLike
-        */
-       public function testBuildLike( $array, $sqlText ) {
-               $this->assertEquals( trim( $this->database->buildLike(
-                       $array
-               ) ), $sqlText );
-       }
-
-       public static function provideBuildLike() {
-               return [
-                       [
-                               'text',
-                               "LIKE 'text' ESCAPE '`'"
-                       ],
-                       [
-                               [ 'text', new LikeMatch( '%' ) ],
-                               "LIKE 'text%' ESCAPE '`'"
-                       ],
-                       [
-                               [ 'text', new LikeMatch( '%' ), 'text2' ],
-                               "LIKE 'text%text2' ESCAPE '`'"
-                       ],
-                       [
-                               [ 'text', new LikeMatch( '_' ) ],
-                               "LIKE 'text_' ESCAPE '`'"
-                       ],
-                       [
-                               'more_text',
-                               "LIKE 'more`_text' ESCAPE '`'"
-                       ],
-                       [
-                               [ 'C:\\Windows\\', new LikeMatch( '%' ) ],
-                               "LIKE 'C:\\Windows\\%' ESCAPE '`'"
-                       ],
-                       [
-                               [ 'accent`_test`', new LikeMatch( '%' ) ],
-                               "LIKE 'accent```_test``%' ESCAPE '`'"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideUnionQueries
-        * @covers Database::unionQueries
-        */
-       public function testUnionQueries( $sql, $sqlText ) {
-               $this->assertEquals( trim( $this->database->unionQueries(
-                       $sql['sqls'],
-                       $sql['all']
-               ) ), $sqlText );
-       }
-
-       public static function provideUnionQueries() {
-               return [
-                       [
-                               [
-                                       'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
-                                       'all' => true,
-                               ],
-                               "(RAW SQL) UNION ALL (RAW2SQL)"
-                       ],
-                       [
-                               [
-                                       'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
-                                       'all' => false,
-                               ],
-                               "(RAW SQL) UNION (RAW2SQL)"
-                       ],
-                       [
-                               [
-                                       'sqls' => [ 'RAW SQL', 'RAW2SQL', 'RAW3SQL' ],
-                                       'all' => false,
-                               ],
-                               "(RAW SQL) UNION (RAW2SQL) UNION (RAW3SQL)"
-                       ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideUnionConditionPermutations
-        * @covers Database::unionConditionPermutations
-        */
-       public function testUnionConditionPermutations( $params, $expect ) {
-               if ( isset( $params['unionSupportsOrderAndLimit'] ) ) {
-                       $this->database->setUnionSupportsOrderAndLimit( $params['unionSupportsOrderAndLimit'] );
-               }
-
-               $sql = trim( $this->database->unionConditionPermutations(
-                       $params['table'],
-                       $params['vars'],
-                       $params['permute_conds'],
-                       isset( $params['extra_conds'] ) ? $params['extra_conds'] : '',
-                       'FNAME',
-                       isset( $params['options'] ) ? $params['options'] : [],
-                       isset( $params['join_conds'] ) ? $params['join_conds'] : []
-               ) );
-               $this->assertEquals( $expect, $sql );
-       }
-
-       public static function provideUnionConditionPermutations() {
-               return [
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
-                       [
-                               [
-                                       'table' => [ 'table1', 'table2' ],
-                                       'vars' => [ 'field1', 'alias' => 'field2' ],
-                                       'permute_conds' => [
-                                               'field3' => [ 1, 2, 3 ],
-                                               'duplicates' => [ 4, 5, 4 ],
-                                               'empty' => [],
-                                               'single' => [ 0 ],
-                                       ],
-                                       'extra_conds' => 'table2.bar > 23',
-                                       'options' => [
-                                               'ORDER BY' => [ 'field1', 'alias' ],
-                                               'INNER ORDER BY' => [ 'field1', 'field2' ],
-                                               'LIMIT' => 100,
-                                       ],
-                                       'join_conds' => [
-                                               'table2' => [ 'JOIN', 'table1.foo_id = table2.foo_id' ],
-                                       ],
-                               ],
-                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '1' AND duplicates = '4' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
-                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '1' AND duplicates = '5' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
-                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '2' AND duplicates = '4' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
-                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '2' AND duplicates = '5' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
-                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '3' AND duplicates = '4' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
-                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '3' AND duplicates = '5' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) " .
-                               "ORDER BY field1,alias LIMIT 100"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [
-                                               'bar' => [ 1, 2, 3 ],
-                                       ],
-                                       'extra_conds' => [ 'baz' => null ],
-                                       'options' => [
-                                               'NOTALL',
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                       ],
-                               ],
-                               "(SELECT  foo_id  FROM foo    WHERE bar = '1' AND baz IS NULL  ORDER BY foo_id LIMIT 25  ) UNION " .
-                               "(SELECT  foo_id  FROM foo    WHERE bar = '2' AND baz IS NULL  ORDER BY foo_id LIMIT 25  ) UNION " .
-                               "(SELECT  foo_id  FROM foo    WHERE bar = '3' AND baz IS NULL  ORDER BY foo_id LIMIT 25  ) " .
-                               "ORDER BY foo_id LIMIT 25"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [
-                                               'bar' => [ 1, 2, 3 ],
-                                       ],
-                                       'extra_conds' => [ 'baz' => null ],
-                                       'options' => [
-                                               'NOTALL' => true,
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                       ],
-                                       'unionSupportsOrderAndLimit' => false,
-                               ],
-                               "(SELECT  foo_id  FROM foo    WHERE bar = '1' AND baz IS NULL  ) UNION " .
-                               "(SELECT  foo_id  FROM foo    WHERE bar = '2' AND baz IS NULL  ) UNION " .
-                               "(SELECT  foo_id  FROM foo    WHERE bar = '3' AND baz IS NULL  ) " .
-                               "ORDER BY foo_id LIMIT 25"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [],
-                                       'extra_conds' => [ 'baz' => null ],
-                                       'options' => [
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                       ],
-                               ],
-                               "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 25"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [
-                                               'bar' => [],
-                                       ],
-                                       'extra_conds' => [ 'baz' => null ],
-                                       'options' => [
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                       ],
-                               ],
-                               "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 25"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [
-                                               'bar' => [ 1 ],
-                                       ],
-                                       'options' => [
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                               'OFFSET' => 150,
-                                       ],
-                               ],
-                               "SELECT  foo_id  FROM foo    WHERE bar = '1'  ORDER BY foo_id LIMIT 150,25"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [],
-                                       'extra_conds' => [ 'baz' => null ],
-                                       'options' => [
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                               'OFFSET' => 150,
-                                               'INNER ORDER BY' => [ 'bar_id' ],
-                                       ],
-                               ],
-                               "(SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY bar_id LIMIT 175  ) ORDER BY foo_id LIMIT 150,25"
-                       ],
-                       [
-                               [
-                                       'table' => 'foo',
-                                       'vars' => [ 'foo_id' ],
-                                       'permute_conds' => [],
-                                       'extra_conds' => [ 'baz' => null ],
-                                       'options' => [
-                                               'ORDER BY' => [ 'foo_id' ],
-                                               'LIMIT' => 25,
-                                               'OFFSET' => 150,
-                                               'INNER ORDER BY' => [ 'bar_id' ],
-                                       ],
-                                       'unionSupportsOrderAndLimit' => false,
-                               ],
-                               "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 150,25"
-                       ],
-                       // @codingStandardsIgnoreEnd
-               ];
-       }
-
-       /**
-        * @covers Database::commit
-        */
-       public function testTransactionCommit() {
-               $this->database->begin( __METHOD__ );
-               $this->database->commit( __METHOD__ );
-               $this->assertLastSql( 'BEGIN; COMMIT' );
-       }
-
-       /**
-        * @covers Database::rollback
-        */
-       public function testTransactionRollback() {
-               $this->database->begin( __METHOD__ );
-               $this->database->rollback( __METHOD__ );
-               $this->assertLastSql( 'BEGIN; ROLLBACK' );
-       }
-
-       /**
-        * @covers Database::dropTable
-        */
-       public function testDropTable() {
-               $this->database->setExistingTables( [ 'table' ] );
-               $this->database->dropTable( 'table', __METHOD__ );
-               $this->assertLastSql( 'DROP TABLE table CASCADE' );
-       }
-
-       /**
-        * @covers Database::dropTable
-        */
-       public function testDropNonExistingTable() {
-               $this->assertFalse(
-                       $this->database->dropTable( 'non_existing', __METHOD__ )
-               );
-       }
-
-       /**
-        * @dataProvider provideMakeList
-        * @covers Database::makeList
-        */
-       public function testMakeList( $list, $mode, $sqlText ) {
-               $this->assertEquals( trim( $this->database->makeList(
-                       $list, $mode
-               ) ), $sqlText );
-       }
-
-       public static function provideMakeList() {
-               return [
-                       [
-                               [ 'value', 'value2' ],
-                               LIST_COMMA,
-                               "'value','value2'"
-                       ],
-                       [
-                               [ 'field', 'field2' ],
-                               LIST_NAMES,
-                               "field,field2"
-                       ],
-                       [
-                               [ 'field' => 'value', 'field2' => 'value2' ],
-                               LIST_AND,
-                               "field = 'value' AND field2 = 'value2'"
-                       ],
-                       [
-                               [ 'field' => null, "field2 != 'value2'" ],
-                               LIST_AND,
-                               "field IS NULL AND (field2 != 'value2')"
-                       ],
-                       [
-                               [ 'field' => [ 'value', null, 'value2' ], 'field2' => 'value2' ],
-                               LIST_AND,
-                               "(field IN ('value','value2')  OR field IS NULL) AND field2 = 'value2'"
-                       ],
-                       [
-                               [ 'field' => [ null ], 'field2' => null ],
-                               LIST_AND,
-                               "field IS NULL AND field2 IS NULL"
-                       ],
-                       [
-                               [ 'field' => 'value', 'field2' => 'value2' ],
-                               LIST_OR,
-                               "field = 'value' OR field2 = 'value2'"
-                       ],
-                       [
-                               [ 'field' => 'value', 'field2' => null ],
-                               LIST_OR,
-                               "field = 'value' OR field2 IS NULL"
-                       ],
-                       [
-                               [ 'field' => [ 'value', 'value2' ], 'field2' => [ 'value' ] ],
-                               LIST_OR,
-                               "field IN ('value','value2')  OR field2 = 'value'"
-                       ],
-                       [
-                               [ 'field' => [ null, 'value', null, 'value2' ], "field2 != 'value2'" ],
-                               LIST_OR,
-                               "(field IN ('value','value2')  OR field IS NULL) OR (field2 != 'value2')"
-                       ],
-                       [
-                               [ 'field' => 'value', 'field2' => 'value2' ],
-                               LIST_SET,
-                               "field = 'value',field2 = 'value2'"
-                       ],
-                       [
-                               [ 'field' => 'value', 'field2' => null ],
-                               LIST_SET,
-                               "field = 'value',field2 = NULL"
-                       ],
-                       [
-                               [ 'field' => 'value', "field2 != 'value2'" ],
-                               LIST_SET,
-                               "field = 'value',field2 != 'value2'"
-                       ],
-               ];
-       }
-
-       public function testSessionTempTables() {
-               $temp1 = $this->database->tableName( 'tmp_table_1' );
-               $temp2 = $this->database->tableName( 'tmp_table_2' );
-               $temp3 = $this->database->tableName( 'tmp_table_3' );
-
-               $this->database->query( "CREATE TEMPORARY TABLE $temp1 LIKE orig_tbl", __METHOD__ );
-               $this->database->query( "CREATE TEMPORARY TABLE $temp2 LIKE orig_tbl", __METHOD__ );
-               $this->database->query( "CREATE TEMPORARY TABLE $temp3 LIKE orig_tbl", __METHOD__ );
-
-               $this->assertTrue( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
-               $this->assertTrue( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
-               $this->assertTrue( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
-
-               $this->database->dropTable( 'tmp_table_1', __METHOD__ );
-               $this->database->dropTable( 'tmp_table_2', __METHOD__ );
-               $this->database->dropTable( 'tmp_table_3', __METHOD__ );
-
-               $this->assertFalse( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
-               $this->assertFalse( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
-               $this->assertFalse( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
-
-               $this->database->query( "CREATE TEMPORARY TABLE tmp_table_1 LIKE orig_tbl", __METHOD__ );
-               $this->database->query( "CREATE TEMPORARY TABLE 'tmp_table_2' LIKE orig_tbl", __METHOD__ );
-               $this->database->query( "CREATE TEMPORARY TABLE `tmp_table_3` LIKE orig_tbl", __METHOD__ );
-
-               $this->assertTrue( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
-               $this->assertTrue( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
-               $this->assertTrue( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
-
-               $this->database->query( "DROP TEMPORARY TABLE tmp_table_1 LIKE orig_tbl", __METHOD__ );
-               $this->database->query( "DROP TEMPORARY TABLE 'tmp_table_2' LIKE orig_tbl", __METHOD__ );
-               $this->database->query( "DROP TABLE `tmp_table_3` LIKE orig_tbl", __METHOD__ );
-
-               $this->assertFalse( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
-               $this->assertFalse( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
-               $this->assertFalse( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
-       }
-}
index b90b1ad..ae61070 100644 (file)
@@ -87,6 +87,10 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
                                new Blob( "hello" ),
                                "x'68656c6c6f'",
                        ],
+                       [ // #5: null
+                               null,
+                               "''",
+                       ],
                ];
        }
 
diff --git a/tests/phpunit/includes/db/DatabaseTest.php b/tests/phpunit/includes/db/DatabaseTest.php
deleted file mode 100644 (file)
index 45791e2..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-<?php
-
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * @group Database
- * @group Database
- */
-class DatabaseTest extends MediaWikiTestCase {
-       /**
-        * @var Database
-        */
-       protected $db;
-
-       private $functionTest = false;
-
-       protected function setUp() {
-               parent::setUp();
-               $this->db = wfGetDB( DB_MASTER );
-       }
-
-       protected function tearDown() {
-               parent::tearDown();
-               if ( $this->functionTest ) {
-                       $this->dropFunctions();
-                       $this->functionTest = false;
-               }
-               $this->db->restoreFlags( IDatabase::RESTORE_INITIAL );
-       }
-
-       /**
-        * @covers Database::dropTable
-        */
-       public function testAddQuotesNull() {
-               $check = "NULL";
-               if ( $this->db->getType() === 'sqlite' || $this->db->getType() === 'oracle' ) {
-                       $check = "''";
-               }
-               $this->assertEquals( $check, $this->db->addQuotes( null ) );
-       }
-
-       public function testAddQuotesInt() {
-               # returning just "1234" should be ok too, though...
-               # maybe
-               $this->assertEquals(
-                       "'1234'",
-                       $this->db->addQuotes( 1234 ) );
-       }
-
-       public function testAddQuotesFloat() {
-               # returning just "1234.5678" would be ok too, though
-               $this->assertEquals(
-                       "'1234.5678'",
-                       $this->db->addQuotes( 1234.5678 ) );
-       }
-
-       public function testAddQuotesString() {
-               $this->assertEquals(
-                       "'string'",
-                       $this->db->addQuotes( 'string' ) );
-       }
-
-       public function testAddQuotesStringQuote() {
-               $check = "'string''s cause trouble'";
-               if ( $this->db->getType() === 'mysql' ) {
-                       $check = "'string\'s cause trouble'";
-               }
-               $this->assertEquals(
-                       $check,
-                       $this->db->addQuotes( "string's cause trouble" ) );
-       }
-
-       private function getSharedTableName( $table, $database, $prefix, $format = 'quoted' ) {
-               global $wgSharedDB, $wgSharedTables, $wgSharedPrefix, $wgSharedSchema;
-
-               $this->db->setTableAliases( [
-                       $table => [
-                               'dbname' => $database,
-                               'schema' => null,
-                               'prefix' => $prefix
-                       ]
-               ] );
-
-               $ret = $this->db->tableName( $table, $format );
-
-               $this->db->setTableAliases( array_fill_keys(
-                       $wgSharedDB ? $wgSharedTables : [],
-                       [
-                               'dbname' => $wgSharedDB,
-                               'schema' => $wgSharedSchema,
-                               'prefix' => $wgSharedPrefix
-                       ]
-               ) );
-
-               return $ret;
-       }
-
-       private function prefixAndQuote( $table, $database = null, $prefix = null, $format = 'quoted' ) {
-               if ( $this->db->getType() === 'sqlite' || $format !== 'quoted' ) {
-                       $quote = '';
-               } elseif ( $this->db->getType() === 'mysql' ) {
-                       $quote = '`';
-               } elseif ( $this->db->getType() === 'oracle' ) {
-                       $quote = '/*Q*/';
-               } else {
-                       $quote = '"';
-               }
-
-               if ( $database !== null ) {
-                       if ( $this->db->getType() === 'oracle' ) {
-                               $database = $quote . $database . '.';
-                       } else {
-                               $database = $quote . $database . $quote . '.';
-                       }
-               }
-
-               if ( $prefix === null ) {
-                       $prefix = $this->dbPrefix();
-               }
-
-               if ( $this->db->getType() === 'oracle' ) {
-                       return strtoupper( $database . $quote . $prefix . $table );
-               } else {
-                       return $database . $quote . $prefix . $table . $quote;
-               }
-       }
-
-       public function testTableNameLocal() {
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename' ),
-                       $this->db->tableName( 'tablename' )
-               );
-       }
-
-       public function testTableNameRawLocal() {
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', null, null, 'raw' ),
-                       $this->db->tableName( 'tablename', 'raw' )
-               );
-       }
-
-       public function testTableNameShared() {
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', 'sharedatabase', 'sh_' ),
-                       $this->getSharedTableName( 'tablename', 'sharedatabase', 'sh_' )
-               );
-
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', 'sharedatabase', null ),
-                       $this->getSharedTableName( 'tablename', 'sharedatabase', null )
-               );
-       }
-
-       public function testTableNameRawShared() {
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', 'sharedatabase', 'sh_', 'raw' ),
-                       $this->getSharedTableName( 'tablename', 'sharedatabase', 'sh_', 'raw' )
-               );
-
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', 'sharedatabase', null, 'raw' ),
-                       $this->getSharedTableName( 'tablename', 'sharedatabase', null, 'raw' )
-               );
-       }
-
-       public function testTableNameForeign() {
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', 'databasename', '' ),
-                       $this->db->tableName( 'databasename.tablename' )
-               );
-       }
-
-       public function testTableNameRawForeign() {
-               $this->assertEquals(
-                       $this->prefixAndQuote( 'tablename', 'databasename', '', 'raw' ),
-                       $this->db->tableName( 'databasename.tablename', 'raw' )
-               );
-       }
-
-       public function testStoredFunctions() {
-               if ( !in_array( wfGetDB( DB_MASTER )->getType(), [ 'mysql', 'postgres' ] ) ) {
-                       $this->markTestSkipped( 'MySQL or Postgres required' );
-               }
-               global $IP;
-               $this->dropFunctions();
-               $this->functionTest = true;
-               $this->assertTrue(
-                       $this->db->sourceFile( "$IP/tests/phpunit/data/db/{$this->db->getType()}/functions.sql" )
-               );
-               $res = $this->db->query( 'SELECT mw_test_function() AS test', __METHOD__ );
-               $this->assertEquals( 42, $res->fetchObject()->test );
-       }
-
-       private function dropFunctions() {
-               $this->db->query( 'DROP FUNCTION IF EXISTS mw_test_function'
-                       . ( $this->db->getType() == 'postgres' ? '()' : '' )
-               );
-       }
-
-       public function testUnknownTableCorruptsResults() {
-               $res = $this->db->select( 'page', '*', [ 'page_id' => 1 ] );
-               $this->assertFalse( $this->db->tableExists( 'foobarbaz' ) );
-               $this->assertInternalType( 'int', $res->numRows() );
-       }
-
-       public function testTransactionIdle() {
-               $db = $this->db;
-
-               $db->setFlag( DBO_TRX );
-               $called = false;
-               $flagSet = null;
-               $db->onTransactionIdle(
-                       function () use ( $db, &$flagSet, &$called ) {
-                               $called = true;
-                               $flagSet = $db->getFlag( DBO_TRX );
-                       },
-                       __METHOD__
-               );
-               $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
-               $this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
-               $this->assertTrue( $called, 'Callback reached' );
-
-               $db->clearFlag( DBO_TRX );
-               $flagSet = null;
-               $db->onTransactionIdle(
-                       function () use ( $db, &$flagSet ) {
-                               $flagSet = $db->getFlag( DBO_TRX );
-                       },
-                       __METHOD__
-               );
-               $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
-               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
-
-               $db->clearFlag( DBO_TRX );
-               $db->onTransactionIdle(
-                       function () use ( $db ) {
-                               $db->setFlag( DBO_TRX );
-                       },
-                       __METHOD__
-               );
-               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
-       }
-
-       public function testTransactionResolution() {
-               $db = $this->db;
-
-               $db->clearFlag( DBO_TRX );
-               $db->begin( __METHOD__ );
-               $called = false;
-               $db->onTransactionResolution( function () use ( $db, &$called ) {
-                       $called = true;
-                       $db->setFlag( DBO_TRX );
-               } );
-               $db->commit( __METHOD__ );
-               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
-               $this->assertTrue( $called, 'Callback reached' );
-
-               $db->clearFlag( DBO_TRX );
-               $db->begin( __METHOD__ );
-               $called = false;
-               $db->onTransactionResolution( function () use ( $db, &$called ) {
-                       $called = true;
-                       $db->setFlag( DBO_TRX );
-               } );
-               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
-               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
-               $this->assertTrue( $called, 'Callback reached' );
-       }
-
-       /**
-        * @covers Database::setTransactionListener()
-        */
-       public function testTransactionListener() {
-               $db = $this->db;
-
-               $db->setTransactionListener( 'ping', function () use ( $db, &$called ) {
-                       $called = true;
-               } );
-
-               $called = false;
-               $db->begin( __METHOD__ );
-               $db->commit( __METHOD__ );
-               $this->assertTrue( $called, 'Callback reached' );
-
-               $called = false;
-               $db->begin( __METHOD__ );
-               $db->commit( __METHOD__ );
-               $this->assertTrue( $called, 'Callback still reached' );
-
-               $called = false;
-               $db->begin( __METHOD__ );
-               $db->rollback( __METHOD__ );
-               $this->assertTrue( $called, 'Callback reached' );
-
-               $db->setTransactionListener( 'ping', null );
-               $called = false;
-               $db->begin( __METHOD__ );
-               $db->commit( __METHOD__ );
-               $this->assertFalse( $called, 'Callback not reached' );
-       }
-
-       /**
-        * @covers Database::flushSnapshot()
-        */
-       public function testFlushSnapshot() {
-               $db = $this->db;
-
-               $db->flushSnapshot( __METHOD__ ); // ok
-               $db->flushSnapshot( __METHOD__ ); // ok
-
-               $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
-               $db->query( 'SELECT 1', __METHOD__ );
-               $this->assertTrue( (bool)$db->trxLevel(), "Transaction started." );
-               $db->flushSnapshot( __METHOD__ ); // ok
-               $db->restoreFlags( $db::RESTORE_PRIOR );
-
-               $this->assertFalse( (bool)$db->trxLevel(), "Transaction cleared." );
-       }
-
-       public function testGetScopedLock() {
-               $db = $this->db;
-
-               $db->setFlag( DBO_TRX );
-               try {
-                       $this->badLockingMethodImplicit( $db );
-               } catch ( RunTimeException $e ) {
-                       $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
-               }
-               $db->clearFlag( DBO_TRX );
-               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
-               $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
-
-               try {
-                       $this->badLockingMethodExplicit( $db );
-               } catch ( RunTimeException $e ) {
-                       $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
-               }
-               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
-               $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
-       }
-
-       private function badLockingMethodImplicit( IDatabase $db ) {
-               $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
-               $db->query( "SELECT 1" ); // trigger DBO_TRX
-               throw new RunTimeException( "Uh oh!" );
-       }
-
-       private function badLockingMethodExplicit( IDatabase $db ) {
-               $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
-               $db->begin( __METHOD__ );
-               throw new RunTimeException( "Uh oh!" );
-       }
-
-       /**
-        * @covers Database::getFlag(
-        * @covers Database::setFlag()
-        * @covers Database::restoreFlags()
-        */
-       public function testFlagSetting() {
-               $db = $this->db;
-               $origTrx = $db->getFlag( DBO_TRX );
-               $origSsl = $db->getFlag( DBO_SSL );
-
-               $origTrx
-                       ? $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR )
-                       : $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
-               $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
-
-               $origSsl
-                       ? $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR )
-                       : $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
-               $this->assertEquals( !$origSsl, $db->getFlag( DBO_SSL ) );
-
-               $db->restoreFlags( $db::RESTORE_INITIAL );
-               $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
-               $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
-
-               $origTrx
-                       ? $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR )
-                       : $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
-               $origSsl
-                       ? $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR )
-                       : $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
-
-               $db->restoreFlags();
-               $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
-               $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
-
-               $db->restoreFlags();
-               $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
-               $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
-       }
-
-       /**
-        * @covers Database::tablePrefix()
-        * @covers Database::dbSchema()
-        */
-       public function testMutators() {
-               $old = $this->db->tablePrefix();
-               $this->assertType( 'string', $old, 'Prefix is string' );
-               $this->assertEquals( $old, $this->db->tablePrefix(), "Prefix unchanged" );
-               $this->assertEquals( $old, $this->db->tablePrefix( 'xxx' ) );
-               $this->assertEquals( 'xxx', $this->db->tablePrefix(), "Prefix set" );
-               $this->db->tablePrefix( $old );
-               $this->assertNotEquals( 'xxx', $this->db->tablePrefix() );
-
-               $old = $this->db->dbSchema();
-               $this->assertType( 'string', $old, 'Schema is string' );
-               $this->assertEquals( $old, $this->db->dbSchema(), "Schema unchanged" );
-               $this->assertEquals( $old, $this->db->dbSchema( 'xxx' ) );
-               $this->assertEquals( 'xxx', $this->db->dbSchema(), "Schema set" );
-               $this->db->dbSchema( $old );
-               $this->assertNotEquals( 'xxx', $this->db->dbSchema() );
-       }
-}
diff --git a/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php
new file mode 100644 (file)
index 0000000..b564310
--- /dev/null
@@ -0,0 +1,371 @@
+<?php
+/**
+ * Holds tests for DatabaseMysqlBase class.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Antoine Musso
+ * @copyright © 2013 Antoine Musso
+ * @copyright © 2013 Wikimedia Foundation and contributors
+ */
+
+use Wikimedia\Rdbms\TransactionProfiler;
+use Wikimedia\Rdbms\DatabaseDomain;
+use Wikimedia\Rdbms\MySQLMasterPos;
+use Wikimedia\Rdbms\DatabaseMysqlBase;
+
+/**
+ * Fake class around abstract class so we can call concrete methods.
+ */
+class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
+       // From Database
+       function __construct() {
+               $this->profiler = new ProfilerStub( [] );
+               $this->trxProfiler = new TransactionProfiler();
+               $this->cliMode = true;
+               $this->connLogger = new \Psr\Log\NullLogger();
+               $this->queryLogger = new \Psr\Log\NullLogger();
+               $this->errorLogger = function ( Exception $e ) {
+                       wfWarn( get_class( $e ) . ": {$e->getMessage()}" );
+               };
+               $this->currentDomain = DatabaseDomain::newUnspecified();
+       }
+
+       protected function closeConnection() {
+       }
+
+       protected function doQuery( $sql ) {
+       }
+
+       // From DatabaseMysql
+       protected function mysqlConnect( $realServer ) {
+       }
+
+       protected function mysqlSetCharset( $charset ) {
+       }
+
+       protected function mysqlFreeResult( $res ) {
+       }
+
+       protected function mysqlFetchObject( $res ) {
+       }
+
+       protected function mysqlFetchArray( $res ) {
+       }
+
+       protected function mysqlNumRows( $res ) {
+       }
+
+       protected function mysqlNumFields( $res ) {
+       }
+
+       protected function mysqlFieldName( $res, $n ) {
+       }
+
+       protected function mysqlFieldType( $res, $n ) {
+       }
+
+       protected function mysqlDataSeek( $res, $row ) {
+       }
+
+       protected function mysqlError( $conn = null ) {
+       }
+
+       protected function mysqlFetchField( $res, $n ) {
+       }
+
+       protected function mysqlRealEscapeString( $s ) {
+       }
+
+       function insertId() {
+       }
+
+       function lastErrno() {
+       }
+
+       function affectedRows() {
+       }
+
+       function getServerVersion() {
+       }
+}
+
+class DatabaseMysqlBaseTest extends PHPUnit_Framework_TestCase {
+       /**
+        * @dataProvider provideDiapers
+        * @covers Wikimedia\Rdbms\DatabaseMysqlBase::addIdentifierQuotes
+        */
+       public function testAddIdentifierQuotes( $expected, $in ) {
+               $db = new FakeDatabaseMysqlBase();
+               $quoted = $db->addIdentifierQuotes( $in );
+               $this->assertEquals( $expected, $quoted );
+       }
+
+       /**
+        * Feeds testAddIdentifierQuotes
+        *
+        * Named per T22281 convention.
+        */
+       public static function provideDiapers() {
+               return [
+                       // Format: expected, input
+                       [ '``', '' ],
+
+                       // Yeah I really hate loosely typed PHP idiocies nowadays
+                       [ '``', null ],
+
+                       // Dear codereviewer, guess what addIdentifierQuotes()
+                       // will return with thoses:
+                       [ '``', false ],
+                       [ '`1`', true ],
+
+                       // We never know what could happen
+                       [ '`0`', 0 ],
+                       [ '`1`', 1 ],
+
+                       // Whatchout! Should probably use something more meaningful
+                       [ "`'`", "'" ],  # single quote
+                       [ '`"`', '"' ],  # double quote
+                       [ '````', '`' ], # backtick
+                       [ '`’`', '’' ],  # apostrophe (look at your encyclopedia)
+
+                       // sneaky NUL bytes are lurking everywhere
+                       [ '``', "\0" ],
+                       [ '`xyzzy`', "\0x\0y\0z\0z\0y\0" ],
+
+                       // unicode chars
+                       [
+                               self::createUnicodeString( '`\u0001a\uFFFFb`' ),
+                               self::createUnicodeString( '\u0001a\uFFFFb' )
+                       ],
+                       [
+                               self::createUnicodeString( '`\u0001\uFFFF`' ),
+                               self::createUnicodeString( '\u0001\u0000\uFFFF\u0000' )
+                       ],
+                       [ '`☃`', '☃' ],
+                       [ '`メインページ`', 'メインページ' ],
+                       [ '`Басты_бет`', 'Басты_бет' ],
+
+                       // Real world:
+                       [ '`Alix`', 'Alix' ],  # while( ! $recovered ) { sleep(); }
+                       [ '`Backtick: ```', 'Backtick: `' ],
+                       [ '`This is a test`', 'This is a test' ],
+               ];
+       }
+
+       private static function createUnicodeString( $str ) {
+               return json_decode( '"' . $str . '"' );
+       }
+
+       private function getMockForViews() {
+               $db = $this->getMockBuilder( 'DatabaseMysqli' )
+                       ->disableOriginalConstructor()
+                       ->setMethods( [ 'fetchRow', 'query' ] )
+                       ->getMock();
+
+               $db->method( 'query' )
+                       ->with( $this->anything() )
+                       ->willReturn( new FakeResultWrapper( [
+                               (object)[ 'Tables_in_' => 'view1' ],
+                               (object)[ 'Tables_in_' => 'view2' ],
+                               (object)[ 'Tables_in_' => 'myview' ]
+                       ] ) );
+
+               return $db;
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\DatabaseMysqlBase::listViews
+        */
+       public function testListviews() {
+               $db = $this->getMockForViews();
+
+               $this->assertEquals( [ 'view1', 'view2', 'myview' ],
+                       $db->listViews() );
+
+               // Prefix filtering
+               $this->assertEquals( [ 'view1', 'view2' ],
+                       $db->listViews( 'view' ) );
+               $this->assertEquals( [ 'myview' ],
+                       $db->listViews( 'my' ) );
+               $this->assertEquals( [],
+                       $db->listViews( 'UNUSED_PREFIX' ) );
+               $this->assertEquals( [ 'view1', 'view2', 'myview' ],
+                       $db->listViews( '' ) );
+       }
+
+       /**
+        * @dataProvider provideComparePositions
+        * @covers Wikimedia\Rdbms\MySQLMasterPos
+        */
+       public function testHasReached( MySQLMasterPos $lowerPos, MySQLMasterPos $higherPos, $match ) {
+               if ( $match ) {
+                       $this->assertTrue( $lowerPos->channelsMatch( $higherPos ) );
+
+                       $this->assertTrue( $higherPos->hasReached( $lowerPos ) );
+                       $this->assertTrue( $higherPos->hasReached( $higherPos ) );
+                       $this->assertTrue( $lowerPos->hasReached( $lowerPos ) );
+                       $this->assertFalse( $lowerPos->hasReached( $higherPos ) );
+               } else { // channels don't match
+                       $this->assertFalse( $lowerPos->channelsMatch( $higherPos ) );
+
+                       $this->assertFalse( $higherPos->hasReached( $lowerPos ) );
+                       $this->assertFalse( $lowerPos->hasReached( $higherPos ) );
+               }
+       }
+
+       public static function provideComparePositions() {
+               return [
+                       // Binlog style
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '843431247' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '843431248' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '1000' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1035-bin.000976', '1000' ),
+                               false
+                       ],
+                       // MySQL GTID style
+                       [
+                               new MySQLMasterPos( 'db1-bin.2', '1', '3E11FA47-71CA-11E1-9E33-C80AA9429562:23' ),
+                               new MySQLMasterPos( 'db1-bin.2', '2', '3E11FA47-71CA-11E1-9E33-C80AA9429562:24' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1-bin.2', '1', '3E11FA47-71CA-11E1-9E33-C80AA9429562:99' ),
+                               new MySQLMasterPos( 'db1-bin.2', '2', '3E11FA47-71CA-11E1-9E33-C80AA9429562:100' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1-bin.2', '1', '3E11FA47-71CA-11E1-9E33-C80AA9429562:99' ),
+                               new MySQLMasterPos( 'db1-bin.2', '2', '1E11FA47-71CA-11E1-9E33-C80AA9429562:100' ),
+                               false
+                       ],
+                       // MariaDB GTID style
+                       [
+                               new MySQLMasterPos( 'db1-bin.2', '1', '255-11-23' ),
+                               new MySQLMasterPos( 'db1-bin.2', '2', '255-11-24' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1-bin.2', '1', '255-11-99' ),
+                               new MySQLMasterPos( 'db1-bin.2', '2', '255-11-100' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1-bin.2', '1', '255-11-999' ),
+                               new MySQLMasterPos( 'db1-bin.2', '2', '254-11-1000' ),
+                               false
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideChannelPositions
+        * @covers Wikimedia\Rdbms\MySQLMasterPos
+        */
+       public function testChannelsMatch( MySQLMasterPos $pos1, MySQLMasterPos $pos2, $matches ) {
+               $this->assertEquals( $matches, $pos1->channelsMatch( $pos2 ) );
+               $this->assertEquals( $matches, $pos2->channelsMatch( $pos1 ) );
+       }
+
+       public static function provideChannelPositions() {
+               return [
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000876', '44' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '74' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1052-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1052-bin.000976', '1000' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1066-bin.000976', '9999' ),
+                               new MySQLMasterPos( 'db1035-bin.000976', '10000' ),
+                               false
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1066-bin.000976', '9999' ),
+                               new MySQLMasterPos( 'trump2016.000976', '10000' ),
+                               false
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideLagAmounts
+        * @covers Wikimedia\Rdbms\DatabaseMysqlBase::getLag
+        * @covers Wikimedia\Rdbms\DatabaseMysqlBase::getLagFromPtHeartbeat
+        */
+       public function testPtHeartbeat( $lag ) {
+               $db = $this->getMockBuilder( 'DatabaseMysqli' )
+                       ->disableOriginalConstructor()
+                       ->setMethods( [
+                               'getLagDetectionMethod', 'getHeartbeatData', 'getMasterServerInfo' ] )
+                       ->getMock();
+
+               $db->method( 'getLagDetectionMethod' )
+                       ->willReturn( 'pt-heartbeat' );
+
+               $db->method( 'getMasterServerInfo' )
+                       ->willReturn( [ 'serverId' => 172, 'asOf' => time() ] );
+
+               // Fake the current time.
+               list( $nowSecFrac, $nowSec ) = explode( ' ', microtime() );
+               $now = (float)$nowSec + (float)$nowSecFrac;
+               // Fake the heartbeat time.
+               // Work arounds for weak DataTime microseconds support.
+               $ptTime = $now - $lag;
+               $ptSec = (int)$ptTime;
+               $ptSecFrac = ( $ptTime - $ptSec );
+               $ptDateTime = new DateTime( "@$ptSec" );
+               $ptTimeISO = $ptDateTime->format( 'Y-m-d\TH:i:s' );
+               $ptTimeISO .= ltrim( number_format( $ptSecFrac, 6 ), '0' );
+
+               $db->method( 'getHeartbeatData' )
+                       ->with( [ 'server_id' => 172 ] )
+                       ->willReturn( [ $ptTimeISO, $now ] );
+
+               $db->setLBInfo( 'clusterMasterHost', 'db1052' );
+               $lagEst = $db->getLag();
+
+               $this->assertGreaterThan( $lag - .010, $lagEst, "Correct heatbeat lag" );
+               $this->assertLessThan( $lag + .010, $lagEst, "Correct heatbeat lag" );
+       }
+
+       public static function provideLagAmounts() {
+               return [
+                       [ 0 ],
+                       [ 0.3 ],
+                       [ 6.5 ],
+                       [ 10.1 ],
+                       [ 200.2 ],
+                       [ 400.7 ],
+                       [ 600.22 ],
+                       [ 1000.77 ],
+               ];
+       }
+}
diff --git a/tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php b/tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php
new file mode 100644 (file)
index 0000000..57666bd
--- /dev/null
@@ -0,0 +1,1075 @@
+<?php
+
+use Wikimedia\Rdbms\LikeMatch;
+
+/**
+ * Test the parts of the Database abstract class that deal
+ * with creating SQL text.
+ */
+class DatabaseSQLTest extends PHPUnit_Framework_TestCase {
+       /** @var DatabaseTestHelper */
+       private $database;
+
+       protected function setUp() {
+               parent::setUp();
+               $this->database = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => true ] );
+       }
+
+       protected function assertLastSql( $sqlText ) {
+               $this->assertEquals(
+                       $sqlText,
+                       $this->database->getLastSqls()
+               );
+       }
+
+       protected function assertLastSqlDb( $sqlText, $db ) {
+               $this->assertEquals( $sqlText, $db->getLastSqls() );
+       }
+
+       /**
+        * @dataProvider provideSelect
+        * @covers Wikimedia\Rdbms\Database::select
+        */
+       public function testSelect( $sql, $sqlText ) {
+               $this->database->select(
+                       $sql['tables'],
+                       $sql['fields'],
+                       isset( $sql['conds'] ) ? $sql['conds'] : [],
+                       __METHOD__,
+                       isset( $sql['options'] ) ? $sql['options'] : [],
+                       isset( $sql['join_conds'] ) ? $sql['join_conds'] : []
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideSelect() {
+               return [
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'fields' => [ 'field', 'alias' => 'field2' ],
+                                       'conds' => [ 'alias' => 'text' ],
+                               ],
+                               "SELECT field,field2 AS alias " .
+                                       "FROM table " .
+                                       "WHERE alias = 'text'"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'fields' => [ 'field', 'alias' => 'field2' ],
+                                       'conds' => [ 'alias' => 'text' ],
+                                       'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
+                               ],
+                               "SELECT field,field2 AS alias " .
+                                       "FROM table " .
+                                       "WHERE alias = 'text' " .
+                                       "ORDER BY field " .
+                                       "LIMIT 1"
+                       ],
+                       [
+                               [
+                                       'tables' => [ 'table', 't2' => 'table2' ],
+                                       'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
+                                       'conds' => [ 'alias' => 'text' ],
+                                       'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
+                                       'join_conds' => [ 't2' => [
+                                               'LEFT JOIN', 'tid = t2.id'
+                                       ] ],
+                               ],
+                               "SELECT tid,field,field2 AS alias,t2.id " .
+                                       "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
+                                       "WHERE alias = 'text' " .
+                                       "ORDER BY field " .
+                                       "LIMIT 1"
+                       ],
+                       [
+                               [
+                                       'tables' => [ 'table', 't2' => 'table2' ],
+                                       'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
+                                       'conds' => [ 'alias' => 'text' ],
+                                       'options' => [ 'LIMIT' => 1, 'GROUP BY' => 'field', 'HAVING' => 'COUNT(*) > 1' ],
+                                       'join_conds' => [ 't2' => [
+                                               'LEFT JOIN', 'tid = t2.id'
+                                       ] ],
+                               ],
+                               "SELECT tid,field,field2 AS alias,t2.id " .
+                                       "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
+                                       "WHERE alias = 'text' " .
+                                       "GROUP BY field HAVING COUNT(*) > 1 " .
+                                       "LIMIT 1"
+                       ],
+                       [
+                               [
+                                       'tables' => [ 'table', 't2' => 'table2' ],
+                                       'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
+                                       'conds' => [ 'alias' => 'text' ],
+                                       'options' => [
+                                               'LIMIT' => 1,
+                                               'GROUP BY' => [ 'field', 'field2' ],
+                                               'HAVING' => [ 'COUNT(*) > 1', 'field' => 1 ]
+                                       ],
+                                       'join_conds' => [ 't2' => [
+                                               'LEFT JOIN', 'tid = t2.id'
+                                       ] ],
+                               ],
+                               "SELECT tid,field,field2 AS alias,t2.id " .
+                                       "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
+                                       "WHERE alias = 'text' " .
+                                       "GROUP BY field,field2 HAVING (COUNT(*) > 1) AND field = '1' " .
+                                       "LIMIT 1"
+                       ],
+                       [
+                               [
+                                       'tables' => [ 'table' ],
+                                       'fields' => [ 'alias' => 'field' ],
+                                       'conds' => [ 'alias' => [ 1, 2, 3, 4 ] ],
+                               ],
+                               "SELECT field AS alias " .
+                                       "FROM table " .
+                                       "WHERE alias IN ('1','2','3','4')"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideUpdate
+        * @covers Wikimedia\Rdbms\Database::update
+        */
+       public function testUpdate( $sql, $sqlText ) {
+               $this->database->update(
+                       $sql['table'],
+                       $sql['values'],
+                       $sql['conds'],
+                       __METHOD__,
+                       isset( $sql['options'] ) ? $sql['options'] : []
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideUpdate() {
+               return [
+                       [
+                               [
+                                       'table' => 'table',
+                                       'values' => [ 'field' => 'text', 'field2' => 'text2' ],
+                                       'conds' => [ 'alias' => 'text' ],
+                               ],
+                               "UPDATE table " .
+                                       "SET field = 'text'" .
+                                       ",field2 = 'text2' " .
+                                       "WHERE alias = 'text'"
+                       ],
+                       [
+                               [
+                                       'table' => 'table',
+                                       'values' => [ 'field = other', 'field2' => 'text2' ],
+                                       'conds' => [ 'id' => '1' ],
+                               ],
+                               "UPDATE table " .
+                                       "SET field = other" .
+                                       ",field2 = 'text2' " .
+                                       "WHERE id = '1'"
+                       ],
+                       [
+                               [
+                                       'table' => 'table',
+                                       'values' => [ 'field = other', 'field2' => 'text2' ],
+                                       'conds' => '*',
+                               ],
+                               "UPDATE table " .
+                                       "SET field = other" .
+                                       ",field2 = 'text2'"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideDelete
+        * @covers Wikimedia\Rdbms\Database::delete
+        */
+       public function testDelete( $sql, $sqlText ) {
+               $this->database->delete(
+                       $sql['table'],
+                       $sql['conds'],
+                       __METHOD__
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideDelete() {
+               return [
+                       [
+                               [
+                                       'table' => 'table',
+                                       'conds' => [ 'alias' => 'text' ],
+                               ],
+                               "DELETE FROM table " .
+                                       "WHERE alias = 'text'"
+                       ],
+                       [
+                               [
+                                       'table' => 'table',
+                                       'conds' => '*',
+                               ],
+                               "DELETE FROM table"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideUpsert
+        * @covers Wikimedia\Rdbms\Database::upsert
+        */
+       public function testUpsert( $sql, $sqlText ) {
+               $this->database->upsert(
+                       $sql['table'],
+                       $sql['rows'],
+                       $sql['uniqueIndexes'],
+                       $sql['set'],
+                       __METHOD__
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideUpsert() {
+               return [
+                       [
+                               [
+                                       'table' => 'upsert_table',
+                                       'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
+                                       'uniqueIndexes' => [ 'field' ],
+                                       'set' => [ 'field' => 'set' ],
+                               ],
+                               "BEGIN; " .
+                                       "UPDATE upsert_table " .
+                                       "SET field = 'set' " .
+                                       "WHERE ((field = 'text')); " .
+                                       "INSERT IGNORE INTO upsert_table " .
+                                       "(field,field2) " .
+                                       "VALUES ('text','text2'); " .
+                                       "COMMIT"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideDeleteJoin
+        * @covers Wikimedia\Rdbms\Database::deleteJoin
+        */
+       public function testDeleteJoin( $sql, $sqlText ) {
+               $this->database->deleteJoin(
+                       $sql['delTable'],
+                       $sql['joinTable'],
+                       $sql['delVar'],
+                       $sql['joinVar'],
+                       $sql['conds'],
+                       __METHOD__
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideDeleteJoin() {
+               return [
+                       [
+                               [
+                                       'delTable' => 'table',
+                                       'joinTable' => 'table_join',
+                                       'delVar' => 'field',
+                                       'joinVar' => 'field_join',
+                                       'conds' => [ 'alias' => 'text' ],
+                               ],
+                               "DELETE FROM table " .
+                                       "WHERE field IN (" .
+                                       "SELECT field_join FROM table_join WHERE alias = 'text'" .
+                                       ")"
+                       ],
+                       [
+                               [
+                                       'delTable' => 'table',
+                                       'joinTable' => 'table_join',
+                                       'delVar' => 'field',
+                                       'joinVar' => 'field_join',
+                                       'conds' => '*',
+                               ],
+                               "DELETE FROM table " .
+                                       "WHERE field IN (" .
+                                       "SELECT field_join FROM table_join " .
+                                       ")"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideInsert
+        * @covers Wikimedia\Rdbms\Database::insert
+        */
+       public function testInsert( $sql, $sqlText ) {
+               $this->database->insert(
+                       $sql['table'],
+                       $sql['rows'],
+                       __METHOD__,
+                       isset( $sql['options'] ) ? $sql['options'] : []
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideInsert() {
+               return [
+                       [
+                               [
+                                       'table' => 'table',
+                                       'rows' => [ 'field' => 'text', 'field2' => 2 ],
+                               ],
+                               "INSERT INTO table " .
+                                       "(field,field2) " .
+                                       "VALUES ('text','2')"
+                       ],
+                       [
+                               [
+                                       'table' => 'table',
+                                       'rows' => [ 'field' => 'text', 'field2' => 2 ],
+                                       'options' => 'IGNORE',
+                               ],
+                               "INSERT IGNORE INTO table " .
+                                       "(field,field2) " .
+                                       "VALUES ('text','2')"
+                       ],
+                       [
+                               [
+                                       'table' => 'table',
+                                       'rows' => [
+                                               [ 'field' => 'text', 'field2' => 2 ],
+                                               [ 'field' => 'multi', 'field2' => 3 ],
+                                       ],
+                                       'options' => 'IGNORE',
+                               ],
+                               "INSERT IGNORE INTO table " .
+                                       "(field,field2) " .
+                                       "VALUES " .
+                                       "('text','2')," .
+                                       "('multi','3')"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideInsertSelect
+        * @covers Wikimedia\Rdbms\Database::insertSelect
+        */
+       public function testInsertSelect( $sql, $sqlTextNative, $sqlSelect, $sqlInsert ) {
+               $this->database->insertSelect(
+                       $sql['destTable'],
+                       $sql['srcTable'],
+                       $sql['varMap'],
+                       $sql['conds'],
+                       __METHOD__,
+                       isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
+                       isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : [],
+                       isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'] : []
+               );
+               $this->assertLastSql( $sqlTextNative );
+
+               $dbWeb = new DatabaseTestHelper( __CLASS__, [ 'cliMode' => false ] );
+               $dbWeb->forceNextResult( [
+                       array_flip( array_keys( $sql['varMap'] ) )
+               ] );
+               $dbWeb->insertSelect(
+                       $sql['destTable'],
+                       $sql['srcTable'],
+                       $sql['varMap'],
+                       $sql['conds'],
+                       __METHOD__,
+                       isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
+                       isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : [],
+                       isset( $sql['selectJoinConds'] ) ? $sql['selectJoinConds'] : []
+               );
+               $this->assertLastSqlDb( implode( '; ', [ $sqlSelect, $sqlInsert ] ), $dbWeb );
+       }
+
+       public static function provideInsertSelect() {
+               return [
+                       [
+                               [
+                                       'destTable' => 'insert_table',
+                                       'srcTable' => 'select_table',
+                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
+                                       'conds' => '*',
+                               ],
+                               "INSERT INTO insert_table " .
+                                       "(field_insert,field) " .
+                                       "SELECT field_select,field2 " .
+                                       "FROM select_table WHERE *",
+                               "SELECT field_select AS field_insert,field2 AS field " .
+                               "FROM select_table WHERE *   FOR UPDATE",
+                               "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
+                       ],
+                       [
+                               [
+                                       'destTable' => 'insert_table',
+                                       'srcTable' => 'select_table',
+                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
+                                       'conds' => [ 'field' => 2 ],
+                               ],
+                               "INSERT INTO insert_table " .
+                                       "(field_insert,field) " .
+                                       "SELECT field_select,field2 " .
+                                       "FROM select_table " .
+                                       "WHERE field = '2'",
+                               "SELECT field_select AS field_insert,field2 AS field FROM " .
+                               "select_table WHERE field = '2'   FOR UPDATE",
+                               "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
+                       ],
+                       [
+                               [
+                                       'destTable' => 'insert_table',
+                                       'srcTable' => 'select_table',
+                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
+                                       'conds' => [ 'field' => 2 ],
+                                       'insertOptions' => 'IGNORE',
+                                       'selectOptions' => [ 'ORDER BY' => 'field' ],
+                               ],
+                               "INSERT IGNORE INTO insert_table " .
+                                       "(field_insert,field) " .
+                                       "SELECT field_select,field2 " .
+                                       "FROM select_table " .
+                                       "WHERE field = '2' " .
+                                       "ORDER BY field",
+                               "SELECT field_select AS field_insert,field2 AS field " .
+                               "FROM select_table WHERE field = '2' ORDER BY field  FOR UPDATE",
+                               "INSERT IGNORE INTO insert_table (field_insert,field) VALUES ('0','1')"
+                       ],
+                       [
+                               [
+                                       'destTable' => 'insert_table',
+                                       'srcTable' => [ 'select_table1', 'select_table2' ],
+                                       'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
+                                       'conds' => [ 'field' => 2 ],
+                                       'selectOptions' => [ 'ORDER BY' => 'field', 'FORCE INDEX' => [ 'select_table1' => 'index1' ] ],
+                                       'selectJoinConds' => [
+                                               'select_table2' => [ 'LEFT JOIN', [ 'select_table1.foo = select_table2.bar' ] ],
+                                       ],
+                               ],
+                               "INSERT INTO insert_table " .
+                                       "(field_insert,field) " .
+                                       "SELECT field_select,field2 " .
+                                       "FROM select_table1 LEFT JOIN select_table2 ON ((select_table1.foo = select_table2.bar)) " .
+                                       "WHERE field = '2' " .
+                                       "ORDER BY field",
+                               "SELECT field_select AS field_insert,field2 AS field " .
+                               "FROM select_table1 LEFT JOIN select_table2 ON ((select_table1.foo = select_table2.bar)) " .
+                               "WHERE field = '2' ORDER BY field  FOR UPDATE",
+                               "INSERT INTO insert_table (field_insert,field) VALUES ('0','1')"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideReplace
+        * @covers Wikimedia\Rdbms\Database::replace
+        */
+       public function testReplace( $sql, $sqlText ) {
+               $this->database->replace(
+                       $sql['table'],
+                       $sql['uniqueIndexes'],
+                       $sql['rows'],
+                       __METHOD__
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideReplace() {
+               return [
+                       [
+                               [
+                                       'table' => 'replace_table',
+                                       'uniqueIndexes' => [ 'field' ],
+                                       'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
+                               ],
+                               "DELETE FROM replace_table " .
+                                       "WHERE ( field='text' ); " .
+                                       "INSERT INTO replace_table " .
+                                       "(field,field2) " .
+                                       "VALUES ('text','text2')"
+                       ],
+                       [
+                               [
+                                       'table' => 'module_deps',
+                                       'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
+                                       'rows' => [
+                                               'md_module' => 'module',
+                                               'md_skin' => 'skin',
+                                               'md_deps' => 'deps',
+                                       ],
+                               ],
+                               "DELETE FROM module_deps " .
+                                       "WHERE ( md_module='module' AND md_skin='skin' ); " .
+                                       "INSERT INTO module_deps " .
+                                       "(md_module,md_skin,md_deps) " .
+                                       "VALUES ('module','skin','deps')"
+                       ],
+                       [
+                               [
+                                       'table' => 'module_deps',
+                                       'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
+                                       'rows' => [
+                                               [
+                                                       'md_module' => 'module',
+                                                       'md_skin' => 'skin',
+                                                       'md_deps' => 'deps',
+                                               ], [
+                                                       'md_module' => 'module2',
+                                                       'md_skin' => 'skin2',
+                                                       'md_deps' => 'deps2',
+                                               ],
+                                       ],
+                               ],
+                               "DELETE FROM module_deps " .
+                                       "WHERE ( md_module='module' AND md_skin='skin' ); " .
+                                       "INSERT INTO module_deps " .
+                                       "(md_module,md_skin,md_deps) " .
+                                       "VALUES ('module','skin','deps'); " .
+                                       "DELETE FROM module_deps " .
+                                       "WHERE ( md_module='module2' AND md_skin='skin2' ); " .
+                                       "INSERT INTO module_deps " .
+                                       "(md_module,md_skin,md_deps) " .
+                                       "VALUES ('module2','skin2','deps2')"
+                       ],
+                       [
+                               [
+                                       'table' => 'module_deps',
+                                       'uniqueIndexes' => [ 'md_module', 'md_skin' ],
+                                       'rows' => [
+                                               [
+                                                       'md_module' => 'module',
+                                                       'md_skin' => 'skin',
+                                                       'md_deps' => 'deps',
+                                               ], [
+                                                       'md_module' => 'module2',
+                                                       'md_skin' => 'skin2',
+                                                       'md_deps' => 'deps2',
+                                               ],
+                                       ],
+                               ],
+                               "DELETE FROM module_deps " .
+                                       "WHERE ( md_module='module' ) OR ( md_skin='skin' ); " .
+                                       "INSERT INTO module_deps " .
+                                       "(md_module,md_skin,md_deps) " .
+                                       "VALUES ('module','skin','deps'); " .
+                                       "DELETE FROM module_deps " .
+                                       "WHERE ( md_module='module2' ) OR ( md_skin='skin2' ); " .
+                                       "INSERT INTO module_deps " .
+                                       "(md_module,md_skin,md_deps) " .
+                                       "VALUES ('module2','skin2','deps2')"
+                       ],
+                       [
+                               [
+                                       'table' => 'module_deps',
+                                       'uniqueIndexes' => [],
+                                       'rows' => [
+                                               'md_module' => 'module',
+                                               'md_skin' => 'skin',
+                                               'md_deps' => 'deps',
+                                       ],
+                               ],
+                               "INSERT INTO module_deps " .
+                                       "(md_module,md_skin,md_deps) " .
+                                       "VALUES ('module','skin','deps')"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideNativeReplace
+        * @covers Wikimedia\Rdbms\Database::nativeReplace
+        */
+       public function testNativeReplace( $sql, $sqlText ) {
+               $this->database->nativeReplace(
+                       $sql['table'],
+                       $sql['rows'],
+                       __METHOD__
+               );
+               $this->assertLastSql( $sqlText );
+       }
+
+       public static function provideNativeReplace() {
+               return [
+                       [
+                               [
+                                       'table' => 'replace_table',
+                                       'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
+                               ],
+                               "REPLACE INTO replace_table " .
+                                       "(field,field2) " .
+                                       "VALUES ('text','text2')"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideConditional
+        * @covers Wikimedia\Rdbms\Database::conditional
+        */
+       public function testConditional( $sql, $sqlText ) {
+               $this->assertEquals( trim( $this->database->conditional(
+                       $sql['conds'],
+                       $sql['true'],
+                       $sql['false']
+               ) ), $sqlText );
+       }
+
+       public static function provideConditional() {
+               return [
+                       [
+                               [
+                                       'conds' => [ 'field' => 'text' ],
+                                       'true' => 1,
+                                       'false' => 'NULL',
+                               ],
+                               "(CASE WHEN field = 'text' THEN 1 ELSE NULL END)"
+                       ],
+                       [
+                               [
+                                       'conds' => [ 'field' => 'text', 'field2' => 'anothertext' ],
+                                       'true' => 1,
+                                       'false' => 'NULL',
+                               ],
+                               "(CASE WHEN field = 'text' AND field2 = 'anothertext' THEN 1 ELSE NULL END)"
+                       ],
+                       [
+                               [
+                                       'conds' => 'field=1',
+                                       'true' => 1,
+                                       'false' => 'NULL',
+                               ],
+                               "(CASE WHEN field=1 THEN 1 ELSE NULL END)"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideBuildConcat
+        * @covers Wikimedia\Rdbms\Database::buildConcat
+        */
+       public function testBuildConcat( $stringList, $sqlText ) {
+               $this->assertEquals( trim( $this->database->buildConcat(
+                       $stringList
+               ) ), $sqlText );
+       }
+
+       public static function provideBuildConcat() {
+               return [
+                       [
+                               [ 'field', 'field2' ],
+                               "CONCAT(field,field2)"
+                       ],
+                       [
+                               [ "'test'", 'field2' ],
+                               "CONCAT('test',field2)"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideBuildLike
+        * @covers Wikimedia\Rdbms\Database::buildLike
+        */
+       public function testBuildLike( $array, $sqlText ) {
+               $this->assertEquals( trim( $this->database->buildLike(
+                       $array
+               ) ), $sqlText );
+       }
+
+       public static function provideBuildLike() {
+               return [
+                       [
+                               'text',
+                               "LIKE 'text' ESCAPE '`'"
+                       ],
+                       [
+                               [ 'text', new LikeMatch( '%' ) ],
+                               "LIKE 'text%' ESCAPE '`'"
+                       ],
+                       [
+                               [ 'text', new LikeMatch( '%' ), 'text2' ],
+                               "LIKE 'text%text2' ESCAPE '`'"
+                       ],
+                       [
+                               [ 'text', new LikeMatch( '_' ) ],
+                               "LIKE 'text_' ESCAPE '`'"
+                       ],
+                       [
+                               'more_text',
+                               "LIKE 'more`_text' ESCAPE '`'"
+                       ],
+                       [
+                               [ 'C:\\Windows\\', new LikeMatch( '%' ) ],
+                               "LIKE 'C:\\Windows\\%' ESCAPE '`'"
+                       ],
+                       [
+                               [ 'accent`_test`', new LikeMatch( '%' ) ],
+                               "LIKE 'accent```_test``%' ESCAPE '`'"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideUnionQueries
+        * @covers Wikimedia\Rdbms\Database::unionQueries
+        */
+       public function testUnionQueries( $sql, $sqlText ) {
+               $this->assertEquals( trim( $this->database->unionQueries(
+                       $sql['sqls'],
+                       $sql['all']
+               ) ), $sqlText );
+       }
+
+       public static function provideUnionQueries() {
+               return [
+                       [
+                               [
+                                       'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
+                                       'all' => true,
+                               ],
+                               "(RAW SQL) UNION ALL (RAW2SQL)"
+                       ],
+                       [
+                               [
+                                       'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
+                                       'all' => false,
+                               ],
+                               "(RAW SQL) UNION (RAW2SQL)"
+                       ],
+                       [
+                               [
+                                       'sqls' => [ 'RAW SQL', 'RAW2SQL', 'RAW3SQL' ],
+                                       'all' => false,
+                               ],
+                               "(RAW SQL) UNION (RAW2SQL) UNION (RAW3SQL)"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideUnionConditionPermutations
+        * @covers Wikimedia\Rdbms\Database::unionConditionPermutations
+        */
+       public function testUnionConditionPermutations( $params, $expect ) {
+               if ( isset( $params['unionSupportsOrderAndLimit'] ) ) {
+                       $this->database->setUnionSupportsOrderAndLimit( $params['unionSupportsOrderAndLimit'] );
+               }
+
+               $sql = trim( $this->database->unionConditionPermutations(
+                       $params['table'],
+                       $params['vars'],
+                       $params['permute_conds'],
+                       isset( $params['extra_conds'] ) ? $params['extra_conds'] : '',
+                       'FNAME',
+                       isset( $params['options'] ) ? $params['options'] : [],
+                       isset( $params['join_conds'] ) ? $params['join_conds'] : []
+               ) );
+               $this->assertEquals( $expect, $sql );
+       }
+
+       public static function provideUnionConditionPermutations() {
+               return [
+                       // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
+                       [
+                               [
+                                       'table' => [ 'table1', 'table2' ],
+                                       'vars' => [ 'field1', 'alias' => 'field2' ],
+                                       'permute_conds' => [
+                                               'field3' => [ 1, 2, 3 ],
+                                               'duplicates' => [ 4, 5, 4 ],
+                                               'empty' => [],
+                                               'single' => [ 0 ],
+                                       ],
+                                       'extra_conds' => 'table2.bar > 23',
+                                       'options' => [
+                                               'ORDER BY' => [ 'field1', 'alias' ],
+                                               'INNER ORDER BY' => [ 'field1', 'field2' ],
+                                               'LIMIT' => 100,
+                                       ],
+                                       'join_conds' => [
+                                               'table2' => [ 'JOIN', 'table1.foo_id = table2.foo_id' ],
+                                       ],
+                               ],
+                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '1' AND duplicates = '4' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
+                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '1' AND duplicates = '5' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
+                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '2' AND duplicates = '4' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
+                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '2' AND duplicates = '5' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
+                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '3' AND duplicates = '4' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) UNION ALL " .
+                               "(SELECT  field1,field2 AS alias  FROM table1 JOIN table2 ON ((table1.foo_id = table2.foo_id))   WHERE field3 = '3' AND duplicates = '5' AND single = '0' AND (table2.bar > 23)  ORDER BY field1,field2 LIMIT 100  ) " .
+                               "ORDER BY field1,alias LIMIT 100"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [
+                                               'bar' => [ 1, 2, 3 ],
+                                       ],
+                                       'extra_conds' => [ 'baz' => null ],
+                                       'options' => [
+                                               'NOTALL',
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                       ],
+                               ],
+                               "(SELECT  foo_id  FROM foo    WHERE bar = '1' AND baz IS NULL  ORDER BY foo_id LIMIT 25  ) UNION " .
+                               "(SELECT  foo_id  FROM foo    WHERE bar = '2' AND baz IS NULL  ORDER BY foo_id LIMIT 25  ) UNION " .
+                               "(SELECT  foo_id  FROM foo    WHERE bar = '3' AND baz IS NULL  ORDER BY foo_id LIMIT 25  ) " .
+                               "ORDER BY foo_id LIMIT 25"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [
+                                               'bar' => [ 1, 2, 3 ],
+                                       ],
+                                       'extra_conds' => [ 'baz' => null ],
+                                       'options' => [
+                                               'NOTALL' => true,
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                       ],
+                                       'unionSupportsOrderAndLimit' => false,
+                               ],
+                               "(SELECT  foo_id  FROM foo    WHERE bar = '1' AND baz IS NULL  ) UNION " .
+                               "(SELECT  foo_id  FROM foo    WHERE bar = '2' AND baz IS NULL  ) UNION " .
+                               "(SELECT  foo_id  FROM foo    WHERE bar = '3' AND baz IS NULL  ) " .
+                               "ORDER BY foo_id LIMIT 25"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [],
+                                       'extra_conds' => [ 'baz' => null ],
+                                       'options' => [
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                       ],
+                               ],
+                               "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 25"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [
+                                               'bar' => [],
+                                       ],
+                                       'extra_conds' => [ 'baz' => null ],
+                                       'options' => [
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                       ],
+                               ],
+                               "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 25"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [
+                                               'bar' => [ 1 ],
+                                       ],
+                                       'options' => [
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                               'OFFSET' => 150,
+                                       ],
+                               ],
+                               "SELECT  foo_id  FROM foo    WHERE bar = '1'  ORDER BY foo_id LIMIT 150,25"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [],
+                                       'extra_conds' => [ 'baz' => null ],
+                                       'options' => [
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                               'OFFSET' => 150,
+                                               'INNER ORDER BY' => [ 'bar_id' ],
+                                       ],
+                               ],
+                               "(SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY bar_id LIMIT 175  ) ORDER BY foo_id LIMIT 150,25"
+                       ],
+                       [
+                               [
+                                       'table' => 'foo',
+                                       'vars' => [ 'foo_id' ],
+                                       'permute_conds' => [],
+                                       'extra_conds' => [ 'baz' => null ],
+                                       'options' => [
+                                               'ORDER BY' => [ 'foo_id' ],
+                                               'LIMIT' => 25,
+                                               'OFFSET' => 150,
+                                               'INNER ORDER BY' => [ 'bar_id' ],
+                                       ],
+                                       'unionSupportsOrderAndLimit' => false,
+                               ],
+                               "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 150,25"
+                       ],
+                       // @codingStandardsIgnoreEnd
+               ];
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::commit
+        */
+       public function testTransactionCommit() {
+               $this->database->begin( __METHOD__ );
+               $this->database->commit( __METHOD__ );
+               $this->assertLastSql( 'BEGIN; COMMIT' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::rollback
+        */
+       public function testTransactionRollback() {
+               $this->database->begin( __METHOD__ );
+               $this->database->rollback( __METHOD__ );
+               $this->assertLastSql( 'BEGIN; ROLLBACK' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::dropTable
+        */
+       public function testDropTable() {
+               $this->database->setExistingTables( [ 'table' ] );
+               $this->database->dropTable( 'table', __METHOD__ );
+               $this->assertLastSql( 'DROP TABLE table CASCADE' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::dropTable
+        */
+       public function testDropNonExistingTable() {
+               $this->assertFalse(
+                       $this->database->dropTable( 'non_existing', __METHOD__ )
+               );
+       }
+
+       /**
+        * @dataProvider provideMakeList
+        * @covers Wikimedia\Rdbms\Database::makeList
+        */
+       public function testMakeList( $list, $mode, $sqlText ) {
+               $this->assertEquals( trim( $this->database->makeList(
+                       $list, $mode
+               ) ), $sqlText );
+       }
+
+       public static function provideMakeList() {
+               return [
+                       [
+                               [ 'value', 'value2' ],
+                               LIST_COMMA,
+                               "'value','value2'"
+                       ],
+                       [
+                               [ 'field', 'field2' ],
+                               LIST_NAMES,
+                               "field,field2"
+                       ],
+                       [
+                               [ 'field' => 'value', 'field2' => 'value2' ],
+                               LIST_AND,
+                               "field = 'value' AND field2 = 'value2'"
+                       ],
+                       [
+                               [ 'field' => null, "field2 != 'value2'" ],
+                               LIST_AND,
+                               "field IS NULL AND (field2 != 'value2')"
+                       ],
+                       [
+                               [ 'field' => [ 'value', null, 'value2' ], 'field2' => 'value2' ],
+                               LIST_AND,
+                               "(field IN ('value','value2')  OR field IS NULL) AND field2 = 'value2'"
+                       ],
+                       [
+                               [ 'field' => [ null ], 'field2' => null ],
+                               LIST_AND,
+                               "field IS NULL AND field2 IS NULL"
+                       ],
+                       [
+                               [ 'field' => 'value', 'field2' => 'value2' ],
+                               LIST_OR,
+                               "field = 'value' OR field2 = 'value2'"
+                       ],
+                       [
+                               [ 'field' => 'value', 'field2' => null ],
+                               LIST_OR,
+                               "field = 'value' OR field2 IS NULL"
+                       ],
+                       [
+                               [ 'field' => [ 'value', 'value2' ], 'field2' => [ 'value' ] ],
+                               LIST_OR,
+                               "field IN ('value','value2')  OR field2 = 'value'"
+                       ],
+                       [
+                               [ 'field' => [ null, 'value', null, 'value2' ], "field2 != 'value2'" ],
+                               LIST_OR,
+                               "(field IN ('value','value2')  OR field IS NULL) OR (field2 != 'value2')"
+                       ],
+                       [
+                               [ 'field' => 'value', 'field2' => 'value2' ],
+                               LIST_SET,
+                               "field = 'value',field2 = 'value2'"
+                       ],
+                       [
+                               [ 'field' => 'value', 'field2' => null ],
+                               LIST_SET,
+                               "field = 'value',field2 = NULL"
+                       ],
+                       [
+                               [ 'field' => 'value', "field2 != 'value2'" ],
+                               LIST_SET,
+                               "field = 'value',field2 != 'value2'"
+                       ],
+               ];
+       }
+
+       public function testSessionTempTables() {
+               $temp1 = $this->database->tableName( 'tmp_table_1' );
+               $temp2 = $this->database->tableName( 'tmp_table_2' );
+               $temp3 = $this->database->tableName( 'tmp_table_3' );
+
+               $this->database->query( "CREATE TEMPORARY TABLE $temp1 LIKE orig_tbl", __METHOD__ );
+               $this->database->query( "CREATE TEMPORARY TABLE $temp2 LIKE orig_tbl", __METHOD__ );
+               $this->database->query( "CREATE TEMPORARY TABLE $temp3 LIKE orig_tbl", __METHOD__ );
+
+               $this->assertTrue( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
+               $this->assertTrue( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
+               $this->assertTrue( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
+
+               $this->database->dropTable( 'tmp_table_1', __METHOD__ );
+               $this->database->dropTable( 'tmp_table_2', __METHOD__ );
+               $this->database->dropTable( 'tmp_table_3', __METHOD__ );
+
+               $this->assertFalse( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
+               $this->assertFalse( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
+               $this->assertFalse( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
+
+               $this->database->query( "CREATE TEMPORARY TABLE tmp_table_1 LIKE orig_tbl", __METHOD__ );
+               $this->database->query( "CREATE TEMPORARY TABLE 'tmp_table_2' LIKE orig_tbl", __METHOD__ );
+               $this->database->query( "CREATE TEMPORARY TABLE `tmp_table_3` LIKE orig_tbl", __METHOD__ );
+
+               $this->assertTrue( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
+               $this->assertTrue( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
+               $this->assertTrue( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
+
+               $this->database->query( "DROP TEMPORARY TABLE tmp_table_1 LIKE orig_tbl", __METHOD__ );
+               $this->database->query( "DROP TEMPORARY TABLE 'tmp_table_2' LIKE orig_tbl", __METHOD__ );
+               $this->database->query( "DROP TABLE `tmp_table_3` LIKE orig_tbl", __METHOD__ );
+
+               $this->assertFalse( $this->database->tableExists( "tmp_table_1", __METHOD__ ) );
+               $this->assertFalse( $this->database->tableExists( "tmp_table_2", __METHOD__ ) );
+               $this->assertFalse( $this->database->tableExists( "tmp_table_3", __METHOD__ ) );
+       }
+}
diff --git a/tests/phpunit/includes/libs/rdbms/database/DatabaseTest.php b/tests/phpunit/includes/libs/rdbms/database/DatabaseTest.php
new file mode 100644 (file)
index 0000000..9bea7ff
--- /dev/null
@@ -0,0 +1,355 @@
+<?php
+
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\TransactionProfiler;
+use Wikimedia\TestingAccessWrapper;
+
+class DatabaseTest extends PHPUnit_Framework_TestCase {
+
+       protected function setUp() {
+               $this->db = new DatabaseTestHelper( __CLASS__ . '::' . $this->getName() );
+       }
+
+       public static function provideAddQuotes() {
+               return [
+                       [ null, 'NULL' ],
+                       [ 1234, "'1234'" ],
+                       [ 1234.5678, "'1234.5678'" ],
+                       [ 'string', "'string'" ],
+                       [ 'string\'s cause trouble', "'string\'s cause trouble'" ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideAddQuotes
+        * @covers Wikimedia\Rdbms\Database::addQuotes
+        */
+       public function testAddQuotes( $input, $expected ) {
+               $this->assertEquals( $expected, $this->db->addQuotes( $input ) );
+       }
+
+       public static function provideTableName() {
+               // Formatting is mostly ignored since addIdentifierQuotes is abstract.
+               // For testing of addIdentifierQuotes, see actual Database subclas tests.
+               return [
+                       'local' => [
+                               'tablename',
+                               'tablename',
+                               'quoted',
+                       ],
+                       'local-raw' => [
+                               'tablename',
+                               'tablename',
+                               'raw',
+                       ],
+                       'shared' => [
+                               'sharedb.tablename',
+                               'tablename',
+                               'quoted',
+                               [ 'dbname' => 'sharedb', 'schema' => null, 'prefix' => '' ],
+                       ],
+                       'shared-raw' => [
+                               'sharedb.tablename',
+                               'tablename',
+                               'raw',
+                               [ 'dbname' => 'sharedb', 'schema' => null, 'prefix' => '' ],
+                       ],
+                       'shared-prefix' => [
+                               'sharedb.sh_tablename',
+                               'tablename',
+                               'quoted',
+                               [ 'dbname' => 'sharedb', 'schema' => null, 'prefix' => 'sh_' ],
+                       ],
+                       'shared-prefix-raw' => [
+                               'sharedb.sh_tablename',
+                               'tablename',
+                               'raw',
+                               [ 'dbname' => 'sharedb', 'schema' => null, 'prefix' => 'sh_' ],
+                       ],
+                       'foreign' => [
+                               'databasename.tablename',
+                               'databasename.tablename',
+                               'quoted',
+                       ],
+                       'foreign-raw' => [
+                               'databasename.tablename',
+                               'databasename.tablename',
+                               'raw',
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideTableName
+        * @covers Wikimedia\Rdbms\Database::tableName
+        */
+       public function testTableName( $expected, $table, $format, array $alias = null ) {
+               if ( $alias ) {
+                       $this->db->setTableAliases( [ $table => $alias ] );
+               }
+               $this->assertEquals(
+                       $expected,
+                       $this->db->tableName( $table, $format ?: 'quoted' )
+               );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::onTransactionIdle
+        * @covers Wikimedia\Rdbms\Database::runOnTransactionIdleCallbacks
+        */
+       public function testTransactionIdle() {
+               $db = $this->db;
+
+               $db->setFlag( DBO_TRX );
+               $called = false;
+               $flagSet = null;
+               $db->onTransactionIdle(
+                       function () use ( $db, &$flagSet, &$called ) {
+                               $called = true;
+                               $flagSet = $db->getFlag( DBO_TRX );
+                       },
+                       __METHOD__
+               );
+               $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
+               $this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
+               $this->assertTrue( $called, 'Callback reached' );
+
+               $db->clearFlag( DBO_TRX );
+               $flagSet = null;
+               $db->onTransactionIdle(
+                       function () use ( $db, &$flagSet ) {
+                               $flagSet = $db->getFlag( DBO_TRX );
+                       },
+                       __METHOD__
+               );
+               $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
+               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
+
+               $db->clearFlag( DBO_TRX );
+               $db->onTransactionIdle(
+                       function () use ( $db ) {
+                               $db->setFlag( DBO_TRX );
+                       },
+                       __METHOD__
+               );
+               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::onTransactionResolution
+        * @covers Wikimedia\Rdbms\Database::runOnTransactionIdleCallbacks
+        */
+       public function testTransactionResolution() {
+               $db = $this->db;
+
+               $db->clearFlag( DBO_TRX );
+               $db->begin( __METHOD__ );
+               $called = false;
+               $db->onTransactionResolution( function () use ( $db, &$called ) {
+                       $called = true;
+                       $db->setFlag( DBO_TRX );
+               } );
+               $db->commit( __METHOD__ );
+               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
+               $this->assertTrue( $called, 'Callback reached' );
+
+               $db->clearFlag( DBO_TRX );
+               $db->begin( __METHOD__ );
+               $called = false;
+               $db->onTransactionResolution( function () use ( $db, &$called ) {
+                       $called = true;
+                       $db->setFlag( DBO_TRX );
+               } );
+               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
+               $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
+               $this->assertTrue( $called, 'Callback reached' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::setTransactionListener
+        */
+       public function testTransactionListener() {
+               $db = $this->db;
+
+               $db->setTransactionListener( 'ping', function () use ( $db, &$called ) {
+                       $called = true;
+               } );
+
+               $called = false;
+               $db->begin( __METHOD__ );
+               $db->commit( __METHOD__ );
+               $this->assertTrue( $called, 'Callback reached' );
+
+               $called = false;
+               $db->begin( __METHOD__ );
+               $db->commit( __METHOD__ );
+               $this->assertTrue( $called, 'Callback still reached' );
+
+               $called = false;
+               $db->begin( __METHOD__ );
+               $db->rollback( __METHOD__ );
+               $this->assertTrue( $called, 'Callback reached' );
+
+               $db->setTransactionListener( 'ping', null );
+               $called = false;
+               $db->begin( __METHOD__ );
+               $db->commit( __METHOD__ );
+               $this->assertFalse( $called, 'Callback not reached' );
+       }
+
+       /**
+        * Use this mock instead of DatabaseTestHelper for cases where
+        * DatabaseTestHelper is too inflexibile due to mocking too much
+        * or being too restrictive about fname matching (e.g. for tests
+        * that assert behaviour when the name is a mismatch, we need to
+        * catch the error here instead of there).
+        *
+        * @return Database
+        */
+       private function getMockDB( $methods = [] ) {
+               static $abstractMethods = [
+                       'affectedRows',
+                       'closeConnection',
+                       'dataSeek',
+                       'doQuery',
+                       'fetchObject', 'fetchRow',
+                       'fieldInfo', 'fieldName',
+                       'getSoftwareLink', 'getServerVersion',
+                       'getType',
+                       'indexInfo',
+                       'insertId',
+                       'lastError', 'lastErrno',
+                       'numFields', 'numRows',
+                       'open',
+                       'strencode',
+               ];
+               $db = $this->getMockBuilder( Database::class )
+                       ->disableOriginalConstructor()
+                       ->setMethods( array_values( array_unique( array_merge(
+                               $abstractMethods,
+                               $methods
+                       ) ) ) )
+                       ->getMock();
+               $wdb = TestingAccessWrapper::newFromObject( $db );
+               $wdb->trxProfiler = new TransactionProfiler();
+               $wdb->connLogger = new \Psr\Log\NullLogger();
+               $wdb->queryLogger = new \Psr\Log\NullLogger();
+               return $db;
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::flushSnapshot
+        */
+       public function testFlushSnapshot() {
+               $db = $this->getMockDB( [ 'isOpen' ] );
+               $db->method( 'isOpen' )->willReturn( true );
+
+               $db->flushSnapshot( __METHOD__ ); // ok
+               $db->flushSnapshot( __METHOD__ ); // ok
+
+               $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
+               $db->query( 'SELECT 1', __METHOD__ );
+               $this->assertTrue( (bool)$db->trxLevel(), "Transaction started." );
+               $db->flushSnapshot( __METHOD__ ); // ok
+               $db->restoreFlags( $db::RESTORE_PRIOR );
+
+               $this->assertFalse( (bool)$db->trxLevel(), "Transaction cleared." );
+       }
+
+       public function testGetScopedLock() {
+               $db = $this->getMockDB( [ 'isOpen' ] );
+               $db->method( 'isOpen' )->willReturn( true );
+
+               $db->setFlag( DBO_TRX );
+               try {
+                       $this->badLockingMethodImplicit( $db );
+               } catch ( RunTimeException $e ) {
+                       $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
+               }
+               $db->clearFlag( DBO_TRX );
+               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
+               $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
+
+               try {
+                       $this->badLockingMethodExplicit( $db );
+               } catch ( RunTimeException $e ) {
+                       $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
+               }
+               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
+               $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
+       }
+
+       private function badLockingMethodImplicit( IDatabase $db ) {
+               $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
+               $db->query( "SELECT 1" ); // trigger DBO_TRX
+               throw new RunTimeException( "Uh oh!" );
+       }
+
+       private function badLockingMethodExplicit( IDatabase $db ) {
+               $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
+               $db->begin( __METHOD__ );
+               throw new RunTimeException( "Uh oh!" );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::getFlag
+        * @covers Wikimedia\Rdbms\Database::setFlag
+        * @covers Wikimedia\Rdbms\Database::restoreFlags
+        */
+       public function testFlagSetting() {
+               $db = $this->db;
+               $origTrx = $db->getFlag( DBO_TRX );
+               $origSsl = $db->getFlag( DBO_SSL );
+
+               $origTrx
+                       ? $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR )
+                       : $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
+               $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
+
+               $origSsl
+                       ? $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR )
+                       : $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
+               $this->assertEquals( !$origSsl, $db->getFlag( DBO_SSL ) );
+
+               $db->restoreFlags( $db::RESTORE_INITIAL );
+               $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
+               $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
+
+               $origTrx
+                       ? $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR )
+                       : $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
+               $origSsl
+                       ? $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR )
+                       : $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
+
+               $db->restoreFlags();
+               $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
+               $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
+
+               $db->restoreFlags();
+               $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
+               $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::tablePrefix
+        * @covers Wikimedia\Rdbms\Database::dbSchema
+        */
+       public function testMutators() {
+               $old = $this->db->tablePrefix();
+               $this->assertInternalType( 'string', $old, 'Prefix is string' );
+               $this->assertEquals( $old, $this->db->tablePrefix(), "Prefix unchanged" );
+               $this->assertEquals( $old, $this->db->tablePrefix( 'xxx' ) );
+               $this->assertEquals( 'xxx', $this->db->tablePrefix(), "Prefix set" );
+               $this->db->tablePrefix( $old );
+               $this->assertNotEquals( 'xxx', $this->db->tablePrefix() );
+
+               $old = $this->db->dbSchema();
+               $this->assertInternalType( 'string', $old, 'Schema is string' );
+               $this->assertEquals( $old, $this->db->dbSchema(), "Schema unchanged" );
+               $this->assertEquals( $old, $this->db->dbSchema( 'xxx' ) );
+               $this->assertEquals( 'xxx', $this->db->dbSchema(), "Schema set" );
+               $this->db->dbSchema( $old );
+               $this->assertNotEquals( 'xxx', $this->db->dbSchema() );
+       }
+}
index 3e0d883..3530d3c 100644 (file)
@@ -43,6 +43,7 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        'test.top' => [ 'position' => 'top' ],
                        'test.private.top' => [ 'group' => 'private', 'position' => 'top' ],
                        'test.private.bottom' => [ 'group' => 'private', 'position' => 'bottom' ],
+                       'test.shouldembed' => [ 'shouldEmbed' => true ],
 
                        'test.styles.pure' => [ 'type' => ResourceLoaderModule::LOAD_STYLES ],
                        'test.styles.mixed' => [],
@@ -64,12 +65,24 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                                'group' => 'private',
                                'styles' => '.private{}',
                        ],
+                       'test.styles.shouldembed' => [
+                               'type' => ResourceLoaderModule::LOAD_STYLES,
+                               'shouldEmbed' => true,
+                               'styles' => '.shouldembed{}',
+                       ],
 
                        'test.scripts' => [],
                        'test.scripts.top' => [ 'position' => 'top' ],
                        'test.scripts.user' => [ 'group' => 'user' ],
                        'test.scripts.user.empty' => [ 'group' => 'user', 'isKnownEmpty' => true ],
                        'test.scripts.raw' => [ 'isRaw' => true ],
+                       'test.scripts.shouldembed' => [ 'shouldEmbed' => true ],
+
+                       'test.ordering.a' => [ 'shouldEmbed' => false ],
+                       'test.ordering.b' => [ 'shouldEmbed' => false ],
+                       'test.ordering.c' => [ 'shouldEmbed' => true, 'styles' => '.orderingC{}' ],
+                       'test.ordering.d' => [ 'shouldEmbed' => true, 'styles' => '.orderingD{}' ],
+                       'test.ordering.e' => [ 'shouldEmbed' => false ],
                ];
                return array_map( function ( $options ) {
                        return self::makeModule( $options );
@@ -102,6 +115,7 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        'test.private.bottom',
                        'test.private.top',
                        'test.top',
+                       'test.shouldembed',
                        'test.unregistered',
                ] );
                $client->setModuleStyles( [
@@ -109,12 +123,14 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        'test.styles.user.empty',
                        'test.styles.private',
                        'test.styles.pure',
+                       'test.styles.shouldembed',
                        'test.unregistered.styles',
                ] );
                $client->setModuleScripts( [
                        'test.scripts',
                        'test.scripts.user.empty',
                        'test.scripts.top',
+                       'test.scripts.shouldembed',
                        'test.unregistered.scripts',
                ] );
 
@@ -122,12 +138,15 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        'states' => [
                                'test.private.top' => 'loading',
                                'test.private.bottom' => 'loading',
+                               'test.shouldembed' => 'loading',
                                'test.styles.pure' => 'ready',
                                'test.styles.user.empty' => 'ready',
                                'test.styles.private' => 'ready',
+                               'test.styles.shouldembed' => 'ready',
                                'test.scripts' => 'loading',
                                'test.scripts.top' => 'loading',
                                'test.scripts.user.empty' => 'ready',
+                               'test.scripts.shouldembed' => 'loading',
                        ],
                        'general' => [
                                'test',
@@ -139,12 +158,14 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        'scripts' => [
                                'test.scripts',
                                'test.scripts.top',
+                               'test.scripts.shouldembed',
                        ],
                        'embed' => [
-                               'styles' => [ 'test.styles.private' ],
+                               'styles' => [ 'test.styles.private', 'test.styles.shouldembed' ],
                                'general' => [
                                        'test.private.bottom',
                                        'test.private.top',
+                                       'test.shouldembed',
                                ],
                        ],
                ];
@@ -276,6 +297,47 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                                'only' => ResourceLoaderModule::TYPE_STYLES,
                                'output' => '<noscript><link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=nl&amp;modules=test.styles.noscript&amp;only=styles&amp;skin=fallback"/></noscript>',
                        ],
+                       [
+                               'context' => [],
+                               'modules' => [ 'test.shouldembed' ],
+                               'only' => ResourceLoaderModule::TYPE_COMBINED,
+                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.shouldembed@09p30q0",function($,jQuery,require,module){},{"css":[]});});</script>',
+                       ],
+                       [
+                               'context' => [],
+                               'modules' => [ 'test.styles.shouldembed' ],
+                               'only' => ResourceLoaderModule::TYPE_STYLES,
+                               'output' => '<style>.shouldembed{}</style>',
+                       ],
+                       [
+                               'context' => [],
+                               'modules' => [ 'test.scripts.shouldembed' ],
+                               'only' => ResourceLoaderModule::TYPE_SCRIPTS,
+                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.state({"test.scripts.shouldembed":"ready"});});</script>',
+                       ],
+                       [
+                               'context' => [],
+                               'modules' => [ 'test', 'test.shouldembed' ],
+                               'only' => ResourceLoaderModule::TYPE_COMBINED,
+                               'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?debug=false\u0026lang=nl\u0026modules=test\u0026skin=fallback");mw.loader.implement("test.shouldembed@09p30q0",function($,jQuery,require,module){},{"css":[]});});</script>',
+                       ],
+                       [
+                               'context' => [],
+                               'modules' => [ 'test.styles.pure', 'test.styles.shouldembed' ],
+                               'only' => ResourceLoaderModule::TYPE_STYLES,
+                               'output' =>
+                                       '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=nl&amp;modules=test.styles.pure&amp;only=styles&amp;skin=fallback"/>' . "\n"
+                                       . '<style>.shouldembed{}</style>'
+                       ],
+                       [
+                               'context' => [],
+                               'modules' => [ 'test.ordering.a', 'test.ordering.e', 'test.ordering.b', 'test.ordering.d', 'test.ordering.c' ],
+                               'only' => ResourceLoaderModule::TYPE_STYLES,
+                               'output' =>
+                                       '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=nl&amp;modules=test.ordering.a%2Cb&amp;only=styles&amp;skin=fallback"/>' . "\n"
+                                       . '<style>.orderingC{}.orderingD{}</style>' . "\n"
+                                       . '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=nl&amp;modules=test.ordering.e&amp;only=styles&amp;skin=fallback"/>'
+                       ],
                        // @codingStandardsIgnoreEnd
                ];
        }
diff --git a/tests/phpunit/structure/DatabaseIntegrationTest.php b/tests/phpunit/structure/DatabaseIntegrationTest.php
new file mode 100644 (file)
index 0000000..b0c1c8f
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\Database;
+
+/**
+ * @group Database
+ */
+class DatabaseIntegrationTest extends MediaWikiTestCase {
+       /**
+        * @var Database
+        */
+       protected $db;
+
+       private $functionTest = false;
+
+       protected function setUp() {
+               parent::setUp();
+               $this->db = wfGetDB( DB_MASTER );
+       }
+
+       protected function tearDown() {
+               parent::tearDown();
+               if ( $this->functionTest ) {
+                       $this->dropFunctions();
+                       $this->functionTest = false;
+               }
+               $this->db->restoreFlags( IDatabase::RESTORE_INITIAL );
+       }
+
+       public function testStoredFunctions() {
+               if ( !in_array( wfGetDB( DB_MASTER )->getType(), [ 'mysql', 'postgres' ] ) ) {
+                       $this->markTestSkipped( 'MySQL or Postgres required' );
+               }
+               global $IP;
+               $this->dropFunctions();
+               $this->functionTest = true;
+               $this->assertTrue(
+                       $this->db->sourceFile( "$IP/tests/phpunit/data/db/{$this->db->getType()}/functions.sql" )
+               );
+               $res = $this->db->query( 'SELECT mw_test_function() AS test', __METHOD__ );
+               $this->assertEquals( 42, $res->fetchObject()->test );
+       }
+
+       private function dropFunctions() {
+               $this->db->query( 'DROP FUNCTION IF EXISTS mw_test_function'
+                       . ( $this->db->getType() == 'postgres' ? '()' : '' )
+               );
+       }
+
+       public function testUnknownTableCorruptsResults() {
+               $res = $this->db->select( 'page', '*', [ 'page_id' => 1 ] );
+               $this->assertFalse( $this->db->tableExists( 'foobarbaz' ) );
+               $this->assertInternalType( 'int', $res->numRows() );
+       }
+}
index f023ddd..929fa1f 100644 (file)
@@ -4,6 +4,22 @@
 
        var addons;
 
+       /**
+        * Make a safe copy of localEnv:
+        * - Creates a copy so that when the same object reference to module hooks is
+        *   used by multipe test hooks, our QUnit.module extension will not wrap the
+        *   callbacks multiple times. Instead, they wrap using a new object.
+        * - Normalise setup/teardown to avoid having to repeat this in each extension
+        *   (deprecated in QUnit 1.16, removed in QUnit 2).
+        * - Strip any other properties.
+        */
+       function makeSafeEnv( localEnv ) {
+               return {
+                       beforeEach: localEnv.setup || localEnv.beforeEach,
+                       afterEach: localEnv.teardown || localEnv.afterEach
+               };
+       }
+
        /**
         * Add bogus to url to prevent IE crazy caching
         *
@@ -42,9 +58,6 @@
         *
         * Glue code for nicer integration with QUnit setup/teardown
         * Inspired by http://sinonjs.org/releases/sinon-qunit-1.0.0.js
-        * Fixes:
-        * - Work properly with asynchronous QUnit by using module setup/teardown
-        *   instead of synchronously wrapping QUnit.test.
         */
        sinon.assert.fail = function ( msg ) {
                QUnit.assert.ok( false, msg );
                useFakeTimers: false,
                useFakeServer: false
        };
+       // Extend QUnit.module to provide a Sinon sandbox.
        ( function () {
                var orgModule = QUnit.module;
-
                QUnit.module = function ( name, localEnv, executeNow ) {
+                       var orgBeforeEach, orgAfterEach;
                        if ( QUnit.config.moduleStack.length ) {
-                               // When inside a nested module, don't add our Sinon
-                               // setup/teardown a second time.
+                               // In a nested module, don't re-run our handlers.
                                return orgModule.apply( this, arguments );
                        }
-
                        if ( arguments.length === 2 && typeof localEnv === 'function' ) {
                                executeNow = localEnv;
                                localEnv = undefined;
                        }
 
                        localEnv = localEnv || {};
-                       orgModule( name, {
-                               setup: function () {
-                                       var config = sinon.getConfig( sinon.config );
-                                       config.injectInto = this;
-                                       sinon.sandbox.create( config );
-
-                                       if ( localEnv.setup ) {
-                                               localEnv.setup.call( this );
-                                       }
-                               },
-                               teardown: function () {
-                                       if ( localEnv.teardown ) {
-                                               localEnv.teardown.call( this );
-                                       }
-
-                                       this.sandbox.verifyAndRestore();
+                       orgBeforeEach = localEnv.beforeEach;
+                       orgAfterEach = localEnv.afterEach;
+                       localEnv.beforeEach = function () {
+                               var config = sinon.getConfig( sinon.config );
+                               config.injectInto = this;
+                               sinon.sandbox.create( config );
+
+                               if ( orgBeforeEach ) {
+                                       return orgBeforeEach.apply( this, arguments );
+                               }
+                       };
+                       localEnv.afterEach = function () {
+                               var ret;
+                               if ( orgAfterEach ) {
+                                       ret = orgAfterEach.apply( this, arguments );
                                }
-                       }, executeNow );
+
+                               this.sandbox.verifyAndRestore();
+                               return ret;
+                       };
+                       return orgModule( name, localEnv, executeNow );
                };
        }() );
 
        // Extend QUnit.module to provide a fixture element.
        ( function () {
                var orgModule = QUnit.module;
-
                QUnit.module = function ( name, localEnv, executeNow ) {
-                       var fixture;
-
+                       var orgBeforeEach, orgAfterEach;
+                       if ( QUnit.config.moduleStack.length ) {
+                               // In a nested module, don't re-run our handlers.
+                               return orgModule.apply( this, arguments );
+                       }
                        if ( arguments.length === 2 && typeof localEnv === 'function' ) {
                                executeNow = localEnv;
                                localEnv = undefined;
                        }
 
                        localEnv = localEnv || {};
-                       orgModule( name, {
-                               setup: function () {
-                                       fixture = document.createElement( 'div' );
-                                       fixture.id = 'qunit-fixture';
-                                       document.body.appendChild( fixture );
-
-                                       if ( localEnv.setup ) {
-                                               localEnv.setup.call( this );
-                                       }
-                               },
-                               teardown: function () {
-                                       if ( localEnv.teardown ) {
-                                               localEnv.teardown.call( this );
-                                       }
-
-                                       fixture.parentNode.removeChild( fixture );
+                       orgBeforeEach = localEnv.beforeEach;
+                       orgAfterEach = localEnv.afterEach;
+                       localEnv.beforeEach = function () {
+                               this.fixture = document.createElement( 'div' );
+                               this.fixture.id = 'qunit-fixture';
+                               document.body.appendChild( this.fixture );
+
+                               if ( orgBeforeEach ) {
+                                       return orgBeforeEach.apply( this, arguments );
                                }
-                       }, executeNow );
+                       };
+                       localEnv.afterEach = function () {
+                               var ret;
+                               if ( orgAfterEach ) {
+                                       ret = orgAfterEach.apply( this, arguments );
+                               }
+
+                               this.fixture.parentNode.removeChild( this.fixture );
+                               return ret;
+                       };
+                       return orgModule( name, localEnv, executeNow );
+               };
+       }() );
+
+       // Extend QUnit.module to normalise localEnv.
+       // NOTE: This MUST be the last QUnit.module extension so that the above extensions
+       // may safely modify the object and assume beforeEach/afterEach.
+       ( function () {
+               var orgModule = QUnit.module;
+               QUnit.module = function ( name, localEnv, executeNow ) {
+                       if ( typeof localEnv === 'object' ) {
+                               localEnv = makeSafeEnv( localEnv );
+                       }
+                       return orgModule( name, localEnv, executeNow );
                };
        }() );
 
                        ajaxRequests.push( { xhr: jqXHR, options: ajaxOptions } );
                }
 
-               return function ( localEnv ) {
-                       localEnv = $.extend( {
-                               // QUnit
-                               setup: $.noop,
-                               teardown: $.noop,
-                               // MediaWiki
-                               config: {},
-                               messages: {}
-                       }, localEnv );
+               return function ( orgEnv ) {
+                       var localEnv = orgEnv ? makeSafeEnv( orgEnv ) : {};
+                       // MediaWiki env testing
+                       localEnv.config = orgEnv && orgEnv.config || {};
+                       localEnv.messages = orgEnv && orgEnv.messages || {};
 
                        return {
-                               setup: function () {
+                               beforeEach: function () {
                                        // Greetings, mock environment!
                                        mw.config = new MwMap();
                                        mw.config.set( freshConfigCopy( localEnv.config ) );
                                        // Start tracking ajax requests
                                        $( document ).on( 'ajaxSend', trackAjax );
 
-                                       localEnv.setup.call( this );
+                                       if ( localEnv.beforeEach ) {
+                                               return localEnv.beforeEach.apply( this, arguments );
+                                       }
                                },
 
-                               teardown: function () {
-                                       var timers, pending, $activeLen;
+                               afterEach: function () {
+                                       var timers, pending, $activeLen, ret;
 
-                                       localEnv.teardown.call( this );
+                                       if ( localEnv.afterEach ) {
+                                               ret = localEnv.afterEach.apply( this, arguments );
+                                       }
 
                                        // Stop tracking ajax requests
                                        $( document ).off( 'ajaxSend', trackAjax );
 
                                                throw new Error( 'Pending AJAX requests: ' + pending.length + ' (active: ' + $activeLen + ')' );
                                        }
+
+                                       return ret;
                                }
                        };
                };
 
                // Expect boolean true
                assertTrue: function ( actual, message ) {
-                       QUnit.push( actual === true, actual, true, message );
+                       this.pushResult( {
+                               result: actual === true,
+                               actual: actual,
+                               expected: true,
+                               message: message
+                       } );
                },
 
                // Expect boolean false
                assertFalse: function ( actual, message ) {
-                       QUnit.push( actual === false, actual, false, message );
+                       this.pushResult( {
+                               result: actual === false,
+                               actual: actual,
+                               expected: false,
+                               message: message
+                       } );
                },
 
                // Expect numerical value less than X
                lt: function ( actual, expected, message ) {
-                       QUnit.push( actual < expected, actual, 'less than ' + expected, message );
+                       this.pushResult( {
+                               result: actual < expected,
+                               actual: actual,
+                               expected: 'less than ' + expected,
+                               message: message
+                       } );
                },
 
                // Expect numerical value less than or equal to X
                ltOrEq: function ( actual, expected, message ) {
-                       QUnit.push( actual <= expected, actual, 'less than or equal to ' + expected, message );
+                       this.pushResult( {
+                               result: actual <= expected,
+                               actual: actual,
+                               expected: 'less than or equal to ' + expected,
+                               message: message
+                       } );
                },
 
                // Expect numerical value greater than X
                gt: function ( actual, expected, message ) {
-                       QUnit.push( actual > expected, actual, 'greater than ' + expected, message );
+                       this.pushResult( {
+                               result: actual > expected,
+                               actual: actual,
+                               expected: 'greater than ' + expected,
+                               message: message
+                       } );
                },
 
                // Expect numerical value greater than or equal to X
                gtOrEq: function ( actual, expected, message ) {
-                       QUnit.push( actual >= expected, actual, 'greater than or equal to ' + expected, message );
+                       this.pushResult( {
+                               result: actual >= true,
+                               actual: actual,
+                               expected: 'greater than or equal to ' + expected,
+                               message: message
+                       } );
                },
 
                /**
                htmlEqual: function ( actualHtml, expectedHtml, message ) {
                        var actual = getHtmlStructure( actualHtml ),
                                expected = getHtmlStructure( expectedHtml );
-
-                       QUnit.push(
-                               QUnit.equiv(
-                                       actual,
-                                       expected
-                               ),
-                               actual,
-                               expected,
-                               message
-                       );
+                       this.pushResult( {
+                               result: QUnit.equiv( actual, expected ),
+                               actual: actual,
+                               expected: expected,
+                               message: message
+                       } );
                },
 
                /**
                        var actual = getHtmlStructure( actualHtml ),
                                expected = getHtmlStructure( expectedHtml );
 
-                       QUnit.push(
-                               !QUnit.equiv(
-                                       actual,
-                                       expected
-                               ),
-                               actual,
-                               expected,
-                               message
-                       );
+                       this.pushResult( {
+                               result: !QUnit.equiv( actual, expected ),
+                               actual: actual,
+                               expected: expected,
+                               message: message,
+                               negative: true
+                       } );
                }
        };
 
         * Small test suite to confirm proper functionality of the utilities and
         * initializations defined above in this file.
         */
-       QUnit.module( 'test.mediawiki.qunit.testrunner', QUnit.newMwEnvironment( {
+       QUnit.module( 'testrunner', QUnit.newMwEnvironment( {
                setup: function () {
                        this.mwHtmlLive = mw.html;
                        mw.html = {
                assert.deepEqual( missing, [], 'Modules in missing state' );
        } );
 
-       QUnit.test( 'htmlEqual', function ( assert ) {
+       QUnit.test( 'assert.htmlEqual', function ( assert ) {
                assert.htmlEqual(
                        '<div><p class="some classes" data-length="10">Child paragraph with <a href="http://example.com">A link</a></p>Regular text<span>A span</span></div>',
                        '<div><p data-length=\'10\'  class=\'some classes\'>Child paragraph with <a href=\'http://example.com\' >A link</a></p>Regular text<span>A span</span></div>',
                        'foo<a href="http://example.com">example</a>quux',
                        'Outer text nodes are compared (last text node different)'
                );
-
        } );
 
-       QUnit.module( 'test.mediawiki.qunit.testrunner-after', QUnit.newMwEnvironment() );
+       QUnit.module( 'testrunner-after', QUnit.newMwEnvironment() );
 
        QUnit.test( 'Teardown', function ( assert ) {
                assert.equal( mw.html.escape( '<' ), '&lt;', 'teardown() callback was ran.' );
                assert.equal( mw.messages.get( 'testMsg' ), null, 'messages object restored to live in next module()' );
        } );
 
+       QUnit.module( 'testrunner-each', {
+               beforeEach: function () {
+                       this.mwHtmlLive = mw.html;
+               },
+               afterEach: function () {
+                       mw.html = this.mwHtmlLive;
+               }
+       } );
+       QUnit.test( 'beforeEach', function ( assert ) {
+               assert.ok( this.mwHtmlLive, 'setup() ran' );
+               mw.html = null;
+       } );
+       QUnit.test( 'afterEach', function ( assert ) {
+               assert.equal( mw.html.escape( '<' ), '&lt;', 'afterEach() ran' );
+       } );
+
+       QUnit.module( 'testrunner-each-compat', {
+               setup: function () {
+                       this.mwHtmlLive = mw.html;
+               },
+               teardown: function () {
+                       mw.html = this.mwHtmlLive;
+               }
+       } );
+       QUnit.test( 'setup', function ( assert ) {
+               assert.ok( this.mwHtmlLive, 'setup() ran' );
+               mw.html = null;
+       } );
+       QUnit.test( 'teardown', function ( assert ) {
+               assert.equal( mw.html.escape( '<' ), '&lt;', 'teardown() ran' );
+       } );
+
+       // Regression test for 'this.sandbox undefined' error, fixed by
+       // ensuring Sinon setup/teardown is not re-run on inner module.
+       QUnit.module( 'testrunner-nested', function () {
+               QUnit.module( 'testrunner-nested-inner', function () {
+                       QUnit.test( 'Dummy', function ( assert ) {
+                               assert.ok( true, 'Nested modules supported' );
+                       } );
+               } );
+       } );
+
 }( jQuery, mediaWiki, QUnit ) );