Merge "Title: Don't create mSubpages member variable"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 25 Jul 2017 15:03:41 +0000 (15:03 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 25 Jul 2017 15:03:41 +0000 (15:03 +0000)
195 files changed:
composer.json
includes/Block.php
includes/EditPage.php
includes/Feed.php
includes/FileDeleteForm.php
includes/HistoryBlob.php
includes/LinkFilter.php
includes/Linker.php
includes/MWNamespace.php
includes/MagicWord.php
includes/MediaWiki.php
includes/MimeMagic.php
includes/Preferences.php
includes/Revision.php
includes/Sanitizer.php
includes/ServiceWiring.php
includes/Setup.php
includes/SiteStats.php
includes/Title.php
includes/WikiMap.php
includes/Xml.php
includes/actions/Action.php
includes/api/ApiBase.php
includes/api/ApiEmailUser.php
includes/api/ApiMain.php
includes/api/ApiPageSet.php
includes/api/ApiQueryImageInfo.php
includes/api/ApiQueryInfo.php
includes/api/ApiResult.php
includes/api/ApiUsageException.php
includes/api/i18n/zh-hant.json
includes/auth/AuthenticationResponse.php
includes/cache/MessageCache.php
includes/changes/ChangesFeed.php
includes/changes/EnhancedChangesList.php
includes/changes/RecentChange.php
includes/collation/IcuCollation.php
includes/collation/NumericUppercaseCollation.php
includes/config/EtcdConfig.php
includes/content/ContentHandler.php
includes/context/DerivativeContext.php
includes/db/CloneDatabase.php
includes/debug/MWDebug.php
includes/deferred/LinksUpdate.php
includes/deferred/SearchUpdate.php
includes/diff/DifferenceEngine.php
includes/exception/HttpError.php
includes/export/WikiExporter.php
includes/filerepo/ForeignAPIRepo.php
includes/htmlform/HTMLForm.php
includes/http/Http.php
includes/import/ImportStreamSource.php
includes/installer/DatabaseUpdater.php
includes/installer/WebInstaller.php
includes/installer/i18n/csb.json
includes/jobqueue/JobQueue.php
includes/libs/CSSMin.php
includes/libs/IP.php
includes/libs/StringUtils.php
includes/libs/objectcache/APCBagOStuff.php
includes/libs/objectcache/APCUBagOStuff.php
includes/libs/objectcache/MemcachedPeclBagOStuff.php
includes/libs/objectcache/MultiWriteBagOStuff.php
includes/libs/rdbms/loadbalancer/ILoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/logging/LogPage.php
includes/logging/LogPager.php
includes/mail/UserMailer.php
includes/media/DjVuImage.php
includes/media/Exif.php
includes/media/SVGMetadataExtractor.php
includes/page/Article.php
includes/page/WikiPage.php
includes/pager/IndexPager.php
includes/parser/Parser.php
includes/parser/ParserOptions.php
includes/parser/ParserOutput.php
includes/profiler/output/ProfilerOutput.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderClientHtml.php
includes/resourceloader/ResourceLoaderModule.php
includes/search/SearchDatabase.php
includes/skins/Skin.php
includes/specialpage/SpecialPage.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/SpecialSpecialpages.php
includes/specials/SpecialUpload.php
includes/specials/pagers/UsersPager.php
includes/tidy/Balancer.php
includes/tidy/RemexCompatMunger.php
includes/user/BotPassword.php
includes/user/User.php
languages/ConverterRule.php
languages/Language.php
languages/i18n/ast.json
languages/i18n/ba.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bs.json
languages/i18n/cdo.json
languages/i18n/cs.json
languages/i18n/csb.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/din.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/eu.json
languages/i18n/fr.json
languages/i18n/frr.json
languages/i18n/gl.json
languages/i18n/gor.json
languages/i18n/gsw.json
languages/i18n/hak.json
languages/i18n/he.json
languages/i18n/hi.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/nap.json
languages/i18n/nn.json
languages/i18n/pl.json
languages/i18n/pnb.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.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
languages/i18n/zh-hant.json
maintenance/Maintenance.php
maintenance/generateSitemap.php
maintenance/language/checkLanguage.inc
maintenance/sqlite.inc
maintenance/userOptions.inc
phpcs.xml
resources/Resources.php
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/dm/mw.rcfilters.dm.ItemModel.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.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
resources/src/mediawiki.widgets.visibleByteLimit/mediawiki.widgets.visibleByteLimit.js
resources/src/mediawiki/mediawiki.hlist-allskins.less [new file with mode: 0644]
resources/src/mediawiki/mediawiki.hlist.css
resources/src/oojs-ui-local.js
tests/parser/ParserTestRunner.php
tests/phpunit/ResourceLoaderTestCase.php
tests/phpunit/includes/DeprecatedGlobalTest.php
tests/phpunit/includes/GitInfoTest.php
tests/phpunit/includes/PreferencesTest.php
tests/phpunit/includes/api/ApiErrorFormatterTest.php
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/config/ConfigFactoryTest.php
tests/phpunit/includes/config/EtcdConfigTest.php
tests/phpunit/includes/content/WikitextContentTest.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/CSSMinTest.php
tests/phpunit/includes/libs/objectcache/MultiWriteBagOStuffTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseDomainTest.php
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/page/WikiPageTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderClientHtmlTest.php
tests/phpunit/includes/site/TestSites.php
tests/phpunit/includes/specials/SpecialRecentchangesTest.php
tests/phpunit/structure/DatabaseIntegrationTest.php [new file with mode: 0644]
tests/phpunit/suite.xml
tests/qunit/data/testrunner.js
tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js

index 83fcda0..d04e9f5 100644 (file)
@@ -53,7 +53,7 @@
                "jakub-onderka/php-parallel-lint": "0.9.2",
                "jetbrains/phpstorm-stubs": "dev-master#1b9906084d6635456fcf3f3a01f0d7d5b99a578a",
                "justinrainbow/json-schema": "~5.2",
-               "mediawiki/mediawiki-codesniffer": "0.8.1",
+               "mediawiki/mediawiki-codesniffer": "0.10.1",
                "monolog/monolog": "~1.22.1",
                "nikic/php-parser": "2.1.0",
                "nmred/kafka-php": "0.1.5",
index 2c935df..2a04879 100644 (file)
@@ -485,7 +485,7 @@ class Block {
 
                # Periodic purge via commit hooks
                if ( mt_rand( 0, 9 ) == 0 ) {
-                       Block::purgeExpired();
+                       self::purgeExpired();
                }
 
                $row = $this->getDatabaseArray();
@@ -778,12 +778,12 @@ class Block {
                # It's okay to autoblock. Go ahead and insert/update the block...
 
                # Do not add a *new* block if the IP is already blocked.
-               $ipblock = Block::newFromTarget( $autoblockIP );
+               $ipblock = self::newFromTarget( $autoblockIP );
                if ( $ipblock ) {
                        # Check if the block is an autoblock and would exceed the user block
                        # if renewed. If so, do nothing, otherwise prolong the block time...
                        if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
-                               $this->mExpiry > Block::getAutoblockExpiry( $ipblock->mTimestamp )
+                               $this->mExpiry > self::getAutoblockExpiry( $ipblock->mTimestamp )
                        ) {
                                # Reset block timestamp to now and its expiry to
                                # $wgAutoblockExpiry in the future
@@ -810,11 +810,11 @@ class Block {
 
                if ( $this->mExpiry == 'infinity' ) {
                        # Original block was indefinite, start an autoblock now
-                       $autoblock->mExpiry = Block::getAutoblockExpiry( $timestamp );
+                       $autoblock->mExpiry = self::getAutoblockExpiry( $timestamp );
                } else {
                        # If the user is already blocked with an expiry date, we don't
                        # want to pile on top of that.
-                       $autoblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $timestamp ) );
+                       $autoblock->mExpiry = min( $this->mExpiry, self::getAutoblockExpiry( $timestamp ) );
                }
 
                # Insert the block...
@@ -870,7 +870,7 @@ class Block {
        public function updateTimestamp() {
                if ( $this->mAuto ) {
                        $this->mTimestamp = wfTimestamp();
-                       $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
+                       $this->mExpiry = self::getAutoblockExpiry( $this->mTimestamp );
 
                        $dbw = wfGetDB( DB_MASTER );
                        $dbw->update( 'ipblocks',
@@ -1111,8 +1111,8 @@ class Block {
         */
        public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
                list( $target, $type ) = self::parseTarget( $specificTarget );
-               if ( $type == Block::TYPE_ID || $type == Block::TYPE_AUTO ) {
-                       return Block::newFromID( $target );
+               if ( $type == self::TYPE_ID || $type == self::TYPE_AUTO ) {
+                       return self::newFromID( $target );
 
                } elseif ( $target === null && $vagueTarget == '' ) {
                        # We're not going to find anything useful here
@@ -1122,7 +1122,7 @@ class Block {
 
                } elseif ( in_array(
                        $type,
-                       [ Block::TYPE_USER, Block::TYPE_IP, Block::TYPE_RANGE, null ] )
+                       [ self::TYPE_USER, self::TYPE_IP, self::TYPE_RANGE, null ] )
                ) {
                        $block = new Block();
                        $block->fromMaster( $fromMaster );
@@ -1189,7 +1189,7 @@ class Block {
                }
                $selectFields = array_merge(
                        [ 'ipb_range_start', 'ipb_range_end' ],
-                       Block::selectFields()
+                       self::selectFields()
                );
                $rows = $db->select( 'ipblocks',
                        $selectFields,
@@ -1350,12 +1350,12 @@ class Block {
                        # off validation checking (which would exclude IP addresses)
                        return [
                                User::newFromName( IP::sanitizeIP( $target ), false ),
-                               Block::TYPE_IP
+                               self::TYPE_IP
                        ];
 
                } elseif ( IP::isValidBlock( $target ) ) {
                        # Can't create a User from an IP range
-                       return [ IP::sanitizeRange( $target ), Block::TYPE_RANGE ];
+                       return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
                }
 
                # Consider the possibility that this is not a username at all
@@ -1370,11 +1370,11 @@ class Block {
                        # Note that since numbers are valid usernames, a $target of "12345" will be
                        # considered a User.  If you want to pass a block ID, prepend a hash "#12345",
                        # since hash characters are not valid in usernames or titles generally.
-                       return [ $userObj, Block::TYPE_USER ];
+                       return [ $userObj, self::TYPE_USER ];
 
                } elseif ( preg_match( '/^#\d+$/', $target ) ) {
                        # Autoblock reference in the form "#12345"
-                       return [ substr( $target, 1 ), Block::TYPE_AUTO ];
+                       return [ substr( $target, 1 ), self::TYPE_AUTO ];
 
                } else {
                        # WTF?
index 973327b..229a36a 100644 (file)
@@ -2783,7 +2783,7 @@ class EditPage {
                $wgOut->addHTML( $this->editFormTextBeforeContent );
 
                if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) {
-                       $wgOut->addHTML( EditPage::getEditToolbar( $this->mTitle ) );
+                       $wgOut->addHTML( self::getEditToolbar( $this->mTitle ) );
                }
 
                if ( $this->blankArticle ) {
@@ -3492,6 +3492,10 @@ HTML
                }
        }
 
+       /**
+        * Inserts optional text shown below edit and upload forms. Can be used to offer special characters not present on
+        * most keyboards for copying/pasting.
+        */
        protected function showEditTools() {
                global $wgOut;
                $wgOut->addHTML( '<div class="mw-editTools">' .
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 2f50558..790e2be 100644 (file)
@@ -50,7 +50,7 @@ class LinkFilter {
 
                $text = $content->getNativeData();
 
-               $regex = LinkFilter::makeRegex( $filterEntry );
+               $regex = self::makeRegex( $filterEntry );
                return preg_match( $regex, $text );
        }
 
index f2e4ac4..4aae3ba 100644 (file)
@@ -1328,7 +1328,7 @@ class Linker {
                Title $title, $text, $wikiId = null, $options = []
        ) {
                if ( $wikiId !== null && !$title->isExternal() ) {
-                       $link = Linker::makeExternalLink(
+                       $link = self::makeExternalLink(
                                WikiMap::getForeignURL(
                                        $wikiId,
                                        $title->getNamespace() === 0
@@ -1341,7 +1341,7 @@ class Linker {
                                /* escape = */ false // Already escaped
                        );
                } else {
-                       $link = Linker::link( $title, $text, [], [], $options );
+                       $link = self::link( $title, $text, [], [], $options );
                }
 
                return $link;
@@ -2021,7 +2021,7 @@ class Linker {
                }
 
                if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
-                       return Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
+                       return self::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
                } else {
                        if ( $rev->getId() ) {
                                // RevDelete links using revision ID are stable across
@@ -2040,7 +2040,7 @@ class Linker {
                                        'ids' => $rev->getTimestamp()
                                ];
                        }
-                       return Linker::revDeleteLink( $query,
+                       return self::revDeleteLink( $query,
                                $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
                }
        }
index 89cb616..97dba26 100644 (file)
@@ -370,7 +370,7 @@ class MWNamespace {
         */
        public static function getSubjectNamespaces() {
                return array_filter(
-                       MWNamespace::getValidNamespaces(),
+                       self::getValidNamespaces(),
                        'MWNamespace::isSubject'
                );
        }
@@ -383,7 +383,7 @@ class MWNamespace {
         */
        public static function getTalkNamespaces() {
                return array_filter(
-                       MWNamespace::getValidNamespaces(),
+                       self::getValidNamespaces(),
                        'MWNamespace::isTalk'
                );
        }
index ee95918..1703179 100644 (file)
@@ -664,7 +664,7 @@ class MagicWord {
                $search = [];
                $replace = [];
                foreach ( $magicarr as $id => $replacement ) {
-                       $mw = MagicWord::get( $id );
+                       $mw = self::get( $id );
                        $search[] = $mw->getRegex();
                        $replace[] = $replacement;
                }
index 4df4d76..4e47184 100644 (file)
@@ -609,6 +609,7 @@ class MediaWiki {
                        $lbFactory->hasOrMadeRecentMasterChanges( INF )
                ) ? self::getUrlDomainDistance( $output->getRedirect(), $context ) : false;
 
+               $allowHeaders = !( $output->isDisabled() || headers_sent() );
                if ( $urlDomainDistance === 'local' || $urlDomainDistance === 'remote' ) {
                        // OutputPage::output() will be fast; $postCommitWork will not be useful for
                        // masking the latency of syncing DB positions accross all datacenters synchronously.
@@ -616,7 +617,7 @@ class MediaWiki {
                        $flags = $lbFactory::SHUTDOWN_CHRONPROT_ASYNC;
                        $cpPosTime = microtime( true );
                        // Client's next request should see 1+ positions with this DBMasterPos::asOf() time
-                       if ( $urlDomainDistance === 'local' ) {
+                       if ( $urlDomainDistance === 'local' && $allowHeaders ) {
                                // Client will stay on this domain, so set an unobtrusive cookie
                                $expires = time() + ChronologyProtector::POSITION_TTL;
                                $options = [ 'prefix' => '' ];
@@ -633,7 +634,7 @@ class MediaWiki {
                        // OutputPage::output() is fairly slow; run it in $postCommitWork to mask
                        // the latency of syncing DB positions accross all datacenters synchronously
                        $flags = $lbFactory::SHUTDOWN_CHRONPROT_SYNC;
-                       if ( $lbFactory->hasOrMadeRecentMasterChanges( INF ) ) {
+                       if ( $lbFactory->hasOrMadeRecentMasterChanges( INF ) && $allowHeaders ) {
                                $cpPosTime = microtime( true );
                                // Set a cookie in case the DB position store cannot sync accross datacenters.
                                // This will at least cover the common case of the user staying on the domain.
index 8670729..a2a44bb 100644 (file)
@@ -35,7 +35,7 @@ class MimeMagic extends MimeAnalyzer {
                $instance = MediaWikiServices::getInstance()->getMimeAnalyzer();
                Assert::postcondition(
                        $instance instanceof MimeMagic,
-                       __METHOD__ . ' should return an instance of ' . MimeMagic::class
+                       __METHOD__ . ' should return an instance of ' . self::class
                );
                return $instance;
        }
index 008963b..7efbef1 100644 (file)
@@ -1316,7 +1316,7 @@ class Preferences {
                $formClass = 'PreferencesForm',
                array $remove = []
        ) {
-               $formDescriptor = Preferences::getPreferences( $user, $context );
+               $formDescriptor = self::getPreferences( $user, $context );
                if ( count( $remove ) ) {
                        $removeKeys = array_flip( $remove );
                        $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
index c3782ba..537b7c1 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
@@ -1004,7 +1002,7 @@ class Revision implements IDBAccessObject {
 
                return RecentChange::newFromConds(
                        [
-                               'rc_user_text' => $this->getUserText( Revision::RAW ),
+                               'rc_user_text' => $this->getUserText( self::RAW ),
                                'rc_timestamp' => $dbr->timestamp( $this->getTimestamp() ),
                                'rc_this_oldid' => $this->getId()
                        ],
@@ -1468,7 +1466,7 @@ class Revision implements IDBAccessObject {
                                ? $this->getPreviousRevisionId( $dbw )
                                : $this->mParentId,
                        'rev_sha1'       => $this->mSha1 === null
-                               ? Revision::base36Sha1( $this->mText )
+                               ? self::base36Sha1( $this->mText )
                                : $this->mSha1,
                ];
 
@@ -1557,7 +1555,7 @@ class Revision implements IDBAccessObject {
                        }
                }
 
-               $content = $this->getContent( Revision::RAW );
+               $content = $this->getContent( self::RAW );
                $prefixedDBkey = $title->getPrefixedDBkey();
                $revId = $this->mId;
 
index b08bc69..2def06a 100644 (file)
@@ -465,7 +465,7 @@ class Sanitizer {
                extract( self::getRecognizedTagData( $extratags, $removetags ) );
 
                # Remove HTML comments
-               $text = Sanitizer::removeHTMLcomments( $text );
+               $text = self::removeHTMLcomments( $text );
                $bits = explode( '<', $text );
                $text = str_replace( '>', '&gt;', array_shift( $bits ) );
                if ( !MWTidy::isEnabled() ) {
@@ -583,12 +583,12 @@ class Sanitizer {
                                                        call_user_func_array( $processCallback, [ &$params, $args ] );
                                                }
 
-                                               if ( !Sanitizer::validateTag( $params, $t ) ) {
+                                               if ( !self::validateTag( $params, $t ) ) {
                                                        $badtag = true;
                                                }
 
                                                # Strip non-approved attributes from the tag
-                                               $newparams = Sanitizer::fixTagAttributes( $params, $t );
+                                               $newparams = self::fixTagAttributes( $params, $t );
                                        }
                                        if ( !$badtag ) {
                                                $rest = str_replace( '>', '&gt;', $rest );
@@ -629,11 +629,11 @@ class Sanitizer {
                                                                call_user_func_array( $warnCallback, [ 'deprecated-self-close-category' ] );
                                                        }
                                                }
-                                               if ( !Sanitizer::validateTag( $params, $t ) ) {
+                                               if ( !self::validateTag( $params, $t ) ) {
                                                        $badtag = true;
                                                }
 
-                                               $newparams = Sanitizer::fixTagAttributes( $params, $t );
+                                               $newparams = self::fixTagAttributes( $params, $t );
                                                if ( !$badtag ) {
                                                        if ( $brace === '/>' && !isset( $htmlsingleonly[$t] ) ) {
                                                                # Interpret self-closing tags as empty tags even when
@@ -710,7 +710,7 @@ class Sanitizer {
         * @return bool
         */
        static function validateTag( $params, $element ) {
-               $params = Sanitizer::decodeTagAttributes( $params );
+               $params = self::decodeTagAttributes( $params );
 
                if ( $element == 'meta' || $element == 'link' ) {
                        if ( !isset( $params['itemprop'] ) ) {
@@ -746,8 +746,8 @@ class Sanitizer {
         * @todo Check for unique id attribute :P
         */
        static function validateTagAttributes( $attribs, $element ) {
-               return Sanitizer::validateAttributes( $attribs,
-                       Sanitizer::attributeWhitelist( $element ) );
+               return self::validateAttributes( $attribs,
+                       self::attributeWhitelist( $element ) );
        }
 
        /**
@@ -795,12 +795,12 @@ class Sanitizer {
                        # Strip javascript "expression" from stylesheets.
                        # https://msdn.microsoft.com/en-us/library/ms537634.aspx
                        if ( $attribute == 'style' ) {
-                               $value = Sanitizer::checkCss( $value );
+                               $value = self::checkCss( $value );
                        }
 
                        # Escape HTML id attributes
                        if ( $attribute === 'id' ) {
-                               $value = Sanitizer::escapeId( $value, 'noninitial' );
+                               $value = self::escapeId( $value, 'noninitial' );
                        }
 
                        # Escape HTML id reference lists
@@ -809,7 +809,7 @@ class Sanitizer {
                                || $attribute === 'aria-labelledby'
                                || $attribute === 'aria-owns'
                        ) {
-                               $value = Sanitizer::escapeIdReferenceList( $value, 'noninitial' );
+                               $value = self::escapeIdReferenceList( $value, 'noninitial' );
                        }
 
                        // RDFa and microdata properties allow URLs, URIs and/or CURIs.
@@ -907,7 +907,7 @@ class Sanitizer {
         */
        public static function normalizeCss( $value ) {
                // Decode character references like &#123;
-               $value = Sanitizer::decodeCharReferences( $value );
+               $value = self::decodeCharReferences( $value );
 
                // Decode escape sequences and line continuation
                // See the grammar in the CSS 2 spec, appendix D.
@@ -1087,14 +1087,14 @@ class Sanitizer {
                        return '';
                }
 
-               $decoded = Sanitizer::decodeTagAttributes( $text );
-               $stripped = Sanitizer::validateTagAttributes( $decoded, $element );
+               $decoded = self::decodeTagAttributes( $text );
+               $stripped = self::validateTagAttributes( $decoded, $element );
 
                if ( $sorted ) {
                        ksort( $stripped );
                }
 
-               return Sanitizer::safeEncodeTagAttributes( $stripped );
+               return self::safeEncodeTagAttributes( $stripped );
        }
 
        /**
@@ -1124,7 +1124,7 @@ class Sanitizer {
         * @return string HTML-encoded text fragment
         */
        static function safeEncodeAttribute( $text ) {
-               $encValue = Sanitizer::encodeAttribute( $text );
+               $encValue = self::encodeAttribute( $text );
 
                # Templates and links may be expanded in later parsing,
                # creating invalid or dangerous output. Suppress this.
@@ -1186,7 +1186,7 @@ class Sanitizer {
                global $wgExperimentalHtmlIds;
                $options = (array)$options;
 
-               $id = Sanitizer::decodeCharReferences( $id );
+               $id = self::decodeCharReferences( $id );
 
                if ( $wgExperimentalHtmlIds && !in_array( 'legacy', $options ) ) {
                        $id = preg_replace( '/[ \t\n\r\f_\'"&#%]+/', '_', $id );
@@ -1238,7 +1238,7 @@ class Sanitizer {
 
                # Escape each token as an id
                foreach ( $references as &$ref ) {
-                       $ref = Sanitizer::escapeId( $ref, $options );
+                       $ref = self::escapeId( $ref, $options );
                }
 
                # Merge the array back to a space delimited list string
@@ -1275,7 +1275,7 @@ class Sanitizer {
         * @return string Escaped input
         */
        static function escapeHtmlAllowEntities( $html ) {
-               $html = Sanitizer::decodeCharReferences( $html );
+               $html = self::decodeCharReferences( $html );
                # It seems wise to escape ' as well as ", as a matter of course.  Can't
                # hurt. Use ENT_SUBSTITUTE so that incorrectly truncated multibyte characters
                # don't cause the entire string to disappear.
@@ -1317,14 +1317,14 @@ class Sanitizer {
 
                foreach ( $pairs as $set ) {
                        $attribute = strtolower( $set[1] );
-                       $value = Sanitizer::getTagAttributeCallback( $set );
+                       $value = self::getTagAttributeCallback( $set );
 
                        // Normalize whitespace
                        $value = preg_replace( '/[\t\r\n ]+/', ' ', $value );
                        $value = trim( $value );
 
                        // Decode character references
-                       $attribs[$attribute] = Sanitizer::decodeCharReferences( $value );
+                       $attribs[$attribute] = self::decodeCharReferences( $value );
                }
                return $attribs;
        }
@@ -1340,7 +1340,7 @@ class Sanitizer {
                $attribs = [];
                foreach ( $assoc_array as $attribute => $value ) {
                        $encAttribute = htmlspecialchars( $attribute );
-                       $encValue = Sanitizer::safeEncodeAttribute( $value );
+                       $encValue = self::safeEncodeAttribute( $value );
 
                        $attribs[] = "$encAttribute=\"$encValue\"";
                }
@@ -1427,11 +1427,11 @@ class Sanitizer {
        static function normalizeCharReferencesCallback( $matches ) {
                $ret = null;
                if ( $matches[1] != '' ) {
-                       $ret = Sanitizer::normalizeEntity( $matches[1] );
+                       $ret = self::normalizeEntity( $matches[1] );
                } elseif ( $matches[2] != '' ) {
-                       $ret = Sanitizer::decCharReference( $matches[2] );
+                       $ret = self::decCharReference( $matches[2] );
                } elseif ( $matches[3] != '' ) {
-                       $ret = Sanitizer::hexCharReference( $matches[3] );
+                       $ret = self::hexCharReference( $matches[3] );
                }
                if ( is_null( $ret ) ) {
                        return htmlspecialchars( $matches[0] );
@@ -1468,7 +1468,7 @@ class Sanitizer {
         */
        static function decCharReference( $codepoint ) {
                $point = intval( $codepoint );
-               if ( Sanitizer::validateCodepoint( $point ) ) {
+               if ( self::validateCodepoint( $point ) ) {
                        return sprintf( '&#%d;', $point );
                } else {
                        return null;
@@ -1481,7 +1481,7 @@ class Sanitizer {
         */
        static function hexCharReference( $codepoint ) {
                $point = hexdec( $codepoint );
-               if ( Sanitizer::validateCodepoint( $point ) ) {
+               if ( self::validateCodepoint( $point ) ) {
                        return sprintf( '&#x%x;', $point );
                } else {
                        return null;
@@ -1550,11 +1550,11 @@ class Sanitizer {
         */
        static function decodeCharReferencesCallback( $matches ) {
                if ( $matches[1] != '' ) {
-                       return Sanitizer::decodeEntity( $matches[1] );
+                       return self::decodeEntity( $matches[1] );
                } elseif ( $matches[2] != '' ) {
-                       return Sanitizer::decodeChar( intval( $matches[2] ) );
+                       return self::decodeChar( intval( $matches[2] ) );
                } elseif ( $matches[3] != '' ) {
-                       return Sanitizer::decodeChar( hexdec( $matches[3] ) );
+                       return self::decodeChar( hexdec( $matches[3] ) );
                }
                # Last case should be an ampersand by itself
                return $matches[0];
@@ -1568,7 +1568,7 @@ class Sanitizer {
         * @private
         */
        static function decodeChar( $codepoint ) {
-               if ( Sanitizer::validateCodepoint( $codepoint ) ) {
+               if ( self::validateCodepoint( $codepoint ) ) {
                        return UtfNormal\Utils::codepointToUtf8( $codepoint );
                } else {
                        return UtfNormal\Constants::UTF8_REPLACEMENT;
@@ -1601,7 +1601,7 @@ class Sanitizer {
         * @return array
         */
        static function attributeWhitelist( $element ) {
-               $list = Sanitizer::setupAttributeWhitelist();
+               $list = self::setupAttributeWhitelist();
                return isset( $list[$element] )
                        ? $list[$element]
                        : [];
@@ -1876,7 +1876,7 @@ class Sanitizer {
        static function cleanUrl( $url ) {
                # Normalize any HTML entities in input. They will be
                # re-escaped by makeExternalLink().
-               $url = Sanitizer::decodeCharReferences( $url );
+               $url = self::decodeCharReferences( $url );
 
                # Escape any control characters introduced by the above step
                $url = preg_replace_callback( '/[\][<>"\\x00-\\x20\\x7F\|]/',
index e1244e7..d048007 100644 (file)
@@ -287,7 +287,7 @@ return [
                return ObjectFactory::constructClassInstance( $conf['class'], [ $conf ] );
        },
 
-       'ParserCache' => function( MediaWikiServices $services ) {
+       'ParserCache' => function ( MediaWikiServices $services ) {
                $config = $services->getMainConfig();
                $cache = ObjectCache::getInstance( $config->get( 'ParserCacheType' ) );
                wfDebugLog( 'caches', 'parser: ' . get_class( $cache ) );
@@ -298,7 +298,7 @@ return [
                );
        },
 
-       'LinkCache' => function( MediaWikiServices $services ) {
+       'LinkCache' => function ( MediaWikiServices $services ) {
                return new LinkCache(
                        $services->getTitleFormatter(),
                        $services->getMainWANObjectCache()
index ac00fab..3d5bee2 100644 (file)
@@ -687,7 +687,7 @@ $messageMemc = wfGetMessageCacheStorage();
 /**
  * @deprecated since 1.30
  */
-$parserMemc = new DeprecatedGlobal( 'parserMemc', function() {
+$parserMemc = new DeprecatedGlobal( 'parserMemc', function () {
        return MediaWikiServices::getInstance()->getParserCache()->getCacheStorage();
 }, '1.30' );
 
index 6ce1aed..df3e305 100644 (file)
@@ -222,13 +222,6 @@ class SiteStats {
                        } catch ( JobQueueError $e ) {
                                self::$jobs = 0;
                        }
-                       /**
-                        * Zero rows still do single row read for row that doesn't exist,
-                        * but people are annoyed by that
-                        */
-                       if ( self::$jobs == 1 ) {
-                               self::$jobs = 0;
-                       }
                }
                return self::$jobs;
        }
@@ -296,7 +289,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 0728065..edfdaca 100644 (file)
@@ -272,7 +272,7 @@ class Title implements LinkTarget {
                }
 
                try {
-                       return Title::newFromTextThrow( strval( $text ), $defaultNamespace );
+                       return self::newFromTextThrow( strval( $text ), $defaultNamespace );
                } catch ( MalformedTitleException $ex ) {
                        return null;
                }
@@ -411,7 +411,7 @@ class Title implements LinkTarget {
                        __METHOD__
                );
                if ( $row !== false ) {
-                       $title = Title::newFromRow( $row );
+                       $title = self::newFromRow( $row );
                } else {
                        $title = null;
                }
@@ -439,7 +439,7 @@ class Title implements LinkTarget {
 
                $titles = [];
                foreach ( $res as $row ) {
-                       $titles[] = Title::newFromRow( $row );
+                       $titles[] = self::newFromRow( $row );
                }
                return $titles;
        }
@@ -541,7 +541,7 @@ class Title implements LinkTarget {
                }
 
                $t = new Title();
-               $t->mDbkeyform = Title::makeName( $ns, $title, $fragment, $interwiki, true );
+               $t->mDbkeyform = self::makeName( $ns, $title, $fragment, $interwiki, true );
 
                try {
                        $t->secureAndSplit();
@@ -557,10 +557,10 @@ class Title implements LinkTarget {
         * @return Title The new object
         */
        public static function newMainPage() {
-               $title = Title::newFromText( wfMessage( 'mainpage' )->inContentLanguage()->text() );
+               $title = self::newFromText( wfMessage( 'mainpage' )->inContentLanguage()->text() );
                // Don't give fatal errors if the message is broken
                if ( !$title ) {
-                       $title = Title::newFromText( 'Main Page' );
+                       $title = self::newFromText( 'Main Page' );
                }
                return $title;
        }
@@ -933,7 +933,7 @@ class Title implements LinkTarget {
         */
        public function getContentModel( $flags = 0 ) {
                if ( !$this->mForcedContentModel
-                       && ( !$this->mContentModel || $flags === Title::GAID_FOR_UPDATE )
+                       && ( !$this->mContentModel || $flags === self::GAID_FOR_UPDATE )
                        && $this->getArticleID( $flags )
                ) {
                        $linkCache = LinkCache::singleton();
@@ -1096,7 +1096,7 @@ class Title implements LinkTarget {
                        if ( $canonicalName ) {
                                $localName = SpecialPageFactory::getLocalNameFor( $canonicalName, $par );
                                if ( $localName != $this->mDbkeyform ) {
-                                       return Title::makeTitle( NS_SPECIAL, $localName );
+                                       return self::makeTitle( NS_SPECIAL, $localName );
                                }
                        }
                }
@@ -1195,7 +1195,7 @@ class Title implements LinkTarget {
         * @return bool
         */
        public function isMainPage() {
-               return $this->equals( Title::newMainPage() );
+               return $this->equals( self::newMainPage() );
        }
 
        /**
@@ -1313,7 +1313,7 @@ class Title implements LinkTarget {
         * @return Title The object for the talk page
         */
        public function getTalkPage() {
-               return Title::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
+               return self::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
        }
 
        /**
@@ -1328,7 +1328,7 @@ class Title implements LinkTarget {
                if ( $this->getNamespace() == $subjectNS ) {
                        return $this;
                }
-               return Title::makeTitle( $subjectNS, $this->getDBkey() );
+               return self::makeTitle( $subjectNS, $this->getDBkey() );
        }
 
        /**
@@ -1388,7 +1388,7 @@ class Title implements LinkTarget {
                if ( !$this->hasFragment() ) {
                        return '';
                } else {
-                       return '#' . Title::escapeFragmentForURL( $this->getFragment() );
+                       return '#' . self::escapeFragmentForURL( $this->getFragment() );
                }
        }
 
@@ -1535,7 +1535,7 @@ class Title implements LinkTarget {
         * @since 1.20
         */
        public function getRootTitle() {
-               return Title::makeTitle( $this->getNamespace(), $this->getRootText() );
+               return self::makeTitle( $this->getNamespace(), $this->getRootText() );
        }
 
        /**
@@ -1575,7 +1575,7 @@ class Title implements LinkTarget {
         * @since 1.20
         */
        public function getBaseTitle() {
-               return Title::makeTitle( $this->getNamespace(), $this->getBaseText() );
+               return self::makeTitle( $this->getNamespace(), $this->getBaseText() );
        }
 
        /**
@@ -1611,7 +1611,7 @@ class Title implements LinkTarget {
         * @since 1.20
         */
        public function getSubpage( $text ) {
-               return Title::makeTitleSafe( $this->getNamespace(), $this->getText() . '/' . $text );
+               return self::makeTitleSafe( $this->getNamespace(), $this->getText() . '/' . $text );
        }
 
        /**
@@ -2847,7 +2847,7 @@ class Title implements LinkTarget {
                                        $page_id = $row->pr_page;
                                        $page_ns = $row->page_namespace;
                                        $page_title = $row->page_title;
-                                       $sources[$page_id] = Title::makeTitle( $page_ns, $page_title );
+                                       $sources[$page_id] = self::makeTitle( $page_ns, $page_title );
                                        # Add groups needed for each restriction type if its not already there
                                        # Make sure this restriction type still exists
 
@@ -3328,7 +3328,7 @@ class Title implements LinkTarget {
         * @return int Int or 0 if the page doesn't exist
         */
        public function getLatestRevID( $flags = 0 ) {
-               if ( !( $flags & Title::GAID_FOR_UPDATE ) && $this->mLatestID !== false ) {
+               if ( !( $flags & self::GAID_FOR_UPDATE ) && $this->mLatestID !== false ) {
                        return intval( $this->mLatestID );
                }
                if ( !$this->getArticleID( $flags ) ) {
@@ -3488,7 +3488,7 @@ class Title implements LinkTarget {
                if ( $res->numRows() ) {
                        $linkCache = LinkCache::singleton();
                        foreach ( $res as $row ) {
-                               $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title );
+                               $titleObj = self::makeTitle( $row->page_namespace, $row->page_title );
                                if ( $titleObj ) {
                                        $linkCache->addGoodLinkObjFromRow( $titleObj, $row );
                                        $retVal[] = $titleObj;
@@ -3556,9 +3556,9 @@ class Title implements LinkTarget {
                $linkCache = LinkCache::singleton();
                foreach ( $res as $row ) {
                        if ( $row->page_id ) {
-                               $titleObj = Title::newFromRow( $row );
+                               $titleObj = self::newFromRow( $row );
                        } else {
-                               $titleObj = Title::makeTitle( $row->$blNamespace, $row->$blTitle );
+                               $titleObj = self::makeTitle( $row->$blNamespace, $row->$blTitle );
                                $linkCache->addBadLinkObj( $titleObj );
                        }
                        $retVal[] = $titleObj;
@@ -3614,7 +3614,7 @@ class Title implements LinkTarget {
 
                $retVal = [];
                foreach ( $res as $row ) {
-                       $retVal[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
+                       $retVal[] = self::makeTitle( $row->pl_namespace, $row->pl_title );
                }
                return $retVal;
        }
@@ -3826,7 +3826,7 @@ class Title implements LinkTarget {
                        }
                        # T16385: we need makeTitleSafe because the new page names may
                        # be longer than 255 characters.
-                       $newSubpage = Title::makeTitleSafe( $newNs, $newPageName );
+                       $newSubpage = self::makeTitleSafe( $newNs, $newPageName );
 
                        $success = $oldSubpage->moveTo( $newSubpage, $auth, $reason, $createRedirect, $changeTags );
                        if ( $success === true ) {
@@ -3988,7 +3988,7 @@ class Title implements LinkTarget {
                                        # Circular reference
                                        $stack[$parent] = [];
                                } else {
-                                       $nt = Title::newFromText( $parent );
+                                       $nt = self::newFromText( $parent );
                                        if ( $nt ) {
                                                $stack[$parent] = $nt->getParentCategoryTree( $children + [ $parent => 1 ] );
                                        }
index a03bc19..6a532e5 100644 (file)
@@ -115,7 +115,7 @@ class WikiMap {
         * @return string|int Wiki's name or $wiki_id if the wiki was not found
         */
        public static function getWikiName( $wikiID ) {
-               $wiki = WikiMap::getWiki( $wikiID );
+               $wiki = self::getWiki( $wikiID );
 
                if ( $wiki ) {
                        return $wiki->getDisplayName();
@@ -166,7 +166,7 @@ class WikiMap {
         * @return string|bool URL or false if the wiki was not found
         */
        public static function getForeignURL( $wikiID, $page, $fragmentId = null ) {
-               $wiki = WikiMap::getWiki( $wikiID );
+               $wiki = self::getWiki( $wikiID );
 
                if ( $wiki ) {
                        return $wiki->getFullUrl( $page, $fragmentId );
index d016433..16a5a9d 100644 (file)
@@ -225,7 +225,7 @@ class Xml {
                $selected = isset( $languages[$selected] ) ? $selected : $wgLanguageCode;
                $options = "\n";
                foreach ( $languages as $code => $name ) {
-                       $options .= Xml::option( "$code - $name", $code, $code == $selected ) . "\n";
+                       $options .= self::option( "$code - $name", $code, $code == $selected ) . "\n";
                }
 
                $attrs = [ 'id' => 'wpUserLanguage', 'name' => 'wpUserLanguage' ];
@@ -235,8 +235,8 @@ class Xml {
                        $msg = wfMessage( 'yourlanguage' );
                }
                return [
-                       Xml::label( $msg->text(), $attrs['id'] ),
-                       Xml::tags( 'select', $attrs, $options )
+                       self::label( $msg->text(), $attrs['id'] ),
+                       self::tags( 'select', $attrs, $options )
                ];
        }
 
@@ -400,7 +400,7 @@ class Xml {
                $value = false, $attribs = []
        ) {
                return [
-                       Xml::label( $label, $id, $attribs ),
+                       self::label( $label, $id, $attribs ),
                        self::input( $name, $size, $value, [ 'id' => $id ] + $attribs )
                ];
        }
@@ -556,11 +556,11 @@ class Xml {
                        $attribs['tabindex'] = $tabindex;
                }
 
-               return Xml::openElement( 'select', $attribs )
+               return self::openElement( 'select', $attribs )
                        . "\n"
                        . $options
                        . "\n"
-                       . Xml::closeElement( 'select' );
+                       . self::closeElement( 'select' );
        }
 
        /**
@@ -575,15 +575,15 @@ class Xml {
         * @return string
         */
        public static function fieldset( $legend = false, $content = false, $attribs = [] ) {
-               $s = Xml::openElement( 'fieldset', $attribs ) . "\n";
+               $s = self::openElement( 'fieldset', $attribs ) . "\n";
 
                if ( $legend ) {
-                       $s .= Xml::element( 'legend', null, $legend ) . "\n";
+                       $s .= self::element( 'legend', null, $legend ) . "\n";
                }
 
                if ( $content !== false ) {
                        $s .= $content . "\n";
-                       $s .= Xml::closeElement( 'fieldset' ) . "\n";
+                       $s .= self::closeElement( 'fieldset' ) . "\n";
                }
 
                return $s;
@@ -644,7 +644,7 @@ class Xml {
         */
        public static function encodeJsCall( $name, $args, $pretty = false ) {
                foreach ( $args as &$arg ) {
-                       $arg = Xml::encodeJsVar( $arg, $pretty );
+                       $arg = self::encodeJsVar( $arg, $pretty );
                        if ( $arg === false ) {
                                return false;
                        }
@@ -702,7 +702,7 @@ class Xml {
                        $text .
                        '</html>';
 
-               return Xml::isWellFormed( $html );
+               return self::isWellFormed( $html );
        }
 
        /**
@@ -736,25 +736,25 @@ class Xml {
 
                foreach ( $fields as $labelmsg => $input ) {
                        $id = "mw-$labelmsg";
-                       $form .= Xml::openElement( 'tr', [ 'id' => $id ] );
+                       $form .= self::openElement( 'tr', [ 'id' => $id ] );
 
                        // TODO use a <label> here for accessibility purposes - will need
                        // to either not use a table to build the form, or find the ID of
                        // the input somehow.
 
-                       $form .= Xml::tags( 'td', [ 'class' => 'mw-label' ], wfMessage( $labelmsg )->parse() );
-                       $form .= Xml::openElement( 'td', [ 'class' => 'mw-input' ] )
-                               . $input . Xml::closeElement( 'td' );
-                       $form .= Xml::closeElement( 'tr' );
+                       $form .= self::tags( 'td', [ 'class' => 'mw-label' ], wfMessage( $labelmsg )->parse() );
+                       $form .= self::openElement( 'td', [ 'class' => 'mw-input' ] )
+                               . $input . self::closeElement( 'td' );
+                       $form .= self::closeElement( 'tr' );
                }
 
                if ( $submitLabel ) {
-                       $form .= Xml::openElement( 'tr' );
-                       $form .= Xml::tags( 'td', [], '' );
-                       $form .= Xml::openElement( 'td', [ 'class' => 'mw-submit' ] )
-                               . Xml::submitButton( wfMessage( $submitLabel )->text(), $submitAttribs )
-                               . Xml::closeElement( 'td' );
-                       $form .= Xml::closeElement( 'tr' );
+                       $form .= self::openElement( 'tr' );
+                       $form .= self::tags( 'td', [], '' );
+                       $form .= self::openElement( 'td', [ 'class' => 'mw-submit' ] )
+                               . self::submitButton( wfMessage( $submitLabel )->text(), $submitAttribs )
+                               . self::closeElement( 'td' );
+                       $form .= self::closeElement( 'tr' );
                }
 
                $form .= "</tbody></table>";
@@ -770,10 +770,10 @@ class Xml {
         * @return string
         */
        public static function buildTable( $rows, $attribs = [], $headers = null ) {
-               $s = Xml::openElement( 'table', $attribs );
+               $s = self::openElement( 'table', $attribs );
 
                if ( is_array( $headers ) ) {
-                       $s .= Xml::openElement( 'thead', $attribs );
+                       $s .= self::openElement( 'thead', $attribs );
 
                        foreach ( $headers as $id => $header ) {
                                $attribs = [];
@@ -782,9 +782,9 @@ class Xml {
                                        $attribs['id'] = $id;
                                }
 
-                               $s .= Xml::element( 'th', $attribs, $header );
+                               $s .= self::element( 'th', $attribs, $header );
                        }
-                       $s .= Xml::closeElement( 'thead' );
+                       $s .= self::closeElement( 'thead' );
                }
 
                foreach ( $rows as $id => $row ) {
@@ -794,10 +794,10 @@ class Xml {
                                $attribs['id'] = $id;
                        }
 
-                       $s .= Xml::buildTableRow( $attribs, $row );
+                       $s .= self::buildTableRow( $attribs, $row );
                }
 
-               $s .= Xml::closeElement( 'table' );
+               $s .= self::closeElement( 'table' );
 
                return $s;
        }
@@ -809,7 +809,7 @@ class Xml {
         * @return string
         */
        public static function buildTableRow( $attribs, $cells ) {
-               $s = Xml::openElement( 'tr', $attribs );
+               $s = self::openElement( 'tr', $attribs );
 
                foreach ( $cells as $id => $cell ) {
                        $attribs = [];
@@ -818,10 +818,10 @@ class Xml {
                                $attribs['id'] = $id;
                        }
 
-                       $s .= Xml::element( 'td', $attribs, $cell );
+                       $s .= self::element( 'td', $attribs, $cell );
                }
 
-               $s .= Xml::closeElement( 'tr' );
+               $s .= self::closeElement( 'tr' );
 
                return $s;
        }
index 88382b6..e8d9a3e 100644 (file)
@@ -151,7 +151,7 @@ abstract class Action implements MessageLocalizer {
                        return 'view';
                }
 
-               $action = Action::factory( $actionName, $context->getWikiPage(), $context );
+               $action = self::factory( $actionName, $context->getWikiPage(), $context );
                if ( $action instanceof Action ) {
                        return $action->getName();
                }
@@ -388,7 +388,7 @@ abstract class Action implements MessageLocalizer {
        public function addHelpLink( $to, $overrideBaseUrl = false ) {
                global $wgContLang;
                $msg = wfMessage( $wgContLang->lc(
-                       Action::getActionName( $this->getContext() )
+                       self::getActionName( $this->getContext() )
                        ) . '-helppage' );
 
                if ( !$msg->isDisabled() ) {
index bc3def8..034d243 100644 (file)
@@ -548,7 +548,7 @@ abstract class ApiBase extends ContextSource {
                // Main module has this method overridden
                // Safety - avoid infinite loop:
                if ( $this->isMain() ) {
-                       ApiBase::dieDebug( __METHOD__, 'base method was called on main module.' );
+                       self::dieDebug( __METHOD__, 'base method was called on main module.' );
                }
 
                return $this->getMain()->lacksSameOriginSecurity();
@@ -620,7 +620,7 @@ abstract class ApiBase extends ContextSource {
                // Main module has getResult() method overridden
                // Safety - avoid infinite loop:
                if ( $this->isMain() ) {
-                       ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
+                       self::dieDebug( __METHOD__, 'base method was called on main module. ' );
                }
 
                return $this->getMain()->getResult();
@@ -634,7 +634,7 @@ abstract class ApiBase extends ContextSource {
                // Main module has getErrorFormatter() method overridden
                // Safety - avoid infinite loop:
                if ( $this->isMain() ) {
-                       ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
+                       self::dieDebug( __METHOD__, 'base method was called on main module. ' );
                }
 
                return $this->getMain()->getErrorFormatter();
@@ -660,7 +660,7 @@ abstract class ApiBase extends ContextSource {
                // Main module has getContinuationManager() method overridden
                // Safety - avoid infinite loop:
                if ( $this->isMain() ) {
-                       ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
+                       self::dieDebug( __METHOD__, 'base method was called on main module. ' );
                }
 
                return $this->getMain()->getContinuationManager();
@@ -674,7 +674,7 @@ abstract class ApiBase extends ContextSource {
                // Main module has setContinuationManager() method overridden
                // Safety - avoid infinite loop:
                if ( $this->isMain() ) {
-                       ApiBase::dieDebug( __METHOD__, 'base method was called on main module. ' );
+                       self::dieDebug( __METHOD__, 'base method was called on main module. ' );
                }
 
                $this->getMain()->setContinuationManager( $manager );
@@ -1059,7 +1059,7 @@ abstract class ApiBase extends ContextSource {
                if ( $type == 'boolean' ) {
                        if ( isset( $default ) && $default !== false ) {
                                // Having a default value of anything other than 'false' is not allowed
-                               ApiBase::dieDebug(
+                               self::dieDebug(
                                        __METHOD__,
                                        "Boolean param $encParamName's default is set to '$default'. " .
                                                'Boolean parameters must default to false.'
@@ -1070,13 +1070,13 @@ abstract class ApiBase extends ContextSource {
                } elseif ( $type == 'upload' ) {
                        if ( isset( $default ) ) {
                                // Having a default value is not allowed
-                               ApiBase::dieDebug(
+                               self::dieDebug(
                                        __METHOD__,
                                        "File upload param $encParamName's default is set to " .
                                                "'$default'. File upload parameters may not have a default." );
                        }
                        if ( $multi ) {
-                               ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
+                               self::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
                        }
                        $value = $this->getMain()->getUpload( $encParamName );
                        if ( !$value->exists() ) {
@@ -1138,7 +1138,7 @@ abstract class ApiBase extends ContextSource {
 
                $allSpecifier = ( is_string( $allowAll ) ? $allowAll : self::ALL_DEFAULT_STRING );
                if ( $allowAll && $multi && is_array( $type ) && in_array( $allSpecifier, $type, true ) ) {
-                       ApiBase::dieDebug(
+                       self::dieDebug(
                                __METHOD__,
                                "For param $encParamName, PARAM_ALL collides with a possible value" );
                }
@@ -1194,13 +1194,13 @@ abstract class ApiBase extends ContextSource {
                                                if ( !isset( $paramSettings[self::PARAM_MAX] )
                                                        || !isset( $paramSettings[self::PARAM_MAX2] )
                                                ) {
-                                                       ApiBase::dieDebug(
+                                                       self::dieDebug(
                                                                __METHOD__,
                                                                "MAX1 or MAX2 are not defined for the limit $encParamName"
                                                        );
                                                }
                                                if ( $multi ) {
-                                                       ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
+                                                       self::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
                                                }
                                                $min = isset( $paramSettings[self::PARAM_MIN] ) ? $paramSettings[self::PARAM_MIN] : 0;
                                                if ( $value == 'max' ) {
@@ -1221,7 +1221,7 @@ abstract class ApiBase extends ContextSource {
                                                break;
                                        case 'boolean':
                                                if ( $multi ) {
-                                                       ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
+                                                       self::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
                                                }
                                                break;
                                        case 'timestamp':
@@ -1255,7 +1255,7 @@ abstract class ApiBase extends ContextSource {
                                                }
                                                break;
                                        default:
-                                               ApiBase::dieDebug( __METHOD__, "Param $encParamName's type is unknown - $type" );
+                                               self::dieDebug( __METHOD__, "Param $encParamName's type is unknown - $type" );
                                }
                        }
 
@@ -2077,19 +2077,19 @@ abstract class ApiBase extends ContextSource {
         * @return Message
         */
        public function getFinalSummary() {
-               $msg = ApiBase::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
+               $msg = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
                        $this->getModulePrefix(),
                        $this->getModuleName(),
                        $this->getModulePath(),
                ] );
                if ( !$msg->exists() ) {
                        wfDeprecated( 'API help "description" messages', '1.30' );
-                       $msg = ApiBase::makeMessage( $this->getDescriptionMessage(), $this->getContext(), [
+                       $msg = self::makeMessage( $this->getDescriptionMessage(), $this->getContext(), [
                                $this->getModulePrefix(),
                                $this->getModuleName(),
                                $this->getModulePath(),
                        ] );
-                       $msg = ApiBase::makeMessage( 'rawmessage', $this->getContext(), [
+                       $msg = self::makeMessage( 'rawmessage', $this->getContext(), [
                                preg_replace( '/\n.*/s', '', $msg->text() )
                        ] );
                }
@@ -2116,12 +2116,12 @@ abstract class ApiBase extends ContextSource {
                        $desc = (string)$desc;
                }
 
-               $summary = ApiBase::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
+               $summary = self::makeMessage( $this->getSummaryMessage(), $this->getContext(), [
                        $this->getModulePrefix(),
                        $this->getModuleName(),
                        $this->getModulePath(),
                ] );
-               $extendedDescription = ApiBase::makeMessage(
+               $extendedDescription = self::makeMessage(
                        $this->getExtendedDescription(), $this->getContext(), [
                                $this->getModulePrefix(),
                                $this->getModuleName(),
@@ -2133,7 +2133,7 @@ abstract class ApiBase extends ContextSource {
                        $msgs = [ $summary, $extendedDescription ];
                } else {
                        wfDeprecated( 'API help "description" messages', '1.30' );
-                       $description = ApiBase::makeMessage( $this->getDescriptionMessage(), $this->getContext(), [
+                       $description = self::makeMessage( $this->getDescriptionMessage(), $this->getContext(), [
                                $this->getModulePrefix(),
                                $this->getModuleName(),
                                $this->getModulePath(),
@@ -2165,10 +2165,10 @@ abstract class ApiBase extends ContextSource {
 
                if ( $this->needsToken() ) {
                        $params['token'] = [
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => true,
-                               ApiBase::PARAM_SENSITIVE => true,
-                               ApiBase::PARAM_HELP_MSG => [
+                               self::PARAM_TYPE => 'string',
+                               self::PARAM_REQUIRED => true,
+                               self::PARAM_SENSITIVE => true,
+                               self::PARAM_HELP_MSG => [
                                        'api-help-param-token',
                                        $this->needsToken(),
                                ],
@@ -2205,7 +2205,7 @@ abstract class ApiBase extends ContextSource {
                }
                $desc = self::escapeWikiText( $desc );
 
-               $params = $this->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
+               $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
                $msgs = [];
                foreach ( $params as $param => $settings ) {
                        if ( !is_array( $settings ) ) {
@@ -2224,15 +2224,15 @@ abstract class ApiBase extends ContextSource {
                                $d = implode( ' ', $d );
                        }
 
-                       if ( isset( $settings[ApiBase::PARAM_HELP_MSG] ) ) {
-                               $msg = $settings[ApiBase::PARAM_HELP_MSG];
+                       if ( isset( $settings[self::PARAM_HELP_MSG] ) ) {
+                               $msg = $settings[self::PARAM_HELP_MSG];
                        } else {
                                $msg = $this->msg( "apihelp-{$path}-param-{$param}" );
                                if ( !$msg->exists() ) {
                                        $msg = $this->msg( 'api-help-fallback-parameter', $d );
                                }
                        }
-                       $msg = ApiBase::makeMessage( $msg, $this->getContext(),
+                       $msg = self::makeMessage( $msg, $this->getContext(),
                                [ $prefix, $param, $name, $path ] );
                        if ( !$msg ) {
                                self::dieDebug( __METHOD__,
@@ -2240,11 +2240,11 @@ abstract class ApiBase extends ContextSource {
                        }
                        $msgs[$param] = [ $msg ];
 
-                       if ( isset( $settings[ApiBase::PARAM_TYPE] ) &&
-                               $settings[ApiBase::PARAM_TYPE] === 'submodule'
+                       if ( isset( $settings[self::PARAM_TYPE] ) &&
+                               $settings[self::PARAM_TYPE] === 'submodule'
                        ) {
-                               if ( isset( $settings[ApiBase::PARAM_SUBMODULE_MAP] ) ) {
-                                       $map = $settings[ApiBase::PARAM_SUBMODULE_MAP];
+                               if ( isset( $settings[self::PARAM_SUBMODULE_MAP] ) ) {
+                                       $map = $settings[self::PARAM_SUBMODULE_MAP];
                                } else {
                                        $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
                                        $map = [];
@@ -2282,29 +2282,29 @@ abstract class ApiBase extends ContextSource {
                                        $arr[] = $m->setContext( $this->getContext() );
                                }
                                $msgs[$param] = array_merge( $msgs[$param], $submodules, $deprecatedSubmodules );
-                       } elseif ( isset( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
-                               if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
+                       } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
+                               if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
                                        self::dieDebug( __METHOD__,
                                                'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
                                }
-                               if ( !is_array( $settings[ApiBase::PARAM_TYPE] ) ) {
+                               if ( !is_array( $settings[self::PARAM_TYPE] ) ) {
                                        self::dieDebug( __METHOD__,
                                                'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
                                                'ApiBase::PARAM_TYPE is an array' );
                                }
 
-                               $valueMsgs = $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE];
-                               $deprecatedValues = isset( $settings[ApiBase::PARAM_DEPRECATED_VALUES] )
-                                       ? $settings[ApiBase::PARAM_DEPRECATED_VALUES]
+                               $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
+                               $deprecatedValues = isset( $settings[self::PARAM_DEPRECATED_VALUES] )
+                                       ? $settings[self::PARAM_DEPRECATED_VALUES]
                                        : [];
 
-                               foreach ( $settings[ApiBase::PARAM_TYPE] as $value ) {
+                               foreach ( $settings[self::PARAM_TYPE] as $value ) {
                                        if ( isset( $valueMsgs[$value] ) ) {
                                                $msg = $valueMsgs[$value];
                                        } else {
                                                $msg = "apihelp-{$path}-paramvalue-{$param}-{$value}";
                                        }
-                                       $m = ApiBase::makeMessage( $msg, $this->getContext(),
+                                       $m = self::makeMessage( $msg, $this->getContext(),
                                                [ $prefix, $param, $name, $path, $value ] );
                                        if ( $m ) {
                                                $m = new ApiHelpParamValueMessage(
@@ -2321,13 +2321,13 @@ abstract class ApiBase extends ContextSource {
                                }
                        }
 
-                       if ( isset( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
-                               if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
+                       if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
+                               if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
                                        self::dieDebug( __METHOD__,
                                                'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
                                }
-                               foreach ( $settings[ApiBase::PARAM_HELP_MSG_APPEND] as $m ) {
-                                       $m = ApiBase::makeMessage( $m, $this->getContext(),
+                               foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
+                                       $m = self::makeMessage( $m, $this->getContext(),
                                                [ $prefix, $param, $name, $path ] );
                                        if ( $m ) {
                                                $msgs[$param][] = $m;
@@ -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 72c7c35..4b4b76b 100644 (file)
@@ -71,7 +71,7 @@ class ApiEmailUser extends ApiBase {
                }
 
                $result = array_filter( [
-                       'result' => $retval->isGood() ? 'Success' : $retval->isOk() ? 'Warnings' : 'Failure',
+                       'result' => $retval->isGood() ? 'Success' : ( $retval->isOk() ? 'Warnings' : 'Failure' ),
                        'warnings' => $this->getErrorFormatter()->arrayFromStatus( $retval, 'warning' ),
                        'errors' => $this->getErrorFormatter()->arrayFromStatus( $retval, 'error' ),
                ] );
index 52f79ee..b7d4529 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'] );
@@ -1829,7 +1829,7 @@ class ApiMain extends ApiBase {
                                ApiBase::PARAM_TYPE => 'submodule',
                        ],
                        'format' => [
-                               ApiBase::PARAM_DFLT => ApiMain::API_DEFAULT_FORMAT,
+                               ApiBase::PARAM_DFLT => self::API_DEFAULT_FORMAT,
                                ApiBase::PARAM_TYPE => 'submodule',
                        ],
                        'maxlag' => [
index 599b3de..cfac761 100644 (file)
@@ -121,7 +121,7 @@ class ApiPageSet extends ApiBase {
        public function __construct( ApiBase $dbSource, $flags = 0, $defaultNamespace = NS_MAIN ) {
                parent::__construct( $dbSource->getMain(), $dbSource->getModuleName() );
                $this->mDbSource = $dbSource;
-               $this->mAllowGenerator = ( $flags & ApiPageSet::DISABLE_GENERATORS ) == 0;
+               $this->mAllowGenerator = ( $flags & self::DISABLE_GENERATORS ) == 0;
                $this->mDefaultNamespace = $defaultNamespace;
 
                $this->mParams = $this->extractRequestParams();
@@ -166,7 +166,7 @@ class ApiPageSet extends ApiBase {
                        }
                        // Create a temporary pageset to store generator's output,
                        // add any additional fields generator may need, and execute pageset to populate titles/pageids
-                       $tmpPageSet = new ApiPageSet( $dbSource, ApiPageSet::DISABLE_GENERATORS );
+                       $tmpPageSet = new ApiPageSet( $dbSource, self::DISABLE_GENERATORS );
                        $generator->setGeneratorMode( $tmpPageSet );
                        $this->mCacheMode = $generator->getCacheMode( $generator->extractRequestParams() );
 
index b2664df..bfd5b17 100644 (file)
@@ -677,7 +677,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
                                ApiBase::PARAM_DFLT => -1,
                                ApiBase::PARAM_HELP_MSG => [
                                        'apihelp-query+imageinfo-param-urlwidth',
-                                       ApiQueryImageInfo::TRANSFORM_LIMIT,
+                                       self::TRANSFORM_LIMIT,
                                ],
                        ],
                        'urlheight' => [
index 6b8f98c..ecdebd4 100644 (file)
@@ -128,7 +128,7 @@ class ApiQueryInfo extends ApiQueryBase {
         * @deprecated since 1.24
         */
        public static function resetTokenCache() {
-               ApiQueryInfo::$cachedTokens = [];
+               self::$cachedTokens = [];
        }
 
        /**
@@ -144,11 +144,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['edit'] ) ) {
-                       ApiQueryInfo::$cachedTokens['edit'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['edit'] ) ) {
+                       self::$cachedTokens['edit'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['edit'];
+               return self::$cachedTokens['edit'];
        }
 
        /**
@@ -161,11 +161,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['delete'] ) ) {
-                       ApiQueryInfo::$cachedTokens['delete'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['delete'] ) ) {
+                       self::$cachedTokens['delete'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['delete'];
+               return self::$cachedTokens['delete'];
        }
 
        /**
@@ -178,11 +178,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['protect'] ) ) {
-                       ApiQueryInfo::$cachedTokens['protect'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['protect'] ) ) {
+                       self::$cachedTokens['protect'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['protect'];
+               return self::$cachedTokens['protect'];
        }
 
        /**
@@ -195,11 +195,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['move'] ) ) {
-                       ApiQueryInfo::$cachedTokens['move'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['move'] ) ) {
+                       self::$cachedTokens['move'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['move'];
+               return self::$cachedTokens['move'];
        }
 
        /**
@@ -212,11 +212,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['block'] ) ) {
-                       ApiQueryInfo::$cachedTokens['block'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['block'] ) ) {
+                       self::$cachedTokens['block'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['block'];
+               return self::$cachedTokens['block'];
        }
 
        /**
@@ -237,11 +237,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['email'] ) ) {
-                       ApiQueryInfo::$cachedTokens['email'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['email'] ) ) {
+                       self::$cachedTokens['email'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['email'];
+               return self::$cachedTokens['email'];
        }
 
        /**
@@ -254,11 +254,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['import'] ) ) {
-                       ApiQueryInfo::$cachedTokens['import'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['import'] ) ) {
+                       self::$cachedTokens['import'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['import'];
+               return self::$cachedTokens['import'];
        }
 
        /**
@@ -271,11 +271,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['watch'] ) ) {
-                       ApiQueryInfo::$cachedTokens['watch'] = $wgUser->getEditToken( 'watch' );
+               if ( !isset( self::$cachedTokens['watch'] ) ) {
+                       self::$cachedTokens['watch'] = $wgUser->getEditToken( 'watch' );
                }
 
-               return ApiQueryInfo::$cachedTokens['watch'];
+               return self::$cachedTokens['watch'];
        }
 
        /**
@@ -288,11 +288,11 @@ class ApiQueryInfo extends ApiQueryBase {
                }
 
                // The token is always the same, let's exploit that
-               if ( !isset( ApiQueryInfo::$cachedTokens['options'] ) ) {
-                       ApiQueryInfo::$cachedTokens['options'] = $wgUser->getEditToken();
+               if ( !isset( self::$cachedTokens['options'] ) ) {
+                       self::$cachedTokens['options'] = $wgUser->getEditToken();
                }
 
-               return ApiQueryInfo::$cachedTokens['options'];
+               return self::$cachedTokens['options'];
        }
 
        public function execute() {
index 6734740..468d878 100644 (file)
@@ -287,12 +287,12 @@ class ApiResult implements ApiSerializable {
         * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
         */
        public static function setValue( array &$arr, $name, $value, $flags = 0 ) {
-               if ( ( $flags & ApiResult::NO_VALIDATE ) !== ApiResult::NO_VALIDATE ) {
+               if ( ( $flags & self::NO_VALIDATE ) !== self::NO_VALIDATE ) {
                        $value = self::validateValue( $value );
                }
 
                if ( $name === null ) {
-                       if ( $flags & ApiResult::ADD_ON_TOP ) {
+                       if ( $flags & self::ADD_ON_TOP ) {
                                array_unshift( $arr, $value );
                        } else {
                                array_push( $arr, $value );
@@ -301,8 +301,8 @@ class ApiResult implements ApiSerializable {
                }
 
                $exists = isset( $arr[$name] );
-               if ( !$exists || ( $flags & ApiResult::OVERRIDE ) ) {
-                       if ( !$exists && ( $flags & ApiResult::ADD_ON_TOP ) ) {
+               if ( !$exists || ( $flags & self::OVERRIDE ) ) {
+                       if ( !$exists && ( $flags & self::ADD_ON_TOP ) ) {
                                $arr = [ $name => $value ] + $arr;
                        } else {
                                $arr[$name] = $value;
@@ -403,13 +403,13 @@ class ApiResult implements ApiSerializable {
         * @since 1.21 int $flags replaced boolean $override
         */
        public function addValue( $path, $name, $value, $flags = 0 ) {
-               $arr = &$this->path( $path, ( $flags & ApiResult::ADD_ON_TOP ) ? 'prepend' : 'append' );
+               $arr = &$this->path( $path, ( $flags & self::ADD_ON_TOP ) ? 'prepend' : 'append' );
 
-               if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
+               if ( $this->checkingSize && !( $flags & self::NO_SIZE_CHECK ) ) {
                        // self::size needs the validated value. Then flag
                        // to not re-validate later.
                        $value = self::validateValue( $value );
-                       $flags |= ApiResult::NO_VALIDATE;
+                       $flags |= self::NO_VALIDATE;
 
                        $newsize = $this->size + self::size( $value );
                        if ( $this->maxSize !== false && $newsize > $this->maxSize ) {
@@ -459,7 +459,7 @@ class ApiResult implements ApiSerializable {
                        $name = array_pop( $path );
                }
                $ret = self::unsetValue( $this->path( $path, 'dummy' ), $name );
-               if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
+               if ( $this->checkingSize && !( $flags & self::NO_SIZE_CHECK ) ) {
                        $newsize = $this->size - self::size( $ret );
                        $this->size = max( $newsize, 0 );
                }
@@ -511,7 +511,7 @@ class ApiResult implements ApiSerializable {
        public function addParsedLimit( $moduleName, $limit ) {
                // Add value, allowing overwriting
                $this->addValue( 'limits', $moduleName, $limit,
-                       ApiResult::OVERRIDE | ApiResult::NO_SIZE_CHECK );
+                       self::OVERRIDE | self::NO_SIZE_CHECK );
        }
 
        /**@}*/
@@ -551,7 +551,7 @@ class ApiResult implements ApiSerializable {
         * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
         */
        public function addContentField( $path, $name, $flags = 0 ) {
-               $arr = &$this->path( $path, ( $flags & ApiResult::ADD_ON_TOP ) ? 'prepend' : 'append' );
+               $arr = &$this->path( $path, ( $flags & self::ADD_ON_TOP ) ? 'prepend' : 'append' );
                self::setContentField( $arr, $name, $flags );
        }
 
@@ -1156,7 +1156,7 @@ class ApiResult implements ApiSerializable {
                $bools = [];
                foreach ( $vars as $k => $v ) {
                        if ( is_array( $v ) || is_object( $v ) ) {
-                               $vars[$k] = ApiResult::addMetadataToResultVars( (array)$v, is_object( $v ) );
+                               $vars[$k] = self::addMetadataToResultVars( (array)$v, is_object( $v ) );
                        } elseif ( is_bool( $v ) ) {
                                // Better here to use real bools even in BC formats
                                $bools[] = $k;
@@ -1176,22 +1176,22 @@ class ApiResult implements ApiSerializable {
                        // Get the list of keys we actually care about. Unfortunately, we can't support
                        // certain keys that conflict with ApiResult metadata.
                        $keys = array_diff( array_keys( $vars ), [
-                               ApiResult::META_TYPE, ApiResult::META_PRESERVE_KEYS, ApiResult::META_KVP_KEY_NAME,
-                               ApiResult::META_INDEXED_TAG_NAME, ApiResult::META_BC_BOOLS
+                               self::META_TYPE, self::META_PRESERVE_KEYS, self::META_KVP_KEY_NAME,
+                               self::META_INDEXED_TAG_NAME, self::META_BC_BOOLS
                        ] );
 
                        return [
-                               ApiResult::META_TYPE => 'kvp',
-                               ApiResult::META_KVP_KEY_NAME => 'key',
-                               ApiResult::META_PRESERVE_KEYS => $keys,
-                               ApiResult::META_BC_BOOLS => $bools,
-                               ApiResult::META_INDEXED_TAG_NAME => 'var',
+                               self::META_TYPE => 'kvp',
+                               self::META_KVP_KEY_NAME => 'key',
+                               self::META_PRESERVE_KEYS => $keys,
+                               self::META_BC_BOOLS => $bools,
+                               self::META_INDEXED_TAG_NAME => 'var',
                        ] + $vars;
                } else {
                        return [
-                               ApiResult::META_TYPE => 'array',
-                               ApiResult::META_BC_BOOLS => $bools,
-                               ApiResult::META_INDEXED_TAG_NAME => 'value',
+                               self::META_TYPE => 'array',
+                               self::META_BC_BOOLS => $bools,
+                               self::META_INDEXED_TAG_NAME => 'value',
                        ] + $vars;
                }
        }
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 1dfeb34..a311728 100644 (file)
@@ -11,7 +11,8 @@
                        "Winstonyin",
                        "Arthur2e5",
                        "烈羽",
-                       "Corainn"
+                       "Corainn",
+                       "A2093064"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|說明文件]]\n* [[mw:API:FAQ|常見問題]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 郵寄清單]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 報告錯誤及請求功能]\n</div>\n<strong>狀態資訊:</strong>本頁所展示的所有功能都應正常工作,但是API仍在開發當中,將會隨時變化。請訂閱[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 郵件清單]以便得到更新通知。\n\n<strong>錯誤的請求:</strong>當API收到錯誤的請求時,會發出以「MediaWiki-API-Error」為鍵的HTTP頭欄位,隨後頭欄位的值與錯誤碼將會被設為相同的值。詳細資訊請參閱[[mw:API:Errors_and_warnings|API: 錯誤與警告]]。\n\n<strong>測試:</strong>要簡化API請求的測試過程,請見[[Special:ApiSandbox]]。",
@@ -57,7 +58,7 @@
        "apihelp-createaccount-summary": "建立新使用者帳號。",
        "apihelp-createaccount-param-name": "使用者名稱。",
        "apihelp-createaccount-param-password": "密碼 (若有設定 <var>$1mailpassword</var> 則可略過)。",
-       "apihelp-createaccount-param-domain": "å¤\96é\83¨èª\8d証使用的網域 (選填)。",
+       "apihelp-createaccount-param-domain": "å¤\96é\83¨èª\8dè­\89使用的網域 (選填)。",
        "apihelp-createaccount-param-token": "在第一次請求時已取得的帳號建立金鑰。",
        "apihelp-createaccount-param-email": "使用者的電子郵件地址 (選填) 。",
        "apihelp-createaccount-param-realname": "使用者的真實姓名 (選填)。",
index 6684fb9..956c985 100644 (file)
@@ -133,7 +133,7 @@ class AuthenticationResponse {
         */
        public static function newPass( $username = null ) {
                $ret = new AuthenticationResponse;
-               $ret->status = AuthenticationResponse::PASS;
+               $ret->status = self::PASS;
                $ret->username = $username;
                return $ret;
        }
@@ -145,7 +145,7 @@ class AuthenticationResponse {
         */
        public static function newFail( Message $msg ) {
                $ret = new AuthenticationResponse;
-               $ret->status = AuthenticationResponse::FAIL;
+               $ret->status = self::FAIL;
                $ret->message = $msg;
                $ret->messageType = 'error';
                return $ret;
@@ -158,7 +158,7 @@ class AuthenticationResponse {
         */
        public static function newRestart( Message $msg ) {
                $ret = new AuthenticationResponse;
-               $ret->status = AuthenticationResponse::RESTART;
+               $ret->status = self::RESTART;
                $ret->message = $msg;
                return $ret;
        }
@@ -169,7 +169,7 @@ class AuthenticationResponse {
         */
        public static function newAbstain() {
                $ret = new AuthenticationResponse;
-               $ret->status = AuthenticationResponse::ABSTAIN;
+               $ret->status = self::ABSTAIN;
                return $ret;
        }
 
@@ -189,7 +189,7 @@ class AuthenticationResponse {
                }
 
                $ret = new AuthenticationResponse;
-               $ret->status = AuthenticationResponse::UI;
+               $ret->status = self::UI;
                $ret->neededRequests = $reqs;
                $ret->message = $msg;
                $ret->messageType = $msgtype;
@@ -209,7 +209,7 @@ class AuthenticationResponse {
                }
 
                $ret = new AuthenticationResponse;
-               $ret->status = AuthenticationResponse::REDIRECT;
+               $ret->status = self::REDIRECT;
                $ret->neededRequests = $reqs;
                $ret->redirectTarget = $redirectTarget;
                $ret->redirectApiData = $redirectApiData;
index ad1fffb..f9f9a08 100644 (file)
@@ -816,7 +816,7 @@ class MessageCache {
                }
 
                // Normalise title-case input (with some inlining)
-               $lckey = MessageCache::normalizeKey( $key );
+               $lckey = self::normalizeKey( $key );
 
                Hooks::run( 'MessageCache::get', [ &$lckey ] );
 
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 30c6995..55cb9ed 100644 (file)
@@ -102,15 +102,17 @@ class EnhancedChangesList extends ChangesList {
                        $rc->mAttribs['rc_timestamp'],
                        $this->getUser()
                );
+               if ( $this->lastdate === '' ) {
+                       $this->lastdate = $date;
+               }
 
                $ret = '';
 
-               # If it's a new day, add the headline and flush the cache
-               if ( $date != $this->lastdate ) {
-                       # Process current cache
+               # If it's a new day, flush the cache and update $this->lastdate
+               if ( $date !== $this->lastdate ) {
+                       # Process current cache (uses $this->lastdate to generate a heading)
                        $ret = $this->recentChangesBlock();
                        $this->rc_cache = [];
-                       $ret .= Xml::element( 'h4', null, $date ) . "\n";
                        $this->lastdate = $date;
                }
 
@@ -763,7 +765,11 @@ class EnhancedChangesList extends ChangesList {
                        }
                }
 
-               return '<div>' . $blockOut . '</div>';
+               if ( $blockOut === '' ) {
+                       return '';
+               }
+               // $this->lastdate is kept up to date by recentChangesLine()
+               return Xml::element( 'h4', null, $this->lastdate ) . "\n<div>" . $blockOut . '</div>';
        }
 
        /**
index e8e35a3..5fad8fd 100644 (file)
@@ -130,7 +130,7 @@ class RecentChange {
                if ( is_array( $type ) ) {
                        $retval = [];
                        foreach ( $type as $t ) {
-                               $retval[] = RecentChange::parseToRCType( $t );
+                               $retval[] = self::parseToRCType( $t );
                        }
 
                        return $retval;
@@ -459,7 +459,7 @@ class RecentChange {
 
                $change = $change instanceof RecentChange
                        ? $change
-                       : RecentChange::newFromId( $change );
+                       : self::newFromId( $change );
 
                if ( !$change instanceof RecentChange ) {
                        return null;
index e2f82d4..d93362b 100644 (file)
@@ -535,7 +535,7 @@ class IcuCollation extends Collation {
         * @return string|bool
         */
        static function getUnicodeVersionForICU() {
-               $icuVersion = IcuCollation::getICUVersion();
+               $icuVersion = self::getICUVersion();
                if ( !$icuVersion ) {
                        return false;
                }
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 c57eba7..6605c38 100644 (file)
@@ -243,7 +243,7 @@ class EtcdConfig implements Config, LoggerAwareInterface {
 
                $info = json_decode( $rbody, true );
                if ( $info === null || !isset( $info['node']['nodes'] ) ) {
-                       return [ null, $rcode, "Unexpected JSON response; missing 'nodes' list.", false ];
+                       return [ null, "Unexpected JSON response; missing 'nodes' list.", false ];
                }
 
                $config = [];
index f85b00d..8603360 100644 (file)
@@ -136,7 +136,7 @@ abstract class ContentHandler {
                        $modelId = $title->getContentModel();
                }
 
-               $handler = ContentHandler::getForModelID( $modelId );
+               $handler = self::getForModelID( $modelId );
 
                return $handler->unserializeContent( $text, $format );
        }
@@ -240,7 +240,7 @@ abstract class ContentHandler {
        public static function getForTitle( Title $title ) {
                $modelId = $title->getContentModel();
 
-               return ContentHandler::getForModelID( $modelId );
+               return self::getForModelID( $modelId );
        }
 
        /**
@@ -256,7 +256,7 @@ abstract class ContentHandler {
        public static function getForContent( Content $content ) {
                $modelId = $content->getModel();
 
-               return ContentHandler::getForModelID( $modelId );
+               return self::getForModelID( $modelId );
        }
 
        /**
@@ -293,8 +293,8 @@ abstract class ContentHandler {
        public static function getForModelID( $modelId ) {
                global $wgContentHandlers;
 
-               if ( isset( ContentHandler::$handlers[$modelId] ) ) {
-                       return ContentHandler::$handlers[$modelId];
+               if ( isset( self::$handlers[$modelId] ) ) {
+                       return self::$handlers[$modelId];
                }
 
                if ( empty( $wgContentHandlers[$modelId] ) ) {
@@ -327,9 +327,9 @@ abstract class ContentHandler {
                wfDebugLog( 'ContentHandler', 'Created handler for ' . $modelId
                        . ': ' . get_class( $handler ) );
 
-               ContentHandler::$handlers[$modelId] = $handler;
+               self::$handlers[$modelId] = $handler;
 
-               return ContentHandler::$handlers[$modelId];
+               return self::$handlers[$modelId];
        }
 
        /**
@@ -372,7 +372,7 @@ abstract class ContentHandler {
                $formats = [];
 
                foreach ( $wgContentHandlers as $model => $class ) {
-                       $handler = ContentHandler::getForModelID( $model );
+                       $handler = self::getForModelID( $model );
                        $formats = array_merge( $formats, $handler->getSupportedFormats() );
                }
 
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 e67a0b3..012837f 100644 (file)
@@ -425,7 +425,7 @@ class MWDebug {
                $html = '';
 
                if ( self::$enabled ) {
-                       MWDebug::log( 'MWDebug output complete' );
+                       self::log( 'MWDebug output complete' );
                        $debugInfo = self::getDebugInfo( $context );
 
                        // Cannot use OutputPage::addJsConfigVars because those are already outputted
@@ -495,7 +495,7 @@ class MWDebug {
                        }
                }
 
-               MWDebug::log( 'MWDebug output complete' );
+               self::log( 'MWDebug output complete' );
                $debugInfo = self::getDebugInfo( $context );
 
                ApiResult::setIndexedTagName( $debugInfo, 'debuginfo' );
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 a307468..943aa04 100644 (file)
@@ -91,8 +91,8 @@ class WikiExporter {
         * @param int $buffer One of WikiExporter::BUFFER or WikiExporter::STREAM
         * @param int $text One of WikiExporter::TEXT or WikiExporter::STUB
         */
-       function __construct( $db, $history = WikiExporter::CURRENT,
-                       $buffer = WikiExporter::BUFFER, $text = WikiExporter::TEXT ) {
+       function __construct( $db, $history = self::CURRENT,
+                       $buffer = self::BUFFER, $text = self::TEXT ) {
                $this->db = $db;
                $this->history = $history;
                $this->buffer = $buffer;
@@ -272,7 +272,7 @@ class WikiExporter {
                        # Get logging table name for logging.* clause
                        $logging = $this->db->tableName( 'logging' );
 
-                       if ( $this->buffer == WikiExporter::STREAM ) {
+                       if ( $this->buffer == self::STREAM ) {
                                $prev = $this->db->bufferResults( false );
                        }
                        $result = null; // Assuring $result is not undefined, if exception occurs early
@@ -284,7 +284,7 @@ class WikiExporter {
                                        [ 'ORDER BY' => 'log_id', 'USE INDEX' => [ 'logging' => 'PRIMARY' ] ]
                                );
                                $this->outputLogStream( $result );
-                               if ( $this->buffer == WikiExporter::STREAM ) {
+                               if ( $this->buffer == self::STREAM ) {
                                        $this->db->bufferResults( $prev );
                                }
                        } catch ( Exception $e ) {
@@ -303,7 +303,7 @@ class WikiExporter {
 
                                // Putting database back in previous buffer mode
                                try {
-                                       if ( $this->buffer == WikiExporter::STREAM ) {
+                                       if ( $this->buffer == self::STREAM ) {
                                                $this->db->bufferResults( $prev );
                                        }
                                } catch ( Exception $e2 ) {
@@ -341,10 +341,10 @@ class WikiExporter {
                                if ( !empty( $this->history['limit'] ) ) {
                                        $opts['LIMIT'] = intval( $this->history['limit'] );
                                }
-                       } elseif ( $this->history & WikiExporter::FULL ) {
+                       } elseif ( $this->history & self::FULL ) {
                                # Full history dumps...
                                # query optimization for history stub dumps
-                               if ( $this->text == WikiExporter::STUB && $orderRevs ) {
+                               if ( $this->text == self::STUB && $orderRevs ) {
                                        $tables = [ 'revision', 'page' ];
                                        $opts[] = 'STRAIGHT_JOIN';
                                        $opts['ORDER BY'] = [ 'rev_page ASC', 'rev_id ASC' ];
@@ -353,13 +353,13 @@ class WikiExporter {
                                } else {
                                        $join['revision'] = [ 'INNER JOIN', 'page_id=rev_page' ];
                                }
-                       } elseif ( $this->history & WikiExporter::CURRENT ) {
+                       } elseif ( $this->history & self::CURRENT ) {
                                # Latest revision dumps...
                                if ( $this->list_authors && $cond != '' ) { // List authors, if so desired
                                        $this->do_list_authors( $cond );
                                }
                                $join['revision'] = [ 'INNER JOIN', 'page_id=rev_page AND page_latest=rev_id' ];
-                       } elseif ( $this->history & WikiExporter::STABLE ) {
+                       } elseif ( $this->history & self::STABLE ) {
                                # "Stable" revision dumps...
                                # Default JOIN, to be overridden...
                                $join['revision'] = [ 'INNER JOIN', 'page_id=rev_page AND page_latest=rev_id' ];
@@ -367,7 +367,7 @@ class WikiExporter {
                                if ( Hooks::run( 'WikiExporter::dumpStableQuery', [ &$tables, &$opts, &$join ] ) ) {
                                        throw new MWException( __METHOD__ . " given invalid history dump type." );
                                }
-                       } elseif ( $this->history & WikiExporter::RANGE ) {
+                       } elseif ( $this->history & self::RANGE ) {
                                # Dump of revisions within a specified range
                                $join['revision'] = [ 'INNER JOIN', 'page_id=rev_page' ];
                                $opts['ORDER BY'] = [ 'rev_page ASC', 'rev_id ASC' ];
@@ -381,12 +381,12 @@ class WikiExporter {
                                $opts['USE INDEX']['page'] = 'PRIMARY';
                        }
                        # Build text join options
-                       if ( $this->text != WikiExporter::STUB ) { // 1-pass
+                       if ( $this->text != self::STUB ) { // 1-pass
                                $tables[] = 'text';
                                $join['text'] = [ 'INNER JOIN', 'rev_text_id=old_id' ];
                        }
 
-                       if ( $this->buffer == WikiExporter::STREAM ) {
+                       if ( $this->buffer == self::STREAM ) {
                                $prev = $this->db->bufferResults( false );
                        }
                        $result = null; // Assuring $result is not undefined, if exception occurs early
@@ -399,7 +399,7 @@ class WikiExporter {
                                # Output dump results
                                $this->outputPageStream( $result );
 
-                               if ( $this->buffer == WikiExporter::STREAM ) {
+                               if ( $this->buffer == self::STREAM ) {
                                        $this->db->bufferResults( $prev );
                                }
                        } catch ( Exception $e ) {
@@ -418,7 +418,7 @@ class WikiExporter {
 
                                // Putting database back in previous buffer mode
                                try {
-                                       if ( $this->buffer == WikiExporter::STREAM ) {
+                                       if ( $this->buffer == self::STREAM ) {
                                                $this->db->bufferResults( $prev );
                                        }
                                } catch ( Exception $e2 ) {
index 43f1d21..56ccc64 100644 (file)
@@ -528,7 +528,7 @@ class ForeignAPIRepo extends FileRepo {
                }
 
                $req = MWHttpRequest::factory( $url, $options, __METHOD__ );
-               $req->setUserAgent( ForeignAPIRepo::getUserAgent() );
+               $req->setUserAgent( self::getUserAgent() );
                $status = $req->execute();
 
                if ( $status->isOK() ) {
index 399147b..61d0d89 100644 (file)
@@ -285,7 +285,7 @@ class HTMLForm extends ContextSource {
                                return ObjectFactory::constructClassInstance( OOUIHTMLForm::class, $arguments );
                        default:
                                /** @var HTMLForm $form */
-                               $form = ObjectFactory::constructClassInstance( HTMLForm::class, $arguments );
+                               $form = ObjectFactory::constructClassInstance( self::class, $arguments );
                                $form->setDisplayFormat( $displayFormat );
                                return $form;
                }
index 4f21ce2..c10b312 100644 (file)
@@ -106,7 +106,7 @@ class Http {
                        $options['timeout'] = $args[1];
                        $caller = __METHOD__;
                }
-               return Http::request( 'GET', $url, $options, $caller );
+               return self::request( 'GET', $url, $options, $caller );
        }
 
        /**
@@ -119,7 +119,7 @@ class Http {
         * @return string|bool false on error
         */
        public static function post( $url, $options = [], $caller = __METHOD__ ) {
-               return Http::request( 'POST', $url, $options, $caller );
+               return self::request( 'POST', $url, $options, $caller );
        }
 
        /**
index 8034400..94a2b93 100644 (file)
@@ -93,7 +93,7 @@ class ImportStreamSource implements ImportSource {
                }
                $fname = $upload['tmp_name'];
                if ( is_uploaded_file( $fname ) ) {
-                       return ImportStreamSource::newFromFile( $fname );
+                       return self::newFromFile( $fname );
                } else {
                        return Status::newFatal( 'importnofile' );
                }
@@ -178,6 +178,6 @@ class ImportStreamSource implements ImportSource {
 
                $url = wfAppendQuery( $link, $params );
                # For interwikis, use POST to avoid redirects.
-               return ImportStreamSource::newFromURL( $url, "POST" );
+               return self::newFromURL( $url, "POST" );
        }
 }
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 a311ce9..27300f3 100644 (file)
@@ -703,7 +703,7 @@ class WebInstaller extends Installer {
                        "<span class=\"config-help-field-hint\" title=\"" .
                        wfMessage( 'config-help-tooltip' )->escaped() . "\">" .
                        wfMessage( 'config-help' )->escaped() . "</span>\n" .
-                       "<span class=\"config-help-field-data\">" . $html . "</span>\n" .
+                       "<div class=\"config-help-field-data\">" . $html . "</div>\n" .
                        "</div>\n";
        }
 
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 d20a233..1f4f179 100644 (file)
@@ -378,7 +378,7 @@ abstract class JobQueue {
                // Flag this job as an old duplicate based on its "root" job...
                try {
                        if ( $job && $this->isRootJobOldDuplicate( $job ) ) {
-                               JobQueue::incrStats( 'dupe_pops', $this->type );
+                               self::incrStats( 'dupe_pops', $this->type );
                                $job = DuplicateJob::newFromJob( $job ); // convert to a no-op
                        }
                } catch ( Exception $e ) {
index ea0f1b7..9e060cd 100644 (file)
@@ -78,7 +78,12 @@ class CSSMin {
                                $url = $match['file'][0];
 
                                // Skip fully-qualified and protocol-relative URLs and data URIs
-                               if ( substr( $url, 0, 2 ) === '//' || parse_url( $url, PHP_URL_SCHEME ) ) {
+                               // Also skips the rare `behavior` property specifying application's default behavior
+                               if (
+                                       substr( $url, 0, 2 ) === '//' ||
+                                       parse_url( $url, PHP_URL_SCHEME ) ||
+                                       substr( $url, 0, 9 ) === '#default#'
+                               ) {
                                        break;
                                }
 
@@ -252,7 +257,7 @@ class CSSMin {
                // quotation marks (e.g. "foo /* bar").
                $comments = [];
 
-               $pattern = '/(?!' . CSSMin::EMBED_REGEX . ')(' . CSSMin::COMMENT_REGEX . ')/s';
+               $pattern = '/(?!' . self::EMBED_REGEX . ')(' . self::COMMENT_REGEX . ')/s';
 
                $source = preg_replace_callback(
                        $pattern,
@@ -355,7 +360,7 @@ class CSSMin {
                        }, $source );
 
                // Re-insert comments
-               $pattern = '/' . CSSMin::PLACEHOLDER . '(\d+)x/';
+               $pattern = '/' . self::PLACEHOLDER . '(\d+)x/';
                $source = preg_replace_callback( $pattern, function ( $match ) use ( &$comments ) {
                        return $comments[ $match[1] ];
                }, $source );
@@ -474,7 +479,12 @@ class CSSMin {
 
                // Pass thru fully-qualified and protocol-relative URLs and data URIs, as well as local URLs if
                // we can't expand them.
-               if ( self::isRemoteUrl( $url ) || self::isLocalUrl( $url ) ) {
+               // Also skips the rare `behavior` property specifying application's default behavior
+               if (
+                       self::isRemoteUrl( $url ) ||
+                       self::isLocalUrl( $url ) ||
+                       substr( $url, 0, 9 ) === '#default#'
+               ) {
                        return $url;
                }
 
index e8b0e6a..b22f06d 100644 (file)
@@ -549,7 +549,7 @@ class IP {
         */
        private static function parseCIDR6( $range ) {
                # Explode into <expanded IP,range>
-               $parts = explode( '/', IP::sanitizeIP( $range ), 2 );
+               $parts = explode( '/', self::sanitizeIP( $range ), 2 );
                if ( count( $parts ) != 2 ) {
                        return [ false, false ];
                }
@@ -590,7 +590,7 @@ class IP {
         */
        private static function parseRange6( $range ) {
                # Expand any IPv6 IP
-               $range = IP::sanitizeIP( $range );
+               $range = self::sanitizeIP( $range );
                // CIDR notation...
                if ( strpos( $range, '/' ) !== false ) {
                        list( $network, $bits ) = self::parseCIDR6( $range );
@@ -732,8 +732,8 @@ class IP {
        public static function getSubnet( $ip ) {
                $matches = [];
                $subnet = false;
-               if ( IP::isIPv6( $ip ) ) {
-                       $parts = IP::parseRange( "$ip/64" );
+               if ( self::isIPv6( $ip ) ) {
+                       $parts = self::parseRange( "$ip/64" );
                        $subnet = $parts[0];
                } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
                        // IPv4
index cffb5a3..9638706 100644 (file)
@@ -276,7 +276,7 @@ class StringUtils {
 
                // Replace instances of the separator inside HTML-like tags with the placeholder
                $replacer = new DoubleReplacer( $separator, $placeholder );
-               $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
+               $cleaned = self::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
 
                // Explode, then put the replaced separators back in
                $items = explode( $separator, $cleaned );
@@ -303,7 +303,7 @@ class StringUtils {
 
                // Replace instances of the separator inside HTML-like tags with the placeholder
                $replacer = new DoubleReplacer( $search, $placeholder );
-               $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
+               $cleaned = self::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
 
                // Explode, then put the replaced separators back in
                $cleaned = str_replace( $search, $replace, $cleaned );
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 687c67c..d94578d 100644 (file)
@@ -181,6 +181,12 @@ class MultiWriteBagOStuff extends BagOStuff {
                $ret = true;
                $args = array_slice( func_get_args(), 3 );
 
+               if ( $count > 1 && $asyncWrites ) {
+                       // Deep-clone $args to prevent misbehavior when something writes an
+                       // object to the BagOStuff then modifies it afterwards, e.g. T168040.
+                       $args = unserialize( serialize( $args ) );
+               }
+
                foreach ( $this->caches as $i => $cache ) {
                        if ( $i >= $count ) {
                                break; // ignore the lower tiers
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..ec97b50 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
@@ -207,7 +205,7 @@ class LogPage {
         * @return bool
         */
        public static function isLogType( $type ) {
-               return in_array( $type, LogPage::validTypes() );
+               return in_array( $type, self::validTypes() );
        }
 
        /**
@@ -350,7 +348,7 @@ class LogPage {
                $this->action = $action;
                $this->target = $target;
                $this->comment = $comment;
-               $this->params = LogPage::makeParamBlob( $params );
+               $this->params = self::makeParamBlob( $params );
 
                if ( $doer === null ) {
                        global $wgUser;
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 3858f27..1f8489f 100644 (file)
@@ -175,18 +175,18 @@ class UserMailer {
                                // first send to non-split address list, then to split addresses one by one
                                $status = Status::newGood();
                                if ( $to ) {
-                                       $status->merge( UserMailer::sendInternal(
+                                       $status->merge( self::sendInternal(
                                                $to, $from, $subject, $body, $options ) );
                                }
                                foreach ( $splitTo as $newTo ) {
-                                       $status->merge( UserMailer::sendInternal(
+                                       $status->merge( self::sendInternal(
                                                [ $newTo ], $from, $subject, $body, $options ) );
                                }
                                return $status;
                        }
                }
 
-               return UserMailer::sendInternal( $to, $from, $subject, $body, $options );
+               return self::sendInternal( $to, $from, $subject, $body, $options );
        }
 
        /**
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..cd457f0 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 ''.
@@ -120,162 +118,162 @@ class Exif {
                        # TIFF Rev. 6.0 Attribute Information (p22)
                        'IFD0' => [
                                # Tags relating to image structure
-                               'ImageWidth' => Exif::SHORT_OR_LONG, # Image width
-                               'ImageLength' => Exif::SHORT_OR_LONG, # Image height
-                               'BitsPerSample' => [ Exif::SHORT, 3 ], # Number of bits per component
+                               'ImageWidth' => self::SHORT_OR_LONG, # Image width
+                               'ImageLength' => self::SHORT_OR_LONG, # Image height
+                               'BitsPerSample' => [ self::SHORT, 3 ], # Number of bits per component
                                # "When a primary image is JPEG compressed, this designation is not"
                                # "necessary and is omitted." (p23)
-                               'Compression' => Exif::SHORT, # Compression scheme #p23
-                               'PhotometricInterpretation' => Exif::SHORT, # Pixel composition #p23
-                               'Orientation' => Exif::SHORT, # Orientation of image #p24
-                               'SamplesPerPixel' => Exif::SHORT, # Number of components
-                               'PlanarConfiguration' => Exif::SHORT, # Image data arrangement #p24
-                               'YCbCrSubSampling' => [ Exif::SHORT, 2 ], # Subsampling ratio of Y to C #p24
-                               'YCbCrPositioning' => Exif::SHORT, # Y and C positioning #p24-25
-                               'XResolution' => Exif::RATIONAL, # Image resolution in width direction
-                               'YResolution' => Exif::RATIONAL, # Image resolution in height direction
-                               'ResolutionUnit' => Exif::SHORT, # Unit of X and Y resolution #(p26)
+                               'Compression' => self::SHORT, # Compression scheme #p23
+                               'PhotometricInterpretation' => self::SHORT, # Pixel composition #p23
+                               'Orientation' => self::SHORT, # Orientation of image #p24
+                               'SamplesPerPixel' => self::SHORT, # Number of components
+                               'PlanarConfiguration' => self::SHORT, # Image data arrangement #p24
+                               'YCbCrSubSampling' => [ self::SHORT, 2 ], # Subsampling ratio of Y to C #p24
+                               'YCbCrPositioning' => self::SHORT, # Y and C positioning #p24-25
+                               'XResolution' => self::RATIONAL, # Image resolution in width direction
+                               'YResolution' => self::RATIONAL, # Image resolution in height direction
+                               'ResolutionUnit' => self::SHORT, # Unit of X and Y resolution #(p26)
 
                                # Tags relating to recording offset
-                               'StripOffsets' => Exif::SHORT_OR_LONG, # Image data location
-                               'RowsPerStrip' => Exif::SHORT_OR_LONG, # Number of rows per strip
-                               'StripByteCounts' => Exif::SHORT_OR_LONG, # Bytes per compressed strip
-                               'JPEGInterchangeFormat' => Exif::SHORT_OR_LONG, # Offset to JPEG SOI
-                               'JPEGInterchangeFormatLength' => Exif::SHORT_OR_LONG, # Bytes of JPEG data
+                               'StripOffsets' => self::SHORT_OR_LONG, # Image data location
+                               'RowsPerStrip' => self::SHORT_OR_LONG, # Number of rows per strip
+                               'StripByteCounts' => self::SHORT_OR_LONG, # Bytes per compressed strip
+                               'JPEGInterchangeFormat' => self::SHORT_OR_LONG, # Offset to JPEG SOI
+                               'JPEGInterchangeFormatLength' => self::SHORT_OR_LONG, # Bytes of JPEG data
 
                                # Tags relating to image data characteristics
-                               'TransferFunction' => Exif::IGNORE, # Transfer function
-                               'WhitePoint' => [ Exif::RATIONAL, 2 ], # White point chromaticity
-                               'PrimaryChromaticities' => [ Exif::RATIONAL, 6 ], # Chromaticities of primarities
+                               'TransferFunction' => self::IGNORE, # Transfer function
+                               'WhitePoint' => [ self::RATIONAL, 2 ], # White point chromaticity
+                               'PrimaryChromaticities' => [ self::RATIONAL, 6 ], # Chromaticities of primarities
                                # Color space transformation matrix coefficients #p27
-                               'YCbCrCoefficients' => [ Exif::RATIONAL, 3 ],
-                               'ReferenceBlackWhite' => [ Exif::RATIONAL, 6 ], # Pair of black and white reference values
+                               'YCbCrCoefficients' => [ self::RATIONAL, 3 ],
+                               'ReferenceBlackWhite' => [ self::RATIONAL, 6 ], # Pair of black and white reference values
 
                                # Other tags
-                               'DateTime' => Exif::ASCII, # File change date and time
-                               'ImageDescription' => Exif::ASCII, # Image title
-                               'Make' => Exif::ASCII, # Image input equipment manufacturer
-                               'Model' => Exif::ASCII, # Image input equipment model
-                               'Software' => Exif::ASCII, # Software used
-                               'Artist' => Exif::ASCII, # Person who created the image
-                               'Copyright' => Exif::ASCII, # Copyright holder
+                               'DateTime' => self::ASCII, # File change date and time
+                               'ImageDescription' => self::ASCII, # Image title
+                               'Make' => self::ASCII, # Image input equipment manufacturer
+                               'Model' => self::ASCII, # Image input equipment model
+                               'Software' => self::ASCII, # Software used
+                               'Artist' => self::ASCII, # Person who created the image
+                               'Copyright' => self::ASCII, # Copyright holder
                        ],
 
                        # Exif IFD Attribute Information (p30-31)
                        'EXIF' => [
                                # @todo NOTE: Nonexistence of this field is taken to mean nonconformance
                                # to the Exif 2.1 AND 2.2 standards
-                               'ExifVersion' => Exif::UNDEFINED, # Exif version
-                               'FlashPixVersion' => Exif::UNDEFINED, # Supported Flashpix version #p32
+                               'ExifVersion' => self::UNDEFINED, # Exif version
+                               'FlashPixVersion' => self::UNDEFINED, # Supported Flashpix version #p32
 
                                # Tags relating to Image Data Characteristics
-                               'ColorSpace' => Exif::SHORT, # Color space information #p32
+                               'ColorSpace' => self::SHORT, # Color space information #p32
 
                                # Tags relating to image configuration
-                               'ComponentsConfiguration' => Exif::UNDEFINED, # Meaning of each component #p33
-                               'CompressedBitsPerPixel' => Exif::RATIONAL, # Image compression mode
-                               'PixelYDimension' => Exif::SHORT_OR_LONG, # Valid image height
-                               'PixelXDimension' => Exif::SHORT_OR_LONG, # Valid image width
+                               'ComponentsConfiguration' => self::UNDEFINED, # Meaning of each component #p33
+                               'CompressedBitsPerPixel' => self::RATIONAL, # Image compression mode
+                               'PixelYDimension' => self::SHORT_OR_LONG, # Valid image height
+                               'PixelXDimension' => self::SHORT_OR_LONG, # Valid image width
 
                                # Tags relating to related user information
-                               'MakerNote' => Exif::IGNORE, # Manufacturer notes
-                               'UserComment' => Exif::UNDEFINED, # User comments #p34
+                               'MakerNote' => self::IGNORE, # Manufacturer notes
+                               'UserComment' => self::UNDEFINED, # User comments #p34
 
                                # Tags relating to related file information
-                               'RelatedSoundFile' => Exif::ASCII, # Related audio file
+                               'RelatedSoundFile' => self::ASCII, # Related audio file
 
                                # Tags relating to date and time
-                               'DateTimeOriginal' => Exif::ASCII, # Date and time of original data generation #p36
-                               'DateTimeDigitized' => Exif::ASCII, # Date and time of original data generation
-                               'SubSecTime' => Exif::ASCII, # DateTime subseconds
-                               'SubSecTimeOriginal' => Exif::ASCII, # DateTimeOriginal subseconds
-                               'SubSecTimeDigitized' => Exif::ASCII, # DateTimeDigitized subseconds
+                               'DateTimeOriginal' => self::ASCII, # Date and time of original data generation #p36
+                               'DateTimeDigitized' => self::ASCII, # Date and time of original data generation
+                               'SubSecTime' => self::ASCII, # DateTime subseconds
+                               'SubSecTimeOriginal' => self::ASCII, # DateTimeOriginal subseconds
+                               'SubSecTimeDigitized' => self::ASCII, # DateTimeDigitized subseconds
 
                                # Tags relating to picture-taking conditions (p31)
-                               'ExposureTime' => Exif::RATIONAL, # Exposure time
-                               'FNumber' => Exif::RATIONAL, # F Number
-                               'ExposureProgram' => Exif::SHORT, # Exposure Program #p38
-                               'SpectralSensitivity' => Exif::ASCII, # Spectral sensitivity
-                               'ISOSpeedRatings' => Exif::SHORT, # ISO speed rating
-                               'OECF' => Exif::IGNORE,
+                               'ExposureTime' => self::RATIONAL, # Exposure time
+                               'FNumber' => self::RATIONAL, # F Number
+                               'ExposureProgram' => self::SHORT, # Exposure Program #p38
+                               'SpectralSensitivity' => self::ASCII, # Spectral sensitivity
+                               'ISOSpeedRatings' => self::SHORT, # ISO speed rating
+                               'OECF' => self::IGNORE,
                                # Optoelectronic conversion factor. Note: We don't have support for this atm.
-                               'ShutterSpeedValue' => Exif::SRATIONAL, # Shutter speed
-                               'ApertureValue' => Exif::RATIONAL, # Aperture
-                               'BrightnessValue' => Exif::SRATIONAL, # Brightness
-                               'ExposureBiasValue' => Exif::SRATIONAL, # Exposure bias
-                               'MaxApertureValue' => Exif::RATIONAL, # Maximum land aperture
-                               'SubjectDistance' => Exif::RATIONAL, # Subject distance
-                               'MeteringMode' => Exif::SHORT, # Metering mode #p40
-                               'LightSource' => Exif::SHORT, # Light source #p40-41
-                               'Flash' => Exif::SHORT, # Flash #p41-42
-                               'FocalLength' => Exif::RATIONAL, # Lens focal length
-                               'SubjectArea' => [ Exif::SHORT, 4 ], # Subject area
-                               'FlashEnergy' => Exif::RATIONAL, # Flash energy
-                               'SpatialFrequencyResponse' => Exif::IGNORE, # Spatial frequency response. Not supported atm.
-                               'FocalPlaneXResolution' => Exif::RATIONAL, # Focal plane X resolution
-                               'FocalPlaneYResolution' => Exif::RATIONAL, # Focal plane Y resolution
-                               'FocalPlaneResolutionUnit' => Exif::SHORT, # Focal plane resolution unit #p46
-                               'SubjectLocation' => [ Exif::SHORT, 2 ], # Subject location
-                               'ExposureIndex' => Exif::RATIONAL, # Exposure index
-                               'SensingMethod' => Exif::SHORT, # Sensing method #p46
-                               'FileSource' => Exif::UNDEFINED, # File source #p47
-                               'SceneType' => Exif::UNDEFINED, # Scene type #p47
-                               'CFAPattern' => Exif::IGNORE, # CFA pattern. not supported atm.
-                               'CustomRendered' => Exif::SHORT, # Custom image processing #p48
-                               'ExposureMode' => Exif::SHORT, # Exposure mode #p48
-                               'WhiteBalance' => Exif::SHORT, # White Balance #p49
-                               'DigitalZoomRatio' => Exif::RATIONAL, # Digital zoom ration
-                               'FocalLengthIn35mmFilm' => Exif::SHORT, # Focal length in 35 mm film
-                               'SceneCaptureType' => Exif::SHORT, # Scene capture type #p49
-                               'GainControl' => Exif::SHORT, # Scene control #p49-50
-                               'Contrast' => Exif::SHORT, # Contrast #p50
-                               'Saturation' => Exif::SHORT, # Saturation #p50
-                               'Sharpness' => Exif::SHORT, # Sharpness #p50
-                               'DeviceSettingDescription' => Exif::IGNORE,
+                               'ShutterSpeedValue' => self::SRATIONAL, # Shutter speed
+                               'ApertureValue' => self::RATIONAL, # Aperture
+                               'BrightnessValue' => self::SRATIONAL, # Brightness
+                               'ExposureBiasValue' => self::SRATIONAL, # Exposure bias
+                               'MaxApertureValue' => self::RATIONAL, # Maximum land aperture
+                               'SubjectDistance' => self::RATIONAL, # Subject distance
+                               'MeteringMode' => self::SHORT, # Metering mode #p40
+                               'LightSource' => self::SHORT, # Light source #p40-41
+                               'Flash' => self::SHORT, # Flash #p41-42
+                               'FocalLength' => self::RATIONAL, # Lens focal length
+                               'SubjectArea' => [ self::SHORT, 4 ], # Subject area
+                               'FlashEnergy' => self::RATIONAL, # Flash energy
+                               'SpatialFrequencyResponse' => self::IGNORE, # Spatial frequency response. Not supported atm.
+                               'FocalPlaneXResolution' => self::RATIONAL, # Focal plane X resolution
+                               'FocalPlaneYResolution' => self::RATIONAL, # Focal plane Y resolution
+                               'FocalPlaneResolutionUnit' => self::SHORT, # Focal plane resolution unit #p46
+                               'SubjectLocation' => [ self::SHORT, 2 ], # Subject location
+                               'ExposureIndex' => self::RATIONAL, # Exposure index
+                               'SensingMethod' => self::SHORT, # Sensing method #p46
+                               'FileSource' => self::UNDEFINED, # File source #p47
+                               'SceneType' => self::UNDEFINED, # Scene type #p47
+                               'CFAPattern' => self::IGNORE, # CFA pattern. not supported atm.
+                               'CustomRendered' => self::SHORT, # Custom image processing #p48
+                               'ExposureMode' => self::SHORT, # Exposure mode #p48
+                               'WhiteBalance' => self::SHORT, # White Balance #p49
+                               'DigitalZoomRatio' => self::RATIONAL, # Digital zoom ration
+                               'FocalLengthIn35mmFilm' => self::SHORT, # Focal length in 35 mm film
+                               'SceneCaptureType' => self::SHORT, # Scene capture type #p49
+                               'GainControl' => self::SHORT, # Scene control #p49-50
+                               'Contrast' => self::SHORT, # Contrast #p50
+                               'Saturation' => self::SHORT, # Saturation #p50
+                               'Sharpness' => self::SHORT, # Sharpness #p50
+                               'DeviceSettingDescription' => self::IGNORE,
                                # Device settings description. This could maybe be supported. Need to find an
                                # example file that uses this to see if it has stuff of interest in it.
-                               'SubjectDistanceRange' => Exif::SHORT, # Subject distance range #p51
+                               'SubjectDistanceRange' => self::SHORT, # Subject distance range #p51
 
-                               'ImageUniqueID' => Exif::ASCII, # Unique image ID
+                               'ImageUniqueID' => self::ASCII, # Unique image ID
                        ],
 
                        # GPS Attribute Information (p52)
                        'GPS' => [
-                               'GPSVersion' => Exif::UNDEFINED,
+                               'GPSVersion' => self::UNDEFINED,
                                # Should be an array of 4 Exif::BYTE's. However php treats it as an undefined
                                # Note exif standard calls this GPSVersionID, but php doesn't like the id suffix
-                               'GPSLatitudeRef' => Exif::ASCII, # North or South Latitude #p52-53
-                               'GPSLatitude' => [ Exif::RATIONAL, 3 ], # Latitude
-                               'GPSLongitudeRef' => Exif::ASCII, # East or West Longitude #p53
-                               'GPSLongitude' => [ Exif::RATIONAL, 3 ], # Longitude
-                               'GPSAltitudeRef' => Exif::UNDEFINED,
+                               'GPSLatitudeRef' => self::ASCII, # North or South Latitude #p52-53
+                               'GPSLatitude' => [ self::RATIONAL, 3 ], # Latitude
+                               'GPSLongitudeRef' => self::ASCII, # East or West Longitude #p53
+                               'GPSLongitude' => [ self::RATIONAL, 3 ], # Longitude
+                               'GPSAltitudeRef' => self::UNDEFINED,
                                # Altitude reference. Note, the exif standard says this should be an EXIF::Byte,
                                # but php seems to disagree.
-                               'GPSAltitude' => Exif::RATIONAL, # Altitude
-                               'GPSTimeStamp' => [ Exif::RATIONAL, 3 ], # GPS time (atomic clock)
-                               'GPSSatellites' => Exif::ASCII, # Satellites used for measurement
-                               'GPSStatus' => Exif::ASCII, # Receiver status #p54
-                               'GPSMeasureMode' => Exif::ASCII, # Measurement mode #p54-55
-                               'GPSDOP' => Exif::RATIONAL, # Measurement precision
-                               'GPSSpeedRef' => Exif::ASCII, # Speed unit #p55
-                               'GPSSpeed' => Exif::RATIONAL, # Speed of GPS receiver
-                               'GPSTrackRef' => Exif::ASCII, # Reference for direction of movement #p55
-                               'GPSTrack' => Exif::RATIONAL, # Direction of movement
-                               'GPSImgDirectionRef' => Exif::ASCII, # Reference for direction of image #p56
-                               'GPSImgDirection' => Exif::RATIONAL, # Direction of image
-                               'GPSMapDatum' => Exif::ASCII, # Geodetic survey data used
-                               'GPSDestLatitudeRef' => Exif::ASCII, # Reference for latitude of destination #p56
-                               'GPSDestLatitude' => [ Exif::RATIONAL, 3 ], # Latitude destination
-                               'GPSDestLongitudeRef' => Exif::ASCII, # Reference for longitude of destination #p57
-                               'GPSDestLongitude' => [ Exif::RATIONAL, 3 ], # Longitude of destination
-                               'GPSDestBearingRef' => Exif::ASCII, # Reference for bearing of destination #p57
-                               'GPSDestBearing' => Exif::RATIONAL, # Bearing of destination
-                               'GPSDestDistanceRef' => Exif::ASCII, # Reference for distance to destination #p57-58
-                               'GPSDestDistance' => Exif::RATIONAL, # Distance to destination
-                               'GPSProcessingMethod' => Exif::UNDEFINED, # Name of GPS processing method
-                               'GPSAreaInformation' => Exif::UNDEFINED, # Name of GPS area
-                               'GPSDateStamp' => Exif::ASCII, # GPS date
-                               'GPSDifferential' => Exif::SHORT, # GPS differential correction
+                               'GPSAltitude' => self::RATIONAL, # Altitude
+                               'GPSTimeStamp' => [ self::RATIONAL, 3 ], # GPS time (atomic clock)
+                               'GPSSatellites' => self::ASCII, # Satellites used for measurement
+                               'GPSStatus' => self::ASCII, # Receiver status #p54
+                               'GPSMeasureMode' => self::ASCII, # Measurement mode #p54-55
+                               'GPSDOP' => self::RATIONAL, # Measurement precision
+                               'GPSSpeedRef' => self::ASCII, # Speed unit #p55
+                               'GPSSpeed' => self::RATIONAL, # Speed of GPS receiver
+                               'GPSTrackRef' => self::ASCII, # Reference for direction of movement #p55
+                               'GPSTrack' => self::RATIONAL, # Direction of movement
+                               'GPSImgDirectionRef' => self::ASCII, # Reference for direction of image #p56
+                               'GPSImgDirection' => self::RATIONAL, # Direction of image
+                               'GPSMapDatum' => self::ASCII, # Geodetic survey data used
+                               'GPSDestLatitudeRef' => self::ASCII, # Reference for latitude of destination #p56
+                               'GPSDestLatitude' => [ self::RATIONAL, 3 ], # Latitude destination
+                               'GPSDestLongitudeRef' => self::ASCII, # Reference for longitude of destination #p57
+                               'GPSDestLongitude' => [ self::RATIONAL, 3 ], # Longitude of destination
+                               'GPSDestBearingRef' => self::ASCII, # Reference for bearing of destination #p57
+                               'GPSDestBearing' => self::RATIONAL, # Bearing of destination
+                               'GPSDestDistanceRef' => self::ASCII, # Reference for distance to destination #p57-58
+                               'GPSDestDistance' => self::RATIONAL, # Distance to destination
+                               'GPSProcessingMethod' => self::UNDEFINED, # Name of GPS processing method
+                               'GPSAreaInformation' => self::UNDEFINED, # Name of GPS area
+                               'GPSDateStamp' => self::ASCII, # GPS date
+                               'GPSDifferential' => self::SHORT, # GPS differential correction
                        ],
                ];
 
@@ -761,43 +759,43 @@ class Exif {
                }
                // Does not work if not typecast
                switch ( (string)$etype ) {
-                       case (string)Exif::BYTE:
+                       case (string)self::BYTE:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isByte( $val );
-                       case (string)Exif::ASCII:
+                       case (string)self::ASCII:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isASCII( $val );
-                       case (string)Exif::SHORT:
+                       case (string)self::SHORT:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isShort( $val );
-                       case (string)Exif::LONG:
+                       case (string)self::LONG:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isLong( $val );
-                       case (string)Exif::RATIONAL:
+                       case (string)self::RATIONAL:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isRational( $val );
-                       case (string)Exif::SHORT_OR_LONG:
+                       case (string)self::SHORT_OR_LONG:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isShort( $val ) || $this->isLong( $val );
-                       case (string)Exif::UNDEFINED:
+                       case (string)self::UNDEFINED:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isUndefined( $val );
-                       case (string)Exif::SLONG:
+                       case (string)self::SLONG:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isSlong( $val );
-                       case (string)Exif::SRATIONAL:
+                       case (string)self::SRATIONAL:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return $this->isSrational( $val );
-                       case (string)Exif::IGNORE:
+                       case (string)self::IGNORE:
                                $this->debug( $val, __FUNCTION__, $debug );
 
                                return false;
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 d13fb3c..e2cf2cf 100644 (file)
@@ -1594,7 +1594,7 @@ class Article implements Page {
                        [ 'delete', $this->getTitle()->getPrefixedText() ] )
                ) {
                        # Flag to hide all contents of the archived revisions
-                       $suppress = $request->getVal( 'wpSuppress' ) && $user->isAllowed( 'suppressrevision' );
+                       $suppress = $request->getCheck( 'wpSuppress' ) && $user->isAllowed( 'suppressrevision' );
 
                        $this->doDelete( $reason, $suppress );
 
@@ -1669,7 +1669,6 @@ class Article implements Page {
                $title = $this->getTitle();
                $ctx = $this->getContext();
                $outputPage = $ctx->getOutput();
-               $useMediaWikiUIEverywhere = $ctx->getConfig()->get( 'UseMediaWikiUIEverywhere' );
                $outputPage->setPageTitle( wfMessage( 'delete-confirm', $title->getPrefixedText() ) );
                $outputPage->addBacklinkSubtitle( $title );
                $outputPage->setRobotPolicy( 'noindex,nofollow' );
@@ -1692,14 +1691,6 @@ class Article implements Page {
                Hooks::run( 'ArticleConfirmDelete', [ $this, $outputPage, &$reason ] );
 
                $user = $this->getContext()->getUser();
-               if ( $user->isAllowed( 'suppressrevision' ) ) {
-                       $suppress = Html::openElement( 'div', [ 'id' => 'wpDeleteSuppressRow' ] ) .
-                               Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
-                                       'wpSuppress', 'wpSuppress', false, [ 'tabindex' => '4' ] ) .
-                               Html::closeElement( 'div' );
-               } else {
-                       $suppress = '';
-               }
                $checkWatch = $user->getBoolOption( 'watchdeletion' ) || $user->isWatched( $title );
 
                $outputPage->enableOOUI();
@@ -1770,6 +1761,21 @@ class Article implements Page {
                        );
                }
 
+               if ( $user->isAllowed( 'suppressrevision' ) ) {
+                       $fields[] = new OOUI\FieldLayout(
+                               new OOUI\CheckboxInputWidget( [
+                                       'name' => 'wpSuppress',
+                                       'inputId' => 'wpSuppress',
+                                       'tabIndex' => 4,
+                               ] ),
+                               [
+                                       'label' => $ctx->msg( 'revdelete-suppress' )->text(),
+                                       'align' => 'inline',
+                                       'infusable' => true,
+                               ]
+                       );
+               }
+
                $fields[] = new OOUI\FieldLayout(
                        new OOUI\ButtonInputWidget( [
                                'name' => 'wpConfirmB',
index 20fb9be..c05ba45 100644 (file)
@@ -50,7 +50,7 @@ class WikiPage implements Page, IDBAccessObject {
        public $mLatest = false;             // !< Integer (false means "not loaded")
        /**@}}*/
 
-       /** @var stdClass Map of cache fields (text, parser output, ect) for a proposed/new edit */
+       /** @var PreparedEdit Map of cache fields (text, parser output, ect) for a proposed/new edit */
        public $mPreparedEdit = false;
 
        /**
@@ -782,7 +782,7 @@ class WikiPage implements Page, IDBAccessObject {
         * Determine whether a page would be suitable for being counted as an
         * article in the site_stats table based on the title & its content
         *
-        * @param object|bool $editInfo (false): object returned by prepareTextForEdit(),
+        * @param PreparedEdit|bool $editInfo (false): object returned by prepareTextForEdit(),
         *   if false, the current database state will be used
         * @return bool
         */
@@ -1607,7 +1607,7 @@ class WikiPage implements Page, IDBAccessObject {
                $meta = [
                        'bot' => ( $flags & EDIT_FORCE_BOT ),
                        'minor' => ( $flags & EDIT_MINOR ) && $user->isAllowed( 'minoredit' ),
-                       'serialized' => $editInfo->pst,
+                       'serialized' => $pstContent->serialize( $serialFormat ),
                        'serialFormat' => $serialFormat,
                        'baseRevId' => $baseRevId,
                        'oldRevision' => $old_revision,
@@ -1961,7 +1961,9 @@ class WikiPage implements Page, IDBAccessObject {
 
        /**
         * Prepare content which is about to be saved.
-        * Returns a stdClass with source, pst and output members
+        *
+        * Prior to 1.30, this returned a stdClass object with the same class
+        * members.
         *
         * @param Content $content
         * @param Revision|int|null $revision Revision object. For backwards compatibility, a
@@ -2971,7 +2973,7 @@ class WikiPage implements Page, IDBAccessObject {
                }
 
                // Clear caches
-               WikiPage::onArticleDelete( $this->mTitle );
+               self::onArticleDelete( $this->mTitle );
                ResourceLoaderWikiModule::invalidateModuleCache(
                        $this->mTitle, $revision, null, wfWikiID()
                );
index 0b867ef..6620c47 100644 (file)
@@ -737,6 +737,6 @@ abstract class IndexPager extends ContextSource implements Pager {
         * @return bool
         */
        protected function getDefaultDirections() {
-               return IndexPager::DIR_ASCENDING;
+               return self::DIR_ASCENDING;
        }
 }
index 5da2546..b035b02 100644 (file)
@@ -227,7 +227,7 @@ class Parser {
         * @var string Deprecated accessor for the strip marker prefix.
         * @deprecated since 1.26; use Parser::MARKER_PREFIX instead.
         */
-       public $mUniqPrefix = Parser::MARKER_PREFIX;
+       public $mUniqPrefix = self::MARKER_PREFIX;
 
        /**
         * @var array Array with the language name of each language link (i.e. the
@@ -1295,7 +1295,7 @@ class Parser {
                        if ( !$frame->depth ) {
                                $flag = 0;
                        } else {
-                               $flag = Parser::PTD_FOR_INCLUSION;
+                               $flag = self::PTD_FOR_INCLUSION;
                        }
                        $dom = $this->preprocessToDom( $text, $flag );
                        $text = $frame->expand( $dom );
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 10ac192..cfb0c3e 100644 (file)
@@ -253,7 +253,7 @@ class ParserOutput extends CacheTime {
                $text = $this->mText;
                if ( $this->mEditSectionTokens ) {
                        $text = preg_replace_callback(
-                               ParserOutput::EDITSECTION_REGEX,
+                               self::EDITSECTION_REGEX,
                                function ( $m ) {
                                        global $wgOut, $wgLang;
                                        $editsectionPage = Title::newFromText( htmlspecialchars_decode( $m[1] ) );
@@ -274,7 +274,7 @@ class ParserOutput extends CacheTime {
                                $text
                        );
                } else {
-                       $text = preg_replace( ParserOutput::EDITSECTION_REGEX, '', $text );
+                       $text = preg_replace( self::EDITSECTION_REGEX, '', $text );
                }
 
                // If you have an old cached version of this class - sorry, you can't disable the TOC
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 8553116..2f29200 100644 (file)
@@ -178,7 +178,7 @@ class ResourceLoader implements LoggerAwareInterface {
         * @return string Filtered data, or a comment containing an error message
         */
        public static function filter( $filter, $data, array $options = [] ) {
-               if ( strpos( $data, ResourceLoader::FILTER_NOMIN ) !== false ) {
+               if ( strpos( $data, self::FILTER_NOMIN ) !== false ) {
                        return $data;
                }
 
@@ -1079,7 +1079,7 @@ MESSAGE;
                                                                // mw.loader.implement will use globalEval if scripts is a string.
                                                                // Minify manually here, because general response minification is
                                                                // not effective due it being a string literal, not a function.
-                                                               if ( !ResourceLoader::inDebugMode() ) {
+                                                               if ( !self::inDebugMode() ) {
                                                                        $scripts = self::filter( 'minify-js', $scripts ); // T107377
                                                                }
                                                        } else {
@@ -1139,7 +1139,7 @@ MESSAGE;
                } else {
                        if ( count( $states ) ) {
                                $this->errors[] = 'Problematic modules: ' .
-                                       FormatJson::encode( $states, ResourceLoader::inDebugMode() );
+                                       FormatJson::encode( $states, self::inDebugMode() );
                        }
                }
 
@@ -1214,7 +1214,7 @@ MESSAGE;
                ];
                self::trimArray( $module );
 
-               return Xml::encodeJsCall( 'mw.loader.implement', $module, ResourceLoader::inDebugMode() );
+               return Xml::encodeJsCall( 'mw.loader.implement', $module, self::inDebugMode() );
        }
 
        /**
@@ -1228,7 +1228,7 @@ MESSAGE;
                return Xml::encodeJsCall(
                        'mw.messages.set',
                        [ (object)$messages ],
-                       ResourceLoader::inDebugMode()
+                       self::inDebugMode()
                );
        }
 
@@ -1285,13 +1285,13 @@ MESSAGE;
                        return Xml::encodeJsCall(
                                'mw.loader.state',
                                [ $name ],
-                               ResourceLoader::inDebugMode()
+                               self::inDebugMode()
                        );
                } else {
                        return Xml::encodeJsCall(
                                'mw.loader.state',
                                [ $name, $state ],
-                               ResourceLoader::inDebugMode()
+                               self::inDebugMode()
                        );
                }
        }
@@ -1317,7 +1317,7 @@ MESSAGE;
                return Xml::encodeJsCall(
                        "( function ( name, version, dependencies, group, source ) {\n\t$script\n} )",
                        [ $name, $version, $dependencies, $group, $source ],
-                       ResourceLoader::inDebugMode()
+                       self::inDebugMode()
                );
        }
 
@@ -1409,7 +1409,7 @@ MESSAGE;
                        return Xml::encodeJsCall(
                                'mw.loader.register',
                                [ $name ],
-                               ResourceLoader::inDebugMode()
+                               self::inDebugMode()
                        );
                } else {
                        $registration = [ $name, $version, $dependencies, $group, $source, $skip ];
@@ -1417,7 +1417,7 @@ MESSAGE;
                        return Xml::encodeJsCall(
                                'mw.loader.register',
                                $registration,
-                               ResourceLoader::inDebugMode()
+                               self::inDebugMode()
                        );
                }
        }
@@ -1441,13 +1441,13 @@ MESSAGE;
                        return Xml::encodeJsCall(
                                'mw.loader.addSource',
                                [ $id ],
-                               ResourceLoader::inDebugMode()
+                               self::inDebugMode()
                        );
                } else {
                        return Xml::encodeJsCall(
                                'mw.loader.addSource',
                                [ $id, $loadUrl ],
-                               ResourceLoader::inDebugMode()
+                               self::inDebugMode()
                        );
                }
        }
@@ -1494,7 +1494,7 @@ MESSAGE;
                return Xml::encodeJsCall(
                        'mw.config.set',
                        [ $configuration ],
-                       ResourceLoader::inDebugMode()
+                       self::inDebugMode()
                );
        }
 
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 a8f9d0c..40905a5 100644 (file)
@@ -95,7 +95,7 @@ abstract class Skin extends ContextSource {
        static function normalizeKey( $key ) {
                global $wgDefaultSkin, $wgFallbackSkin;
 
-               $skinNames = Skin::getSkinNames();
+               $skinNames = self::getSkinNames();
 
                // Make keys lowercase for case-insensitive matching.
                $skinNames = array_change_key_case( $skinNames, CASE_LOWER );
index 67c14d8..4c3ca54 100644 (file)
@@ -383,7 +383,7 @@ class SpecialPage implements MessageLocalizer {
                        return true;
                } elseif ( $securityStatus === AuthManager::SEC_REAUTH ) {
                        $request = $this->getRequest();
-                       $title = SpecialPage::getTitleFor( 'Userlogin' );
+                       $title = self::getTitleFor( 'Userlogin' );
                        $query = [
                                'returnto' => $this->getFullTitle()->getPrefixedDBkey(),
                                'returntoquery' => wfArrayToCgi( array_diff_key( $request->getQueryValues(),
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..a05900b 100644 (file)
@@ -315,7 +315,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                $opts = parent::getDefaultOptions();
                $user = $this->getUser();
 
-               $opts->add( 'days', $user->getIntOption( 'rcdays' ) );
+               $opts->add( 'days', $user->getIntOption( 'rcdays' ), FormOptions::FLOAT );
                $opts->add( 'limit', $user->getIntOption( 'rclimit' ) );
                $opts->add( 'from', '' );
 
@@ -359,7 +359,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                        if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
                                $opts['limit'] = $m[1];
                        }
-                       if ( preg_match( '/^days=(\d+)$/', $bit, $m ) ) {
+                       if ( preg_match( '/^days=(\d+(?:\.\d+)?)$/', $bit, $m ) ) {
                                $opts['days'] = $m[1];
                        }
                        if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
@@ -388,7 +388,6 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
 
                // Calculate cutoff
                $cutoff_unixtime = time() - ( $opts['days'] * 86400 );
-               $cutoff_unixtime = $cutoff_unixtime - ( $cutoff_unixtime % 86400 );
                $cutoff = $dbr->timestamp( $cutoff_unixtime );
 
                $fromValid = preg_match( '/^[0-9]{14}$/', $opts['from'] );
@@ -669,6 +668,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 +685,9 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                                        $rcfilterContainer . $rcoptions
                                )
                        );
+
+                       // Add spinner
+                       $this->getOutput()->addHTML( $loadingContainer );
                } else {
                        $this->getOutput()->addHTML( $rcoptions );
                }
index 451669c..4f29082 100644 (file)
@@ -130,9 +130,29 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
                        );
                }
 
-               if ( $includesRestrictedPages || $includesCachedPages ) {
-                       $out->wrapWikiMsg( "<h2 class=\"mw-specialpages-note-top\">$1</h2>", 'specialpages-note-top' );
-                       $out->wrapWikiMsg( "<div class=\"mw-specialpages-notes\">\n$1\n</div>", 'specialpages-note' );
+               // add legend
+               $notes = [];
+               if ( $includesRestrictedPages ) {
+                       $restricedMsg = $this->msg( 'specialpages-note-restricted' );
+                       if ( !$restricedMsg->isDisabled() ) {
+                               $notes[] = $restricedMsg->plain();
+                       }
+               }
+               if ( $includesCachedPages ) {
+                       $cachedMsg = $this->msg( 'specialpages-note-cached' );
+                       if ( !$cachedMsg->isDisabled() ) {
+                               $notes[] = $cachedMsg->plain();
+                       }
+               }
+               if ( $notes !== [] ) {
+                       $out->wrapWikiMsg(
+                               "<h2 class=\"mw-specialpages-note-top\">$1</h2>", 'specialpages-note-top'
+                       );
+                       $out->addWikiText(
+                               "<div class=\"mw-specialpages-notes\">\n" .
+                               implode( "\n", $notes ) .
+                               "\n</div>"
+                       );
                }
        }
 }
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 7fa03ba..10baadf 100644 (file)
@@ -275,17 +275,6 @@ class UsersPager extends AlphabeticPager {
                        $groupOptions[ $groupText ] = $group;
                }
 
-               $optionsDefault = [];
-               if ( $this->editsOnly ) {
-                       $optionsDefault[] = 'editsOnly';
-               }
-               if ( $this->creationSort ) {
-                       $optionsDefault[] = 'creationSort';
-               }
-               if ( $this->mDefaultDirection ) {
-                       $optionsDefault[] = 'desc';
-               }
-
                $formDescriptor = [
                        'user' => [
                                'class' => 'HTMLUserTextField',
@@ -300,14 +289,26 @@ class UsersPager extends AlphabeticPager {
                                'class' => 'HTMLSelectField',
                                'options' => $groupOptions,
                        ],
-                       'options' => [
-                               'class' => 'HTMLMultiSelectField',
-                               'options' => [
-                                       $this->msg( 'listusers-editsonly' )->text() => 'editsOnly',
-                                       $this->msg( 'listusers-creationsort' )->text() => 'creationSort',
-                                       $this->msg( 'listusers-desc' )->text() => 'desc'
-                               ],
-                               'default' => $optionsDefault
+                       'editsOnly' => [
+                               'type' => 'check',
+                               'label' => $this->msg( 'listusers-editsonly' )->text(),
+                               'name' => 'editsOnly',
+                               'id' => 'editsOnly',
+                               'value' => $this->editsOnly
+                       ],
+                       'creationSort' => [
+                               'type' => 'check',
+                               'label' => $this->msg( 'listusers-creationsort' )->text(),
+                               'name' => 'creationSort',
+                               'id' => 'creationSort',
+                               'value' => $this->creationSort
+                       ],
+                       'desc' => [
+                               'type' => 'check',
+                               'label' => $this->msg( 'listusers-desc' )->text(),
+                               'name' => 'desc',
+                               'id' => 'desc',
+                               'value' => $this->mDefaultDirection
                        ],
                        'limithiddenfield' => [
                                'class' => 'HTMLHiddenField',
index b0c12e4..4852ce5 100644 (file)
@@ -2156,7 +2156,7 @@ class Balancer {
                if (
                        $this->allowComments &&
                        !( $this->inRCDATA || $this->inRAWTEXT ) &&
-                       preg_match( Balancer::VALID_COMMENT_REGEX, $x, $regs, PREG_OFFSET_CAPTURE ) &&
+                       preg_match( self::VALID_COMMENT_REGEX, $x, $regs, PREG_OFFSET_CAPTURE ) &&
                        // verify EOF condition where necessary
                        ( $regs[4][1] < 0 || !$this->bitsIterator->valid() )
                ) {
index dbcf568..a797398 100644 (file)
@@ -81,8 +81,6 @@ class RemexCompatMunger implements TreeHandler {
        ];
 
        /**
-        * Constructor
-        *
         * @param Serializer $serializer
         */
        public function __construct( Serializer $serializer ) {
index 9a955fb..25625e7 100644 (file)
@@ -411,7 +411,7 @@ class BotPassword implements IDBAccessObject {
         * @return array|false
         */
        public static function canonicalizeLoginData( $username, $password ) {
-               $sep = BotPassword::getSeparator();
+               $sep = self::getSeparator();
                // the strlen check helps minimize the password information obtainable from timing
                if ( strlen( $password ) >= 32 && strpos( $username, $sep ) !== false ) {
                        // the separator is not valid in new usernames but might appear in legacy ones
index 7bf6be5..fa84c94 100644 (file)
@@ -603,7 +603,7 @@ class User implements IDBAccessObject {
                        ]
                );
 
-               return $id ? User::newFromId( $id ) : null;
+               return $id ? self::newFromId( $id ) : null;
        }
 
        /**
@@ -842,7 +842,7 @@ class User implements IDBAccessObject {
                global $wgContLang, $wgMaxNameChars;
 
                if ( $name == ''
-                       || User::isIP( $name )
+                       || self::isIP( $name )
                        || strpos( $name, '/' ) !== false
                        || strlen( $name ) > $wgMaxNameChars
                        || $name != $wgContLang->ucfirst( $name )
@@ -1109,17 +1109,17 @@ class User implements IDBAccessObject {
                        case false:
                                break;
                        case 'valid':
-                               if ( !User::isValidUserName( $name ) ) {
+                               if ( !self::isValidUserName( $name ) ) {
                                        $name = false;
                                }
                                break;
                        case 'usable':
-                               if ( !User::isUsableName( $name ) ) {
+                               if ( !self::isUsableName( $name ) ) {
                                        $name = false;
                                }
                                break;
                        case 'creatable':
-                               if ( !User::isCreatableName( $name ) ) {
+                               if ( !self::isCreatableName( $name ) ) {
                                        $name = false;
                                }
                                break;
@@ -1591,7 +1591,7 @@ class User implements IDBAccessObject {
                // since extensions may change the set of searchable namespaces depending
                // on user groups/permissions.
                foreach ( $wgNamespacesToBeSearchedDefault as $nsnum => $val ) {
-                       $defOpt['searchNs' . $nsnum] = (boolean)$val;
+                       $defOpt['searchNs' . $nsnum] = (bool)$val;
                }
                $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
 
@@ -2212,7 +2212,7 @@ class User implements IDBAccessObject {
         * @return int The user's ID; 0 if the user is anonymous or nonexistent
         */
        public function getId() {
-               if ( $this->mId === null && $this->mName !== null && User::isIP( $this->mName ) ) {
+               if ( $this->mId === null && $this->mName !== null && self::isIP( $this->mName ) ) {
                        // Special case, we know the user is anonymous
                        return 0;
                } elseif ( !$this->isItemLoaded( 'id' ) ) {
@@ -4131,7 +4131,7 @@ class User implements IDBAccessObject {
                }
                $dbw->insert( 'user', $fields, __METHOD__, [ 'IGNORE' ] );
                if ( $dbw->affectedRows() ) {
-                       $newUser = User::newFromId( $dbw->insertId() );
+                       $newUser = self::newFromId( $dbw->insertId() );
                } else {
                        $newUser = null;
                }
@@ -5036,7 +5036,7 @@ class User implements IDBAccessObject {
                        // Do nothing
                } elseif ( $wgGroupsAddToSelf[$group] === true ) {
                        // No idea WHY this would be used, but it's there
-                       $groups['add-self'] = User::getAllGroups();
+                       $groups['add-self'] = self::getAllGroups();
                } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
                        $groups['add-self'] = $wgGroupsAddToSelf[$group];
                }
@@ -5044,7 +5044,7 @@ class User implements IDBAccessObject {
                if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
                        // Do nothing
                } elseif ( $wgGroupsRemoveFromSelf[$group] === true ) {
-                       $groups['remove-self'] = User::getAllGroups();
+                       $groups['remove-self'] = self::getAllGroups();
                } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
                        $groups['remove-self'] = $wgGroupsRemoveFromSelf[$group];
                }
@@ -5065,7 +5065,7 @@ class User implements IDBAccessObject {
                        // compatibility with old "userrights lets you change
                        // everything")
                        // Using array_merge to make the groups reindexed
-                       $all = array_merge( User::getAllGroups() );
+                       $all = array_merge( self::getAllGroups() );
                        return [
                                'add' => $all,
                                'remove' => $all,
@@ -5491,7 +5491,7 @@ class User implements IDBAccessObject {
                global $wgLang;
 
                $groups = [];
-               foreach ( User::getGroupsWithPermission( $permission ) as $group ) {
+               foreach ( self::getGroupsWithPermission( $permission ) as $group ) {
                        $groups[] = UserGroupMembership::getLink( $group, RequestContext::getMain(), 'wiki' );
                }
 
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 83dff65..12f26c3 100644 (file)
@@ -208,11 +208,11 @@ class Language {
         * @return Language
         */
        protected static function newFromCode( $code, $fallback = false ) {
-               if ( !Language::isValidCode( $code ) ) {
+               if ( !self::isValidCode( $code ) ) {
                        throw new MWException( "Invalid language code \"$code\"" );
                }
 
-               if ( !Language::isValidBuiltInCode( $code ) ) {
+               if ( !self::isValidBuiltInCode( $code ) ) {
                        // It's not possible to customise this code with class files, so
                        // just return a Language object. This is to support uselang= hacks.
                        $lang = new Language;
@@ -228,9 +228,9 @@ class Language {
                }
 
                // Keep trying the fallback list until we find an existing class
-               $fallbacks = Language::getFallbacksFor( $code );
+               $fallbacks = self::getFallbacksFor( $code );
                foreach ( $fallbacks as $fallbackCode ) {
-                       if ( !Language::isValidBuiltInCode( $fallbackCode ) ) {
+                       if ( !self::isValidBuiltInCode( $fallbackCode ) ) {
                                throw new MWException( "Invalid fallback '$fallbackCode' in fallback sequence for '$code'" );
                        }
 
@@ -829,7 +829,7 @@ class Language {
                global $wgExtraLanguageNames, $wgUsePigLatinVariant;
 
                // If passed an invalid language code to use, fallback to en
-               if ( $inLanguage !== null && !Language::isValidCode( $inLanguage ) ) {
+               if ( $inLanguage !== null && !self::isValidCode( $inLanguage ) ) {
                        $inLanguage = 'en';
                }
 
@@ -1192,7 +1192,7 @@ class Language {
                                case 'D':
                                        $usedDay = true;
                                        $s .= $this->getWeekdayAbbreviation(
-                                               Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'w' ) + 1
+                                               self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'w' ) + 1
                                        );
                                        break;
                                case 'j':
@@ -1223,7 +1223,7 @@ class Language {
                                case 'l':
                                        $usedDay = true;
                                        $s .= $this->getWeekdayName(
-                                               Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'w' ) + 1
+                                               self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'w' ) + 1
                                        );
                                        break;
                                case 'F':
@@ -1404,36 +1404,36 @@ class Language {
                                case 'O':
                                case 'P':
                                case 'T':
-                                       $s .= Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $s .= self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case 'w':
                                case 'N':
                                case 'z':
                                        $usedDay = true;
-                                       $num = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case 'W':
                                        $usedWeek = true;
-                                       $num = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case 't':
                                        $usedMonth = true;
-                                       $num = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case 'L':
                                        $usedIsLeapYear = true;
-                                       $num = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case 'o':
                                        $usedISOYear = true;
-                                       $num = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case 'U':
                                        $usedSecond = true;
                                        // fall through
                                case 'I':
                                case 'Z':
-                                       $num = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
+                                       $num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
                                        break;
                                case '\\':
                                        # Backslash escaping
@@ -1467,7 +1467,7 @@ class Language {
                                        $s .= $num;
                                        $raw = false;
                                } elseif ( $roman ) {
-                                       $s .= Language::romanNumeral( $num );
+                                       $s .= self::romanNumeral( $num );
                                        $roman = false;
                                } elseif ( $hebrewNum ) {
                                        $s .= self::hebrewNumeral( $num );
@@ -1509,7 +1509,7 @@ class Language {
                                substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
                        if ( $usedWeek ) {
                                $possibleTtls[] =
-                                       ( 7 - Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'N' ) ) * 86400 +
+                                       ( 7 - self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'N' ) ) * 86400 +
                                        $timeRemainingInDay;
                        } elseif ( $usedISOYear ) {
                                // December 28th falls on the last ISO week of the year, every year.
@@ -1519,29 +1519,29 @@ class Language {
                                        substr( $ts, 0, 4 ) . '1228',
                                        $zone ?: new DateTimeZone( 'UTC' )
                                )->format( 'W' );
-                               $currentISOWeek = Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'W' );
+                               $currentISOWeek = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'W' );
                                $weeksRemaining = $lastWeekOfISOYear - $currentISOWeek;
                                $timeRemainingInWeek =
-                                       ( 7 - Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'N' ) ) * 86400
+                                       ( 7 - self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'N' ) ) * 86400
                                        + $timeRemainingInDay;
                                $possibleTtls[] = $weeksRemaining * 604800 + $timeRemainingInWeek;
                        }
 
                        if ( $usedMonth ) {
                                $possibleTtls[] =
-                                       ( Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 't' ) -
+                                       ( self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 't' ) -
                                                substr( $ts, 6, 2 ) ) * 86400
                                        + $timeRemainingInDay;
                        } elseif ( $usedYear ) {
                                $possibleTtls[] =
-                                       ( Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'L' ) + 364 -
-                                               Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'z' ) ) * 86400
+                                       ( self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'L' ) + 364 -
+                                               self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'z' ) ) * 86400
                                        + $timeRemainingInDay;
                        } elseif ( $usedIsLeapYear ) {
                                $year = substr( $ts, 0, 4 );
                                $timeRemainingInYear =
-                                       ( Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'L' ) + 364 -
-                                               Language::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'z' ) ) * 86400
+                                       ( self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'L' ) + 364 -
+                                               self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'z' ) ) * 86400
                                        + $timeRemainingInDay;
                                $mod = $year % 4;
                                if ( $mod || ( !( $year % 100 ) && $year % 400 ) ) {
@@ -3956,7 +3956,7 @@ class Language {
         * @return string Text, wrapped in LRE...PDF or RLE...PDF or nothing
         */
        public function embedBidi( $text = '' ) {
-               $dir = Language::strongDirFromContent( $text );
+               $dir = self::strongDirFromContent( $text );
                if ( $dir === 'ltr' ) {
                        // Wrap in LEFT-TO-RIGHT EMBEDDING ... POP DIRECTIONAL FORMATTING
                        return self::$lre . $text . self::$pdf;
@@ -4264,7 +4264,7 @@ class Language {
                        $this->mParentLanguage = null;
                        return null;
                }
-               $lang = Language::factory( $code );
+               $lang = self::factory( $code );
                if ( !$lang->hasVariant( $this->getCode() ) ) {
                        $this->mParentLanguage = null;
                        return null;
@@ -4420,7 +4420,7 @@ class Language {
         * @return array Non-empty array, ending in "en"
         */
        public static function getFallbacksFor( $code ) {
-               if ( $code === 'en' || !Language::isValidBuiltInCode( $code ) ) {
+               if ( $code === 'en' || !self::isValidBuiltInCode( $code ) ) {
                        return [];
                }
                // For unknown languages, fallbackSequence returns an empty array,
@@ -4821,7 +4821,7 @@ class Language {
         */
        public function getCompiledPluralRules() {
                $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'compiledPluralRules' );
-               $fallbacks = Language::getFallbacksFor( $this->mCode );
+               $fallbacks = self::getFallbacksFor( $this->mCode );
                if ( !$pluralRules ) {
                        foreach ( $fallbacks as $fallbackCode ) {
                                $pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ), 'compiledPluralRules' );
@@ -4840,7 +4840,7 @@ class Language {
         */
        public function getPluralRules() {
                $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRules' );
-               $fallbacks = Language::getFallbacksFor( $this->mCode );
+               $fallbacks = self::getFallbacksFor( $this->mCode );
                if ( !$pluralRules ) {
                        foreach ( $fallbacks as $fallbackCode ) {
                                $pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ), 'pluralRules' );
@@ -4859,7 +4859,7 @@ class Language {
         */
        public function getPluralRuleTypes() {
                $pluralRuleTypes = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRuleTypes' );
-               $fallbacks = Language::getFallbacksFor( $this->mCode );
+               $fallbacks = self::getFallbacksFor( $this->mCode );
                if ( !$pluralRuleTypes ) {
                        foreach ( $fallbacks as $fallbackCode ) {
                                $pluralRuleTypes = self::$dataCache->getItem( strtolower( $fallbackCode ), 'pluralRuleTypes' );
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..d59b3d3 100644 (file)
        "thu": "Кс",
        "fri": "Йм",
        "sat": "Шб",
-       "january": "Ò\93инÑ\83аÑ\80",
-       "february": "февраль",
-       "march": "маÑ\80Ñ\82",
-       "april": "апÑ\80елÑ\8c",
-       "may_long": "май (Ò»абанай)",
-       "june": "иÑ\8eнÑ\8c",
-       "july": "иÑ\8eлÑ\8c",
-       "august": "авгÑ\83Ñ\81Ñ\82",
-       "september": "сентябрь",
-       "october": "окÑ\82Ñ\8fбÑ\80Ñ\8c",
-       "november": "ноÑ\8fбÑ\80Ñ\8c",
-       "december": "декабÑ\80Ñ\8c",
-       "january-gen": "Ò\93инÑ\83аÑ\80",
-       "february-gen": "февраль",
-       "march-gen": "маÑ\80Ñ\82",
-       "april-gen": "апÑ\80елÑ\8c",
-       "may-gen": "май",
-       "june-gen": "иÑ\8eнÑ\8c",
-       "july-gen": "иÑ\8eлÑ\8c",
-       "august-gen": "авгÑ\83Ñ\81Ñ\82",
-       "september-gen": "сентябрь",
-       "october-gen": "окÑ\82Ñ\8fбÑ\80Ñ\8c",
-       "november-gen": "ноÑ\8fбÑ\80Ñ\8c",
-       "december-gen": "декабÑ\80Ñ\8c",
-       "jan": "Ò\93ин",
-       "feb": "фев",
-       "mar": "мар",
-       "apr": "апр",
-       "may": "май",
-       "jun": "июн",
-       "jul": "июл",
-       "aug": "авг",
-       "sep": "сен",
-       "oct": "окт",
-       "nov": "ноя",
-       "dec": "дек",
+       "january": "Ò\92инÑ\83аÑ\80 (ÒºÑ\8bÑ\83Ñ\8bÒ\93ай)",
+       "february": "Февраль (Шаҡай)",
+       "march": "Ð\9cаÑ\80Ñ\82 (Ð\91Ñ\83Ñ\80анай)",
+       "april": "Ð\90пÑ\80елÑ\8c (Ð\90лаÒ\93аÑ\80ай)",
+       "may_long": "Ð\9cай (Òºабанай)",
+       "june": "Ð\98Ñ\8eнÑ\8c (ÒºÓ©Ñ\82ай)",
+       "july": "Ð\98Ñ\8eлÑ\8c (Ð\9cайай)",
+       "august": "Ð\90вгÑ\83Ñ\81Ñ\82 (УÑ\80аÒ\93ай)",
+       "september": "Сентябрь (Һарысай)",
+       "october": "Ð\9eкÑ\82Ñ\8fбÑ\80Ñ\8c (ҠаÑ\80аÑ\81ай)",
+       "november": "Ð\9dоÑ\8fбÑ\80Ñ\8c (Ò Ñ\8bÑ\80паÒ\93ай)",
+       "december": "Ð\94екабÑ\80Ñ\8c (Ð\90Ò¡Ñ\8aÑ\8eлай)",
+       "january-gen": "Ò\92инÑ\83аÑ\80 (ÒºÑ\8bÑ\83Ñ\8bÒ\93ай)",
+       "february-gen": "Февраль (Шаҡай)",
+       "march-gen": "Ð\9cаÑ\80Ñ\82 (Ð\91Ñ\83Ñ\80анай)",
+       "april-gen": "Ð\90пÑ\80елÑ\8c (Ð\90лаÒ\93аÑ\80ай)",
+       "may-gen": "Ð\9cай (Һабанай)",
+       "june-gen": "Ð\98Ñ\8eнÑ\8c (ÒºÓ©Ñ\82ай)",
+       "july-gen": "Ð\98Ñ\8eлÑ\8c (Ð\9cайай)",
+       "august-gen": "Ð\90вгÑ\83Ñ\81Ñ\82 (УÑ\80аÒ\93ай)",
+       "september-gen": "Сентябрь (Һарысай)",
+       "october-gen": "Ð\9eкÑ\82Ñ\8fбÑ\80Ñ\8c (ҠаÑ\80аÑ\81ай)",
+       "november-gen": "Ð\9dоÑ\8fбÑ\80Ñ\8c (Ò Ñ\8bÑ\80паÒ\93ай)",
+       "december-gen": "Ð\94екабÑ\80Ñ\8c (Ð\90Ò¡Ñ\8aÑ\8eлай)",
+       "jan": "Ò\92ин",
+       "feb": "Фев",
+       "mar": "Ð\9cар",
+       "apr": "Ð\90пр",
+       "may": "Ð\9cай",
+       "jun": "Ð\98юн",
+       "jul": "Ð\98юл",
+       "aug": "Ð\90вг",
+       "sep": "Сен",
+       "oct": "Ð\9eкт",
+       "nov": "Ð\9dоя",
+       "dec": "Ð\94ек",
        "january-date": "Ғинуар $1",
        "february-date": "Февраль $1",
        "march-date": "Март $1",
        "september-date": "Сентябрь $1",
        "october-date": "Октябрь $1",
        "november-date": "Ноябрь $1",
-       "december-date": "СенÑ\82Ñ\8fбрь $1",
+       "december-date": "Ð\94екабрь $1",
        "period-am": "ТК",
        "period-pm": "ТС",
        "pagecategories": "{{PLURAL:$1|1=Категория|Категориялар}}",
        "category-empty": "\"Был категория әлегә буш.\"",
        "hidden-categories": "{{PLURAL:$1|Йәшерен категория|Йәшерен категориялар}}",
        "hidden-category-category": "Йәшерен категориялар",
-       "category-subcat-count": "{{PLURAL:$2|Был категорияла тик киләһе эске категория ғына бар.|Барлығы $2 категориянан, был категорияла киләһе  {{PLURAL:$1|эске категория|$1 эске категория}} күрһәтелә.}}",
+       "category-subcat-count": "{{PLURAL:$2|Был категорияла тик киләһе эске категория ғына бар.|Барлығы $2 категориянан, был категорияла киләһе {{PLURAL:$1|эске категория|$1 эске категория}} күрһәтелә.}}",
        "category-subcat-count-limited": "Был категорияға киләһе {{PLURAL:$1|эске категория|$1 эске категория}} ингән.",
        "category-article-count": "{{PLURAL:$2|1=Был категорияла бер генә бит бар.|Категориялағы $2 биттең $1 бите күрһәтелгән.}}",
        "category-article-count-limited": "Был категорияла {{PLURAL:$1|$1 бит}} бар.",
        "category-file-count": "{{PLURAL:$2|Был категорияла бер генә файл бар.|Категориялағы $2 файлдың {{PLURAL:$1|$1 файлы күрһәтелгән}}.}}",
        "category-file-count-limited": "Был категорияла {{PLURAL:$1|$1 файл}} бар.",
-       "listingcontinuesabbrev": "(дауамы)",
+       "listingcontinuesabbrev": "дауамы",
        "index-category": "Индексланған биттәр",
        "noindex-category": "Индексланмаған биттәр",
        "broken-file-category": "Файлға һылтанмалары эшләмәгән биттәр",
        "newwindow": "(яңы биттә)",
        "cancel": "Кире алырға",
        "moredotdotdot": "Дауамы...",
-       "morenotlisted": "Был исемлек тулы түгел",
+       "morenotlisted": "Был исемлек тулы түгел.",
        "mypage": "Бит",
        "mytalk": "Әңгәмә",
        "anontalk": "Әңгәмә",
        "navigation": "Төп йүнәлештәр",
        "and": "&#32;һәм",
-       "faq": "ЙБҺ",
+       "faq": "ЙБҺ (ЧаВо)",
        "actions": "Ғәмәлдәр",
        "namespaces": "Исем арауыҡтары",
        "variants": "Варианттар",
        "tagline": "{{SITENAME}} проектынан",
        "help": "Белешмә",
        "search": "Эҙләү",
-       "search-ignored-headings": " #<!-- был юлды нисек бар шулай ҡалдырығыҙ --> <pre>\n# Эҙләүҙәр инҡар иткән атамалар.\n# Атамаһы булған бит индексланғас та, үҙгәртмәләр үҙ көсөнә инәсәк.\n# Буш төҙәтеү менән һеҙ битте яңынан индекслата алаһығыҙ\n# Синтаксис шулай күренә:\n#   * Ошо символға «#» башланған юлдың аҙағына тиклем комментарий була\n#   * Һәр буш булмаған юл - инҡар ителгәндең атамаһы, быға регистр ҙа инә\nИҫкәрмәләр\nҺылтанмалар\nҠарағыҙ шулай уҡ\n#</pre> <!-- был юлды шул көйө ҡалдырығыҙ -->",
+       "search-ignored-headings": " #<!-- был юлды нисек бар, шулай ҡалдырығыҙ --> <pre>\n# Эҙләүҙәр инҡар иткән атамалар.\n# Атамаһы булған бит индексланғас та, үҙгәртмәләр үҙ көсөнә инәсәк.\n# Буш төҙәтеү менән һеҙ битте яңынан индекслата алаһығыҙ\n# Синтаксис шулай күренә:\n#   * Ошо символға «#» башланған юлдың аҙағына тиклем комментарий була\n#   * Һәр буш булмаған юл - инҡар ителгәндең атамаһы, быға регистр ҙа инә\nИҫкәрмәләр\nҺылтанмалар\nҠарағыҙ шулай уҡ\n#</pre> <!-- был юлды шул көйө ҡалдырығыҙ -->",
        "searchbutton": "Эҙләү",
        "go": "Күсеү",
        "searcharticle": "Күсеү",
        "updatedmarker": "һуңғы инеүемдән һуң яңыртылған",
        "printableversion": "Баҫтырыу өлгөһө",
        "permalink": "Даими һылтанма",
-       "print": "Баҫыу",
+       "print": "Ð\91аҫÑ\82Ñ\8bÑ\80Ñ\8bÑ\83",
        "view": "Ҡарау",
        "view-foreign": "$1 сайтында ҡарау",
        "edit": "Үҙгәртеү",
        "edit-local": "Локаль тасуирламаны үҙгәртергә",
-       "create": "Төҙөргә",
+       "create": "Төҙөү",
        "create-local": "Локаль тасуирлама өҫтәргә",
-       "delete": "Юҡ  итергә",
+       "delete": "Юйырға",
        "undelete_short": "$1 {{PLURAL:$1|үҙгәртеүҙе}} тергеҙергә",
        "viewdeleted_short": "{{PLURAL:$1|1=1 юйылған үҙгәртеүҙе|$1 юйылған үҙгәртеүҙе}} ҡарау",
        "protect": "Һаҡларға",
        "talkpagelinktext": "әңг.",
        "specialpage": "Ярҙамсы бит",
        "personaltools": "Шәхси ҡоралдар",
-       "talk": "Әңгәмә",
+       "talk": "Фекер алышыу",
        "views": "Ҡарауҙар",
        "toolbox": "Ҡоралдар",
        "tool-link-userrights": "{{GENDER:$1|Ҡатнашыусы}} төркөмдәрен үҙгәртергә",
-       "tool-link-userrights-readonly": "{{GENDER:$1|Ҡатнашыусы|Ҡатнашыулар}} төркөмдәрен ҡарарға",
+       "tool-link-userrights-readonly": "{{GENDER:$1|Ҡатнашыусы}} төркөмдәрен ҡарарға",
        "tool-link-emailuser": "{{GENDER:$1|Ҡатнашыусыға}} хат яҙырға",
        "imagepage": "Файл битен ҡарарға",
        "mediawikipage": "Хәбәрҙәр битен ҡарарға",
        "jumpto": "Унда күсергә:",
        "jumptonavigation": "төп йүнәлештәр",
        "jumptosearch": "эҙләү",
-       "view-pool-error": "Ò\92Ó\99Ñ\84Ò¯ Ð¸Ñ\82егеÒ\99, Ñ\85Ó\99Ò\99еÑ\80ге Ð²Ð°Ò¡Ñ\8bÑ\82Ñ\82а Ñ\81еÑ\80веÑ\80Ò\99аÑ\80 Ð°Ñ\80Ñ\82Ñ\8bÒ¡ Ñ\82ейÓ\99лгÓ\99н.\nБыл битте ҡарарға теләүселәр бик күп.\nБыл биткә һуңғарак кереп ҡарағыҙ.\n\n$1",
-       "generic-pool-error": "Ò\92Ó\99Ñ\84Ò¯ Ð¸Ñ\82егеÒ\99, Ñ\85Ó\99Ò\99еÑ\80ге Ð²Ð°Ò¡Ñ\8bÑ\82Ñ\82а Ñ\81еÑ\80веÑ\80Ò\99аÑ\80 ÐºÓ©Ñ\81Ó©Ñ\80гÓ\99неÑ\88ле Ñ\8dÑ\88лÓ\99й.\nÐ\91Ñ\8bл Ð±Ð¾Ð»Ð´Ñ\8b Ò¡Ð°Ñ\80аÑ\80Ò\93а Ñ\82елÓ\99Ò¯Ñ\81елÓ\99Ñ\80 Ð±Ð¸Ðº ÐºÒ¯Ð¿.\nÐ\97инһаÑ\80, Ð±ер ни тиклем көтөгөҙ һәм һуңыраҡ тағы мөрәжәғәт итеп ҡарағыҙ.",
+       "view-pool-error": "Ò\92Ó\99Ñ\84Ò¯ Ð¸Ñ\82егеÒ\99, Ñ\85Ó\99Ò\99еÑ\80ге Ð²Ð°Ò¡Ñ\8bÑ\82Ñ\82а Ñ\81еÑ\80веÑ\80Ò\99аÑ\80 ÐºÓ©Ñ\81Ó©Ñ\80гÓ\99неÑ\88ле Ñ\8dÑ\88лÓ\99й.\nБыл битте ҡарарға теләүселәр бик күп.\nБыл биткә һуңғарак кереп ҡарағыҙ.\n\n$1",
+       "generic-pool-error": "Ò\92Ó\99Ñ\84Ò¯ Ð¸Ñ\82егеÒ\99, Ñ\85Ó\99Ò\99еÑ\80ге Ð²Ð°Ò¡Ñ\8bÑ\82Ñ\82а Ñ\81еÑ\80веÑ\80Ò\99аÑ\80 ÐºÓ©Ñ\81Ó©Ñ\80гÓ\99неÑ\88ле Ñ\8dÑ\88лÓ\99й.\nÐ\91Ñ\8bл Ð±Ð¾Ð»Ð´Ñ\8b Ò¡Ð°Ñ\80аÑ\80Ò\93а Ñ\82елÓ\99Ò¯Ñ\81елÓ\99Ñ\80 Ð±Ð¸Ðº ÐºÒ¯Ð¿.\nÐ\91ер ни тиклем көтөгөҙ һәм һуңыраҡ тағы мөрәжәғәт итеп ҡарағыҙ.",
        "pool-timeout": "Блоклауҙы көтөү ваҡыты үтте",
        "pool-queuefull": "Һорауҙар сираты тулы",
        "pool-errorunknown": "Билдәһеҙ хата",
        "disclaimerpage": "Project:Яуаплылыҡтан баш тартыу",
        "edithelp": "Төҙәтеү белешмәһе",
        "helppage-top-gethelp": "Ярҙам",
-       "mainpage": "Ð\91аÑ\88 Ð±ит",
+       "mainpage": "Ð\91аÑ\88 Ð\91ит",
        "mainpage-description": "Баш бит",
        "policy-url": "Project:Ҡағиҙәләр",
        "portal": "Берләшмә",
        "badaccess": "Кереү хатаһы",
        "badaccess-group0": "Һоратылған ғәмәлде үтәй алмайһығыҙ.",
        "badaccess-groups": "Һоратылған ғәмәлде киләһе {{PLURAL:$2|1=төркөм|төркөмдәр}} ҡулланыусылары ғына башҡара ала: $1.",
-       "versionrequired": "MediaWiki-ның $1 версияһы кәрәкле",
+       "versionrequired": "MediaWiki-ның $1 версияһы кәрәк",
        "versionrequiredtext": "Был бит менән эшләү өсөн MediaWiki-ның $1 версияһы кәрәк. [[Special:Version|Ҡулланылған версия тураһында мәғлүмәт битен]] ҡара.",
        "ok": "Тамам",
        "pagetitle": "{{SITENAME}} проектынан",
        "retrievedfrom": "Сығанағы — «$1»",
-       "youhavenewmessages": "Яңы $1 бар ($2).",
+       "youhavenewmessages": "{{PLURAL:$3|Һеҙгә}} $1 ($2) бар.",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|Һеҙгә}} {{PLURAL:$3|$3 ҡатнашыусыһынан}} $1 килде ($2).",
        "youhavenewmessagesmanyusers": "Һеҙгә күп ҡатнашыусынан $1 бар ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|1=яңы хәбәр|яңы хәбәр}}",
        "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": "викитекст",
        "tooltip-pt-watchlist": "Һеҙ күҙәткән биттәр исемлеге",
        "tooltip-pt-mycontris": "{{GENDER:|Һеҙҙең}} төҙәтеүҙәр исемлеге",
        "tooltip-pt-anoncontribs": "Был IP-адрестан яһалған төҙәтеүҙәр",
-       "tooltip-pt-login": "Бында теркәлеү үтергә була, әммә был эш мәжбүри түгел.",
+       "tooltip-pt-login": "Бында теркәлеү үтергә була, әммә был эш мәжбүри түгел",
        "tooltip-pt-logout": "Сығырға",
-       "tooltip-pt-createaccount": "Ð\9cоÑ\82лаҡ Ð±Ñ\83лмаһа Ð»Ð°, ÒºÐµÒ\99гÓ\99 Ð¸Ò«Ó\99п Ñ\8fÒ\99маһÑ\8b Ñ\82Ó©Ò\99Ó©Ñ\80гө Ò»Ó\99м Ñ\81иÑ\81Ñ\82емала Ñ\82анÑ\8bлÑ\8bÑ\80Ò\93а Ñ\82Ó\99ҡдим Ð¸Ñ\82Ó\99беÒ\99.",
+       "tooltip-pt-createaccount": "Ð\9cоÑ\82лаҡ Ð±Ñ\83лмаһа Ð»Ð°, ÒºÐµÒ\99гÓ\99 Ð¸Ò«Ó\99п Ñ\8fÒ\99маһÑ\8b Ñ\82Ó©Ò\99Ó©Ñ\80гÓ\99 Ò»Ó\99м Ñ\81иÑ\81Ñ\82емала Ñ\82анÑ\8bлÑ\8bÑ\80Ò\93а Ñ\82Ó\99ҡдим Ð¸Ñ\82Ó\99беÒ\99",
        "tooltip-ca-talk": "Биттең эстәлеге тураһында фекерләшеү",
        "tooltip-ca-edit": "Был битте үҙгәртергә",
        "tooltip-ca-addsection": "Яңы бүлек эшләргә",
        "tooltip-watchlistedit-raw-submit": "Күҙәтеү исемлеген яңыртырға",
        "tooltip-recreate": "Битте юйылған булыуына ҡарамаҫтан тергеҙергә",
        "tooltip-upload": "Күсерә башларға",
-       "tooltip-rollback": "Бер баҫыу менән аҙаҡҡы мөхәррирләүсенең үҙгәртеүҙәрен кире ала.",
+       "tooltip-rollback": "Бер баҫыу менән аҙаҡҡы мөхәррирләүсенең үҙгәртеүҙәрен кире ала",
        "tooltip-undo": "\"Кире ал\" төҙәтеүҙе кире ала һәм төҙәтеү формаһын \"алдан байҡау\"ҙа күрһәтә. Һәм кире алыуҙың сәбәбен белдерергә була.",
        "tooltip-preferences-save": "Көйләүҙәрҙе һаҡларға",
        "tooltip-summary": "Ҡыҫҡаса тасуирлама керетегеҙ",
index 989a466..7587f79 100644 (file)
        "rcfilters-activefilters": "Актыўныя фільтры",
        "rcfilters-advancedfilters": "Пашыраныя фільтры",
        "rcfilters-limit-title": "Паказаць зьменаў",
+       "rcfilters-limit-shownum": "Паказаць апошнія $1 зьменаў",
+       "rcfilters-days-title": "Апошнія дні",
+       "rcfilters-hours-title": "Апошнія гадзіны",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|дзень|дні|дзён}}",
        "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..238c450 100644 (file)
@@ -31,7 +31,8 @@
                        "Liashko",
                        "Mechanizatar",
                        "Artsiom91",
-                       "Andrus"
+                       "Andrus",
+                       "Da voli"
                ]
        },
        "tog-underline": "Падкрэсліваць спасылкі:",
        "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": "Чалавек (не бот)",
        "rcfilters-filter-unpatrolled-label": "Недагледжаны",
        "rcfilters-filtergroup-lastRevision": "Цяперашняя версія",
        "rcfilters-filter-lastrevision-label": "Актуальная версія",
+       "rcfilters-exclude-button-on": "За выключэннем выбранага",
        "rcnotefrom": "Ніжэй {{PLURAL:$5|паказана змяненне|паказаны змены}} з <strong>$3, $4</strong> (не больш за <strong>$1</strong>).",
        "rclistfrom": "Паказаць змены з $3 $2",
        "rcshowhideminor": "$1 дробныя праўкі",
index 03a2b69..ec68b16 100644 (file)
        "recentchanges-submit": "Prikaži",
        "rcfilters-activefilters": "Aktivni filteri",
        "rcfilters-advancedfilters": "Napredni filteri",
-       "rcfilters-quickfilters": "Sačuvane postavke filtera",
+       "rcfilters-quickfilters": "Sačuvani filteri",
        "rcfilters-quickfilters-placeholder-title": "Zasad nema sačuvanih linkova",
        "rcfilters-quickfilters-placeholder-description": "Da sačuvate postavke filtera da biste ih kasnije ponovo upotrijebili, kliknite na ikonu markera pod \"Aktivni filterima\" ispod.",
        "rcfilters-savedqueries-defaultlabel": "Sačuvani filteri",
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..6a78683 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é.",
        "headline_sample": "Tekst nadgłówka",
        "headline_tip": "Nadgłówk 2 lédżi",
        "nowiki_sample": "Wstawi tuwò niesfòrmatowóny tekst",
-       "nowiki_tip": "Ignorëjë wiki-fòrmatowanié",
+       "nowiki_tip": "Jignorëjë wiki-fòrmatowanié",
        "image_sample": "Przëmiôr.jpg",
        "image_tip": "Òbsôdzony lopk (n.p. òbrôzk)",
        "media_sample": "Przëmiôr.ogg",
        "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ù:",
        "template-protected": "(zazychrowónô)",
        "template-semiprotected": "(dzélowò zazychrowóné)",
        "hiddencategories": "Na starna przënôleżi do w {{PLURAL:$1|1 zatacony kategòrëji|$1 zataconych kategòrëjów}}:",
-       "permissionserrors": "Fela przistspù",
+       "permissionserrors": "Fela przistãpù",
        "permissionserrorstext-withaction": "Ni môsz przëstãpù do $2, z {{PLURAL:$1|nôslédny przëczënë|nôslédnych przëczënów}}:",
        "recreate-moveddeleted-warn": "<strong>Bôczënk! Chcesz usadzëc starnã, chtërna wczasni òsta rëmniãtô.</strong>\n\nÙgwësni sã, czë pònowné ùsôdzenié ti starnë je kònieczné. \nNiżi je widzec register rëmaniów i zmian pòzwë ti starnë:",
        "moveddeleted-notice": "Na starna òsta rëmniãtô.\nSpisënk rëmaniô ë zjinaków miona ti starnë je niżi.",
        "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ô",
+       "sp-contributions-talk": "diskùsëjô",
        "sp-contributions-blocked-notice-anon": "Ta adresa IP je w tim sztërkù zablokòwónô.\nSlédny wpisënk z registru blokòwaniów je widzec niżi:",
        "sp-contributions-search": "Szëkba za edicëjama",
        "sp-contributions-username": "Adresa IP abò miono brëkòwnika:",
        "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ã",
        "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' nie mòże bëc brëkòwónô, temù że '''$wgUseDatabaseMessages''' je wëłączony.",
        "thumbnail-more": "Zwikszi",
        "import": "Impòrtëjë starnë",
-       "importlogpage": "Log impòrtu",
+       "importlogpage": "Log jimpòrtu",
        "tooltip-pt-userpage": "{{GENDER:|Twòja}} starna brëkòwnika",
        "tooltip-pt-mytalk": "{{GENDER:|Mòjô}} starna diskùsëji",
        "tooltip-pt-anontalk": "Diskùsjô brëkòwnika dlô ti adresë IP",
        "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",
        "pageinfo-robot-policy": "Jindeksowanié przez robòtë",
        "pageinfo-robot-index": "Zezwòloné",
        "pageinfo-robot-noindex": "Niedozwóloné",
-       "pageinfo-watchers": "Wielëna ùżérających",
+       "pageinfo-watchers": "Wielëna ùzérających",
        "pageinfo-few-watchers": "Mni jak $1 {{PLURAL:$1|ùzyrający|ùzyrających}}",
        "pageinfo-redirects-name": "Wielëna przeczérowaniów do ti starnë",
        "pageinfo-subpages-name": "Wielëna pòdstarnów ti starnë",
        "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",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskùsëjô]])",
        "version": "Wersëjô",
        "redirect": "Przeczérëjë z jidentyfikatora lopka, brëkòwnika, starnë, wersëji abò wpisënka loga",
-       "redirect-summary": "Na szpecjalnô starna przczerowùje do: lopka(ò pòdónym mionie), do sstarny (ò pòdónym numrze wersëji abò jidentyfikatorze starë), do starnë brëkòwnika (ò pòdónym numerowim jidentyfikatorze) abò do rejestru (ò pòdónym numrze akcëji). Òrt ùżëcô: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] abò [[{{#Special:Redirect}}/logid/186]].",
+       "redirect-summary": "Na specjalnô starna przczerowùje do: lopka(ò pòdónym mionie), do starny (ò pòdónym numrze wersëji abò jidentyfikatorze starë), do starnë brëkòwnika (ò pòdónym numerowim jidentyfikatorze) abò do rejestru (ò pòdónym numrze akcëji). Òrt ùżëcô: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] abò [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Biéj",
        "redirect-lookup": "Szëkôj:",
        "redirect-value": "Wôrtnota:",
index 68727dd..5ec41ab 100644 (file)
@@ -62,7 +62,8 @@
                        "Jhertel",
                        "IBDJ",
                        "SimmeD",
-                       "BoBrandt"
+                       "BoBrandt",
+                       "R12ntech"
                ]
        },
        "tog-underline": "Understreg henvisninger:",
        "rcfilters-highlightmenu-help": "Vælg en farve for at fremhæve denne egenskab",
        "rcfilters-filterlist-noresults": "Ingen filtre fundet",
        "rcfilters-noresults-conflict": "Ingen resultater fundet fordi søgekriterierne er i konflikt",
-       "rcfilters-filtergroup-registration": "Brugerregistrering",
-       "rcfilters-filter-registered-label": "Registrerede",
-       "rcfilters-filter-registered-description": "Indloggede brugere",
-       "rcfilters-filter-unregistered-label": "Uregistrerede",
-       "rcfilters-filter-unregistered-description": "Redaktører, der ikke er logget ind.",
        "rcfilters-filtergroup-authorship": "Bidragets forfatter",
        "rcfilters-filter-editsbyself-label": "Ændringer af dig",
        "rcfilters-filter-editsbyself-description": "Dine egne bidrag.",
        "rcfilters-filter-editsbyother-label": "Ændringer af andre",
        "rcfilters-filter-editsbyother-description": "Alle ændringer undtagen din egen.",
        "rcfilters-filtergroup-userExpLevel": "Erfaringsniveau (kun for registrerede brugere)",
-       "rcfilters-filtergroup-user-experience-level-conflicts-unregistered": "Erfaringsfiltre finder kun registrerede brugere, så dette filter er i konflikt med filtret \"Uregistrerede\".",
+       "rcfilters-filter-user-experience-level-registered-label": "Registrerede",
+       "rcfilters-filter-user-experience-level-registered-description": "Indloggede brugere",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Uregistrerede",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Redaktører, der ikke er logget ind.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Nybegyndere",
        "rcfilters-filter-user-experience-level-newcomer-description": "Færre end 10 redigeringer og 4 dages aktivitet",
        "rcfilters-filter-user-experience-level-learner-label": "Let øvede",
        "version-libraries-license": "Licens",
        "version-libraries-description": "Beskrivelse",
        "version-libraries-authors": "Forfattere",
-       "redirect": "Omdirigering pga. fil, bruger-, side- eller udgave-ID",
-       "redirect-summary": "Denne specialside omdirigerer til en fil (hvis filnavnet er angivet), en side (hvis udgave ID'et eller side ID'et er angivet) eller en brugerside (hvis et numerisk brugernummer er angivet). Eksempler på brug: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]],[[{{#Special:Redirect}}/revision/328429]] eller [[{{#Special:Redirect}}/user/101]].",
+       "redirect": "Omdiriger via filnavn, bruge-, side-, revision- eller log-ID.",
+       "redirect-summary": "Denne spesialsiden omdirigerer til en fil (hvis et filnavn angis), en lave (om revisions- eller side-ID angis), en brugerside (om bruge-ID angis), eller en loggoppføring (om log-ID angis). Bruk: [[{{#Special:Redirect}}/file/Eksempel.jpg]], [[{{#Special:Redirect}}/page/#64308]], [[{{#Special:Redirect}}/revision/#328429]], [[{{#Special:Redirect}}/user/#101]] eller [[{{#Special:Redirect}}/logid/#186]].",
        "redirect-submit": "Vis",
        "redirect-lookup": "Slå op:",
        "redirect-value": "Værdi:",
        "htmlform-title-not-exists": "$1 findes ikke.",
        "logentry-delete-delete": "$1 {{GENDER:$2|slettede}} siden $3",
        "logentry-delete-delete_redir": "$1 {{GENDER:$2|slettede}} omdirigering $3 ved overskrivning",
-       "logentry-delete-restore": "$1 {{GENDER:$2|gendannede}} siden $3",
+       "logentry-delete-restore": "$1 {{GENDER:$2|gendannede}} siden $3 ($4)",
        "logentry-delete-event": "$1 {{GENDER:$2|ændrede}} synligheden af {{PLURAL:$5|en loghændelse|$5 loghændelser}} for siden $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|ændrede}} synligheden af {{PLURAL:$5|en version|$5 versioner}} af siden $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|ændrede}} synligheden af loghændelser for siden $3",
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..eed494d 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",
        "watchlist": "Abërtït",
        "mywatchlist": "Abërtït",
        "watch": "Ɣoi",
+       "watchthispage": "Watch this page",
        "watchlist-hide": "Thaan",
        "watchlist-submit": "Nyooth",
        "historyaction-submit": "Nyooth",
index fd7921f..85dd493 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",
        "specialpages": "Special pages",
        "specialpages-summary": "",
        "specialpages-note-top": "Legend",
-       "specialpages-note": "* Normal special pages.\n* <span class=\"mw-specialpagerestricted\">Restricted special pages.</span>",
+       "specialpages-note-restricted": "* Normal special pages.\n* <span class=\"mw-specialpagerestricted\">Restricted special pages.</span>",
+       "specialpages-note-cached": "-",
        "specialpages-group-maintenance": "Maintenance reports",
        "specialpages-group-other": "Other special pages",
        "specialpages-group-login": "Login / create account",
index 9dbfd7f..c361acd 100644 (file)
        "rcfilters-legend-heading": "<strong>Lista de abreviaturas:</strong>",
        "rcfilters-activefilters": "Filtros activos",
        "rcfilters-advancedfilters": "Filtros avanzados",
+       "rcfilters-limit-title": "Cambios para mostrar",
+       "rcfilters-limit-shownum": "Mostrar los últimos $1 cambios",
+       "rcfilters-days-title": "Días recientes",
+       "rcfilters-hours-title": "Horas recientes",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|día|días}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|hora|horas}}",
        "rcfilters-quickfilters": "Filtros guardados",
        "rcfilters-quickfilters-placeholder-title": "Ningún enlace guardado aún",
        "rcfilters-quickfilters-placeholder-description": "Para guardar tus ajustes de filtro y reutilizarlos más tarde, pulsa en el icono del marcador en el área de Filtro activo que se encuentra a continuación.",
        "rcfilters-invalid-filter": "Filtro no válido",
        "rcfilters-empty-filter": "No hay filtros activos. Se muestran todas las contribuciones.",
        "rcfilters-filterlist-title": "Filtros",
-       "rcfilters-filterlist-whatsthis": "¿Qué es esto?",
+       "rcfilters-filterlist-whatsthis": "¿Cómo funcionan?",
        "rcfilters-filterlist-feedbacklink": "Comparte tus comentarios sobre los filtros (beta) nuevos",
        "rcfilters-highlightbutton-title": "Resaltar los resultados",
        "rcfilters-highlightmenu-title": "Selecciona un color",
        "rcfilters-hideminor-conflicts-typeofchange-global": "El filtro \"Ediciones menores\" está en conflicto con uno o más Tipos de filtros de Cambio, ya que ciertos tipos de cambio no pueden ser designados como \"menores\". Los filtros en conflicto están marcados en el área Filtros activos, anterior.",
        "rcfilters-hideminor-conflicts-typeofchange": "Ciertos tipos de cambio no pueden ser designados como \"menores\", por lo que este filtro entra en conflicto con los siguientes  Tipos de filtros de Cambio: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "Este filtro «Tipo de cambio» entra en conflicto con el filtro «Ediciones menores». Hay ciertos tipos de cambios que no pueden denominarse «menores».",
-       "rcfilters-filtergroup-lastRevision": "Revisión actual",
-       "rcfilters-filter-lastrevision-label": "Revisión actual",
-       "rcfilters-filter-lastrevision-description": "El cambio más reciente a una página.",
-       "rcfilters-filter-previousrevision-label": "Revisiones anteriores",
-       "rcfilters-filter-previousrevision-description": "Todos los cambios que no son los más recientes cambian a una página.",
+       "rcfilters-filtergroup-lastRevision": "Últimas revisiones",
+       "rcfilters-filter-lastrevision-label": "Última revisión",
+       "rcfilters-filter-lastrevision-description": "Solo el cambio más reciente a una página.",
+       "rcfilters-filter-previousrevision-label": "No la última revisión",
+       "rcfilters-filter-previousrevision-description": "Todos los cambios que no son la \"última revisión\".",
        "rcfilters-filter-excluded": "Excluido",
        "rcfilters-tag-prefix-namespace-inverted": "<strong>Estado:</strong> $1",
+       "rcfilters-exclude-button-off": "Excluir los seleccionados",
+       "rcfilters-exclude-button-on": "Excluyendo los seleccionados",
        "rcfilters-view-tags": "Ediciones etiquetadas",
        "rcfilters-view-namespaces-tooltip": "Filtrar resultados por espacio de nombres",
        "rcfilters-view-tags-tooltip": "filtrado de resultados usando etiquetas de edición",
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..6f51de3 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 version",
+       "rcfilters-filter-previousrevision-description": "Toutes les modifications apportées à une page et qui ne concernent pas la « dernière version ».",
        "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 bafdb74..75b5744 100644 (file)
        "newarticletext": "Yi'o lodudu'a wumbuta ode halaman diya'a. \nWonu mohutu halaman botiye, ketik tuwango halaman to kotak to tibawa botiye (bilohi [$1 halaman wubodu] ode habari wumbutiyo). \nWonu Yi'o ja sangaja tilumuwota ode halaman botiye, kutiya tombol <strong>mohuwalingo</strong>.",
        "noarticletext": "Sa'ati botiye diya'a teks to halaman botiye.\nYi'o mowali [[Special:Search/{{PAGENAME}}|mololohu  judul halaman botiye]] to halaman-halaman uweewo, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mololohu log a'ayita], meyalo [{{fullurl:{{FULLPAGENAME}}|action=edit}} mohutu halaman botiye]</span>.",
        "noarticletext-nopermission": "!Sa'ati botiye diya'a teks to halaman boptiye.\nYi'o mowali [[Special:Search/{{PAGENAME}}|mololohu judul halaman botiye]] to halaman-halaman uweewo, meyalo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mololohu log a'ayita]</span>, dabo Yi'o ja o ijin mohutu halaman botiye.",
+       "userpage-userdoesnotexist-view": "Ta ohu'uwo \"$1\" diyaalu to daputari.",
        "editing": "Momoli'o $1",
        "creating": "Mohutu $1",
        "editingsection": "Momoli'o $1 (tayadu)",
        "moveddeleted-notice": "Halaman botiye ma yiluluto.\nSebagai referensi, botiya log piloluluta wawu piloheyiya halaman botiye.",
        "postedit-confirmation-saved": "Biloli'umu ma tilahu.",
        "edit-already-exists": "Ja mowali mohutu halaman bohu. Ma woluwo.",
+       "content-model-wikitext": "tuladu wiki",
        "viewpagelogs": "Bilohi log lo halaman botiye",
        "currentrev-asof": "Biloli'o pulitiyo to $1",
        "revisionasof": "Biloli'o to $1",
        "history-fieldset-title": "Lolohe u biloli'o",
        "histfirst": "mohihewo da'a",
        "histlast": "bohu da'a",
+       "history-feed-title": "Riwayati lo'u biloli'o",
+       "history-feed-description": "Riwayati bilolio to halaman wiki botiye",
+       "history-feed-item-nocomment": "$1 to $2",
        "rev-delundel": "popobilohe/wanto'a",
        "history-title": "Riwayati lo'u loboli'a lonto \"$1\"",
        "difference-title": "$1 hihede revisi",
        "lineno": "Baarisi $1:",
+       "compareselectedversions": "Popotadenga u tilulawoto",
        "editundo": "pohuwalinga",
        "diff-multi-sameuser": "({{PLURAL:$1|$1 revisi wolota}} pilohutu lo tawu ngota ja pilopobilohu)",
        "searchresults": "U yilotapu",
        "search-result-size": "$1 ({{PLURAL:$2|1 tahe|$2 tahe}})",
        "search-redirect": "(pilobale lonto $1)",
        "search-section": "(tayadu) $1",
+       "search-file-match": "(sama lo tuwango berkas)",
        "search-suggest": "Patujumu yito:$1",
        "searchall": "nga'amila",
        "search-showingresults": "{{PLURAL:$4|hASIL <strong>$1</strong> of <strong>$3</strong>|Hasil <strong>$1 - $2</strong> lonto <strong>$3</strong>}}",
        "search-nonefound": "Diya'a hasili mohumayawa lo kriteria",
        "powersearch-toggleall": "Nga'amila",
        "powersearch-togglenone": "Diya'a",
-       "powersearch-remember": "Eelayi u tilulawoto wonu mololohe pe'eentamayi",
+       "powersearch-remember": "Toloma u tilulawoto wonu mololohe pe'eenta mayi",
        "mypreferences": "Preperensi",
        "prefs-skin": "Alipo",
        "searchresultshead": "Lolohe",
        "prefs-searchoptions": "Lolohe",
        "prefs-namespaces": "Huwali lo tanggulo",
-       "default": "Kakali",
+       "default": "kakali",
        "yourrealname": "Tanggula banari",
        "yourlanguage": "Bahasa",
        "grouppage-bot": "{{ns:project}}:Bot",
        "recentchangeslinked-page": "Tanggulo halaman:",
        "recentchangeslinked-to": "Poppobilohe loboli'a to halaman wayitiyo wolo halaman hepoposadiyalo",
        "upload": "Detohe berkas",
+       "uploadlogpage": "Detohu log",
        "filedesc": "Limbu'o",
+       "license": "Lisensi",
        "license-header": "Tayadu lisensi",
        "imgfile": "berkas",
        "file-anchor-link": "Berkas",
        "nmembers": "$1 {{PLURAL:$1|tuwango}}",
        "listusers": "Daputari ta ohu'uwo",
        "newpages": "Halaman bohu",
+       "move": "Heyiya",
        "pager-newer-n": "{{PLURAL:$1|bohu da'a|$1bohu da'a}}",
        "pager-older-n": "{{PLURAL:$1|$1 mohihewo}}",
        "booksources": "Bungo buku",
        "booksources-search-legend": "Lolohe to bungo lo buku",
        "booksources-search": "Lolohe",
        "log": "Log",
+       "all-logs-page": "Nga'amila log publik",
+       "allpages": "Nga'amila halaman",
        "allarticles": "Nga'amila halaman",
        "allpagessubmit": "Ntali",
        "categories": "Kategori",
+       "usermessage-editor": "Sistem lo tahuli",
+       "watchlist": "U he'awasiyalo",
        "mywatchlist": "Daputari he'awasiyalo",
        "watch": "Dahayi",
+       "unwatch": "Batali mongawasi",
        "wlshowlast": "Popobilohe $1 jam $2 dulahe pulitiyo",
        "dellogpage": "Log loluluto",
        "rollbacklink": "wuwalinga",
        "protectlogpage": "Log mopo'aamani",
        "protectedarticle": "modaha \"[[$1]]\"",
        "protect-default": "Poluliya nga'amila ta ohu'uwo",
+       "restriction-edit": "Boli'a",
+       "restriction-move": "Heyiya",
        "namespace": "Huwali lo tanggulo",
        "invert": "Pohuwalinga tilulawoto",
        "tooltip-invert": "Centang kotak botiye u mopowanto'o halaman yiloboli'a to delomo huwali lo tanggulo tilulawoto (wawu huwali lo tanggulo a'ayita wanu dicentang)",
        "contributions": "Kontribusi {{GENDER:$1|Ta ohu'uwo}}",
        "mycontris": "Kontribusi",
        "anoncontribs": "Kontribusi",
+       "contribsub2": "Ode {{GENDER:$3|$1}} ($2)",
        "uctop": "(masatiya)",
        "month": "Lonto hulalo (wawu to'udiipo)",
        "year": "Lonto taawunu (wawu to'udiipo)",
+       "sp-contributions-newbies": "Popobilohe bo lonto ta ohu'uwo bohu",
+       "sp-contributions-blocklog": "bubuli log",
+       "sp-contributions-uploads": "u diletohu",
        "sp-contributions-logs": "log",
        "sp-contributions-talk": "lo'iya",
        "sp-contributions-search": "Lolohe kontribusi",
+       "sp-contributions-username": "Alamat IP meyalo tanggulo ta ohu'uwo",
+       "sp-contributions-toponly": "Popobiloho bo biloli'a to yitaato",
+       "sp-contributions-newonly": "Popobilohe biloli'o bo u lohutu halaman",
        "sp-contributions-submit": "Lolohe",
        "whatlinkshere": "Wumbuta",
        "whatlinkshere-title": "Halaman botiye o wumbuta ode \"$1\"",
        "whatlinkshere-hidelinks": "$1 wumbuta",
        "whatlinkshere-hideimages": "$1 berkas wumbuta",
        "whatlinkshere-filters": "U'ayahu",
+       "ipboptions": "2 jam:2 hours,1 huyi:1 day,3 huyi:3 days,1 diminggu:1 week,2 diminggu:2 weeks,1 hula:1 month,3 hula:3 months,6 hula:6 months,1 taawunu:1 year,layito:infinite",
        "blocklink": "tangguwalo",
        "contribslink": "kontrib",
+       "blocklogpage": "Bubuli log",
+       "blocklogentry": "momubulo [[$1]] wolo pulito wakutu $2 $3",
+       "proxyblocker": "Bubulo proxi",
        "movelogpage": "Log piloheyiya",
        "export": "Ekspor halaman",
        "thumbnail-more": "Po'odamanga",
        "tooltip-ca-nstab-special": "Utiye halaman istimewa, wawu ja mowali boli'olo",
        "tooltip-ca-nstab-project": "Bilohi halaman poroyek",
        "tooltip-ca-nstab-image": "Bilohi berkas lo halaman",
+       "tooltip-ca-nstab-mediawiki": "Bilohi tahuli lo sistem",
        "tooltip-ca-nstab-template": "Bilohi template",
        "tooltip-ca-nstab-category": "Bilohi kategori halaman",
        "tooltip-save": "Tahuwa u biloli'umu",
        "tooltip-preview": "Bilohipo u biloli'umu. Popopasiya utiye to'u diipo molahu.",
        "tooltip-diff": "Bilohi u loboli'o pilohutumu",
        "tooltip-compareselectedversions": "Bilohi hihede lohalaman duluwo u tilulawoto.",
+       "tooltip-watch": "Poduhengama'o halaman botiye to daputari he'awasiyalo",
        "tooltip-rollback": "\"Wuwalingo\" lopobatali u pilo'opiyohu to halaman botiye ode kontributor pulitiyo pe'enta lo klik.",
        "tooltip-undo": "\"wuwalingo\" lopobatali u biloli'a botiye wawu lomu'o kotak momoli'o wolo mode pratayang. Alasani mowali duhengalo to kotak limbu-limbu'o.",
        "tooltip-summary": "Tuwota tulade limbu-limbu'o",
        "simpleantispam-label": "Momarakisa anti-spam.\n<strong>kekeya</strong> tuwangalo!",
+       "pageinfo-title": "Informasi untuk \"$1\"",
+       "pageinfo-header-basic": "Bungo lo habari",
+       "pageinfo-header-restrictions": "Dudaha halaman",
+       "pageinfo-display-title": "Judul bibilohu",
+       "pageinfo-length": "Haya'o halaman (to delomo bita)",
+       "pageinfo-article-id": "ID Halaman",
+       "pageinfo-language": "Bahasa tuwango halaman",
+       "pageinfo-robot-policy": "Pengindeksan monto robot",
+       "pageinfo-watchers": "Jumula lo ta hemongawasi halaman",
+       "pageinfo-redirects-name": "Jumula u pilobale ode halaman botiya",
+       "pageinfo-firsttime": "Tanggal pilohutuwa halaman",
+       "pageinfo-recent-edits": "Jumula boheli biloli'a mola (to delomo $1 pulitiyo)",
        "pageinfo-toolboxlink": "Halaman habari",
+       "pageinfo-contentpage-yes": "Jo",
        "previousdiff": "← Biloli'o to'udiipo",
        "nextdiff": "Biloli'o lapatiyoma'o →",
        "file-info-size": "$1 x $2 piksel, tu'udu berkas:$3, MIME tipe: $4",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag}}]]: $2)",
        "tags-active-yes": "Jo",
        "logentry-delete-delete": "$1 {{GENDER:$2|moluluto}}halaman $3",
+       "revdelete-content-hid": "tuwango yilanto'o",
        "logentry-move-move": "$1 {{GENDER:$2|moheyi}} halaman $3 ode $4",
+       "logentry-move-move-noredirect": "$1 {{GENDER:$2|loheyi}} halaman $3 ode $4 ja lohutu pengalihan",
+       "logentry-move-move_redir": "$1 {{GENDER:$2|loheyi}} halaman $3 ode $4 lodeehu pengalihan",
        "logentry-newusers-create": "Ta ohu'uwo akun $1 {{GENDER:$2|mohutu}}",
+       "logentry-newusers-autocreate": "Akun $1 {{GENDER:$2|pilohutu}} otomatis",
        "logentry-upload-upload": "$1 {{GENDER:$2|mengunggah}} $3",
-       "searchsuggest-search": "Lolohe {{SITENAME}}"
+       "searchsuggest-search": "Lolohe {{SITENAME}}",
+       "duration-days": "$1 {{PLURAL:$1|huyi}}",
+       "randomrootpage": "Halaman totonulalo"
 }
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 b48188e..a0a6768 100644 (file)
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|नए पन्नों की सूची]] को भी देखें)",
        "recentchanges-submit": "दिखाएँ",
        "rcfilters-activefilters": "सक्रिय फिल्टर",
+       "rcfilters-limit-shownum": "पिछले $1 बदलाव दिखायें",
+       "rcfilters-days-title": "कुछ दिनों के",
+       "rcfilters-hours-title": "कुछ घंटों के",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|दिन}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|घंटा|घंटे}}",
        "rcfilters-quickfilters": "सुरक्षित फ़िल्टर",
        "rcfilters-quickfilters-placeholder-title": "कोई कड़ी अभी तक सहेजा नहीं गया",
        "rcfilters-quickfilters-placeholder-description": "अपने फ़िल्टर सेटिंग को सहेजने और बाद में उपयोग करने के लिए नीचे दिये बूकमार्क छवि पर क्लिक करें।",
        "rcfilters-savedqueries-unsetdefault": "मूल के रूप से हटाएँ",
        "rcfilters-savedqueries-remove": "निकालें",
        "rcfilters-savedqueries-new-name-label": "नाम",
-       "rcfilters-savedqueries-apply-label": "सेटिंग संजोयें",
+       "rcfilters-savedqueries-new-name-placeholder": "फ़िल्टर का उद्देश्य समझाएँ",
+       "rcfilters-savedqueries-apply-label": "फ़िल्टर बनायें",
        "rcfilters-savedqueries-cancel-label": "रद्द करें",
        "rcfilters-savedqueries-add-new-title": "वर्तमान फ़िल्टर सेटिंग को सहेजें",
        "rcfilters-restore-default-filters": "मूलभूत फिल्टर पुनर्स्थापित करे",
        "rcfilters-invalid-filter": "अमान्य फ़िल्टर",
        "rcfilters-empty-filter": "कोई सक्रिय फिल्टर नहीं। सभी योगदान दिखाए गए है।",
        "rcfilters-filterlist-title": "फिल्टर",
-       "rcfilters-filterlist-whatsthis": "यह à¤\95à¥\8dया है?",
+       "rcfilters-filterlist-whatsthis": "यह à¤\95à¥\88सà¥\87 à¤\95ारà¥\8dय à¤\95रता है?",
        "rcfilters-filterlist-feedbacklink": "नए (बीटा) फिल्टर पर प्रतिक्रिया दें",
        "rcfilters-highlightbutton-title": "Highlight results",
        "rcfilters-highlightmenu-title": "रंग चुनें",
        "rcfilters-filter-editsbyother-label": "दूसरों के द्वारा बदलाव",
        "rcfilters-filter-editsbyother-description": "आपके बदलावों को छोड़ कर सभी के बदलाव।",
        "rcfilters-filtergroup-userExpLevel": "अनुभव स्तर (केवल पंजीकृत सदस्यों के लिए)",
-       "rcfilters-filter-user-experience-level-registered-label": "पंजीकृत:",
+       "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-hideminor-conflicts-typeofchange-global": "\"लघु संपादन\" फ़िल्टर एक या एक से अधिक प्रकार के परिवर्तन फ़िल्टर के साथ संघर्ष करता है, क्योंकि कुछ प्रकार के परिवर्तन को \"लघु\" के रूप में निर्दिष्ट नहीं किया जा सकता है। परस्पर विरोधी फिल्टर ऊपर सक्रिय फिल्टर क्षेत्र में चिह्नित हैं।",
        "rcfilters-hideminor-conflicts-typeofchange": "कुछ प्रकार के परिवर्तन को \"लघु\" के रूप में निर्दिष्ट नहीं किया जा सकता है\", इसलिए यह फ़िल्टर निम्न प्रकार के परिवर्तन फिल्टर के साथ संघर्ष करता है: $1",
        "rcfilters-typeofchange-conflicts-hideminor": "इस प्रकार का परिवर्तन फ़िल्टर \"लघु संपादन\" फ़िल्टर के साथ संघर्ष करता है। कुछ प्रकार के परिवर्तन को \"लघु\" के रूप में निर्दिष्ट नहीं किया जा सकता है।",
-       "rcfilters-filtergroup-lastRevision": "सदà¥\8dय अवतरण",
-       "rcfilters-filter-lastrevision-label": "à¤\85à¤\82तिम अवतरण",
+       "rcfilters-filtergroup-lastRevision": "नया अवतरण",
+       "rcfilters-filter-lastrevision-label": "नया अवतरण",
        "rcfilters-filter-lastrevision-description": "पृष्ठ का सबसे हाल में हुआ बदलाव",
        "rcfilters-filter-previousrevision-label": "पहले के अवतरण",
        "rcfilters-filter-previousrevision-description": "सभी परिवर्तन जो एक पृष्ठ में सबसे हाल के परिवर्तन नहीं हैं।",
        "rcfilters-filter-excluded": "अपवर्जित",
        "rcfilters-tag-prefix-namespace-inverted": " $1 <strong>:नहीं</strong>",
-       "rcfilters-view-tags": "à¤\9aिपà¥\8dपियाà¤\81",
+       "rcfilters-view-tags": "à¤\9fà¥\88à¤\97 à¤µà¤¾à¤²à¥\87 à¤¸à¤®à¥\8dपादन",
        "rcnotefrom": "नीचे <strong>$2</strong> के बाद से (<strong>$1</strong> तक) {{PLURAL:$5|हुआ बदलाव दर्शाया गया है|हुए बदलाव दर्शाए गये हैं}}।",
        "rclistfromreset": "चुने दिनांक पहले जैसा करें",
        "rclistfrom": "$3 $2 से नये बदलाव दिखाएँ",
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..4e1a8d2 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-filter-editsbyself-description": "Är eegen Ännerungen.",
        "rcfilters-filter-editsbyother-label": "Ännerunge vun Aneren",
        "rcfilters-filter-editsbyother-description": "All Ännerunge ausser Ären eegenen.",
-       "rcfilters-filtergroup-userExpLevel": "Niveau vun der Erfahrung (just fir registréiert Benotzer)",
+       "rcfilters-filtergroup-userExpLevel": "Umeldung an Erfarung vu Benotzer",
        "rcfilters-filter-user-experience-level-registered-label": "Ugemellt",
        "rcfilters-filter-user-experience-level-unregistered-label": "Net-ugemellt",
        "rcfilters-filter-user-experience-level-unregistered-description": "Auteuren déi net ageloggt sinn.",
        "rcfilters-filter-logactions-label": "Protokolléiert Aktiounen",
        "rcfilters-filter-logactions-description": "Administrativ Aktiounen, Uleeë vu Benotzerkonten, Läsche vu Säiten, Eropgeluede Fichieren, ...",
        "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-filtergroup-lastRevision": "Lescht Versiounen",
        "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 116b216..18af297 100644 (file)
@@ -41,7 +41,7 @@
        "tog-enotifminoredits": "Famme na masciata mail pure quanno se fanno cagnamiente piccerille 'e paggene e files",
        "tog-enotifrevealaddr": "Fa' vedé 'o ndirizzo mail ncopp'e mmasciate 'e notifica",
        "tog-shownumberswatching": "Fa' vedé 'o nummero d'utente che teneno 'a paggena cuntrullata",
-       "tog-oldsig": "Firma 'e mmo:",
+       "tog-oldsig": "'A firma vosta (mo' mo'):",
        "tog-fancysig": "Piglia 'a firma comme fosse nu wikitesto (senza fà link automatico)",
        "tog-uselivepreview": "Abbìa 'o \"Live preview\"",
        "tog-forceeditsummary": "Chiere a mme quanno se sta azzeccanno nu campo oggetto abbacante",
@@ -58,7 +58,7 @@
        "tog-showhiddencats": "Fa' vedé 'e categurie annascunnute",
        "tog-norollbackdiff": "Nun fà vedé 'o cunfronto nfra verziune quanno se fà nu rollback ('o torna arreto)",
        "tog-useeditwarning": "Famme sapé quanno lasso na paggena 'e mudifeca senza sarvà 'e cagnamiente",
-       "tog-prefershttps": "Usa sempe na connessione sicura quanno s'accummincia sessione",
+       "tog-prefershttps": "Usa sempe na connessione sicura pe' tramente ca s'accummincia sessione",
        "underline-always": "Sèmpe",
        "underline-never": "Màje",
        "underline-default": "Tiene sempe le mpostazzione d' 'o navigatóre",
        "newwindow": "(s'arape n'ata fenèsta)",
        "cancel": "Scancèlla",
        "moredotdotdot": "Cchiù...",
-       "morenotlisted": "Chisto elenco nun è cumpreto.",
+       "morenotlisted": "Chisto elenco putesse nun essere cumpleto sano sano.",
        "mypage": "Paggena",
        "mytalk": "'E chiàcchieriate mmie",
        "anontalk": "Chiacchierate",
        "navigation": "Navigazzione",
        "and": "&#32;e",
-       "qbfind": "Truòva",
-       "qbbrowse": "Sfoglia",
-       "qbedit": "Càgna",
-       "qbpageoptions": "Chesta paggena",
-       "qbmyoptions": "'E ppaggene mie",
        "faq": "FAQ",
-       "faqpage": "Project:Domanne frequente",
        "actions": "Azione",
        "namespaces": "Namespace",
        "variants": "Variante",
        "searcharticle": "Vàje",
        "history": "Verziune 'e primma",
        "history_short": "Cronologgia",
+       "history_small": "cronologgia",
        "updatedmarker": "cagnamiénte 'e ll'urdema visita d' 'a mia",
        "printableversion": "Verzione pe' stampa",
        "permalink": "Jonta permanente",
        "edit-local": "Càgna descrizione lucale",
        "create": "Crèa",
        "create-local": "Azzecca descrizione lucale",
-       "editthispage": "Càgna chesta paggena",
-       "create-this-page": "Crèa sta paggena",
        "delete": "Scancèlla",
-       "deletethispage": "Scancèlla chésta paggena",
-       "undeletethispage": "Arrepiglia chista paggena",
        "undelete_short": "Arremedia {{PLURAL:$1|na verziona|$1 vverziune}}",
        "viewdeleted_short": "Vide {{PLURAL:$1|nu cagnamiénto scancellato|$1 cagnamiénte scancellate}}",
        "protect": "Prutegge",
        "protect_change": "càgna",
-       "protectthispage": "Ferma chesta paggena",
        "unprotect": "Càgna prutezzione",
-       "unprotectthispage": "Càgna prutezzione 'e chesta paggena",
        "newpage": "Paggena nòva",
-       "talkpage": "Paggena 'e chiàcchiera",
        "talkpagelinktext": "Chiàcchiera",
        "specialpage": "Paggena speciàle",
        "personaltools": "Strumiente perzonale",
-       "articlepage": "Vere a paggena e contenuto",
        "talk": "Chiàcchiera",
        "views": "Visite",
        "toolbox": "Strumiente",
-       "userpage": "Vere a paggena utente",
-       "projectpage": "Vere a paggena 'e servizio",
+       "tool-link-userrights": "Càgna gruppe {{GENDER:$1|utente}}",
+       "tool-link-userrights-readonly": "Vire gruppe {{GENDER:$1|utente}}",
+       "tool-link-emailuser": "Manna na masciata email a st'{{GENDER:$1|utente}}",
        "imagepage": "Vere a paggena d' 'o file",
        "mediawikipage": "Vere 'a mmasciata",
        "templatepage": "Vere 'o template",
        "redirectedfrom": "(Redirect 'a $1)",
        "redirectpagesub": "Paggena 'e redirect",
        "redirectto": "Reindirizza a:",
-       "lastmodifiedat": "Urdemo cagnamiénto pe' a paggena: $2, $1.",
+       "lastmodifiedat": "Sta paggena fuje, n'urdema vota, cagnàta 'o $1, 'e $2.",
        "viewcount": "Chesta paggena è stata liggiùta {{PLURAL:$1|una vòta|$1 vòte}}.",
        "protectedpage": "Paggena prutetta",
        "jumpto": "Vaje a:",
        "createacct-another-username-ph": "'Nserisce 'o nomme utente",
        "yourpassword": "Password:",
        "userlogin-yourpassword": "Password",
-       "userlogin-yourpassword-ph": "'Nserisce 'a toja password",
+       "userlogin-yourpassword-ph": "Nzertàte 'a password vuosta",
        "createacct-yourpassword-ph": "'Nserisce 'na password",
        "yourpasswordagain": "Ripete 'a password:",
        "createacct-yourpasswordagain": "Cunferma password",
        "eauthentsent": "Na mmasciata 'e conferma t'è stata mannata a l'indirizzo e-mail nzignàto.\nApprimm' 'e te mannà n'atu mail, hè 'a stà 'a ffà 'e struzione dint'a l'e-mail, pe' cunfermà ca 'o cunto fosse d' 'o tujo overo.",
        "throttled-mailpassword": "S'è mannata na mail pe te' riabbià 'a password 'a meno 'e {{PLURAL:$1|n'ora|$1 ore}}.\nPe' ce sparagnà abbuse, 'a funzione 'e riabbiamento d' 'a password se può usa sulamente na vota ogne {{PLURAL:$1|ora|$1 ore}}.",
        "mailerror": "Errore pe' tramente ca se mannava na mmasciata: $1",
-       "acct_creation_throttle_hit": "{{PLURAL:$1|1 registrazzione è già stata effettuata|$1 registrazzione song già state effettuate}} 'e qualcuno cu 'o tujo stisso innerezzo IP dint'ô urdemo juorno: è 'o massimo cunsentito 'n chisto periodo 'e tiempo.\nPerciò, 'e utente ca ausano chisto innerezzo IP nun possono registrarse ppe 'o mumiento.",
+       "acct_creation_throttle_hit": "'E vvisite a sta wiki ausanno l'IP tuoja se so' mise a crià {{PLURAL:$1|1 registrazzione|$1 registrazzione}} int'a ll'urdeme juorne ($2), chesto fosse 'o massimo premmesso pe' stu periodo 'e tiempo.\nPerciò, 'e utente ca ausano chisto innerezzo IP nun se ponno riggistrà ancora mò mò.",
        "emailauthenticated": "'O ndirizzo email è stato cunfermato 'o $2 a 'e $3.",
        "emailnotauthenticated": "'O ndirizzo 'e posta elettronica nun è stat'ancora cunfermato.\nNun se mannarranno mmasciate e-mail p' ' funzione ccà abbascio.",
        "noemailprefs": "Avite 'a specificà nu ndirizzo e-mail pe ll'attivà sti funzione.",
        "botpasswords-label-delete": "Scancèlla",
        "botpasswords-label-resetpassword": "Riabbìa 'a password",
        "botpasswords-label-grants": "Assegnaziune apprecabbele:",
-       "botpasswords-help-grants": "Ogne assegnazione dà acciesso a 'e deritte utente elencate ca n'utenza avesse già. Vedite 'a [[Special:ListGrants|tabbella 'e ll'assegnaziune]] pe' ne mòvere cchiù nfurmaziune.",
+       "botpasswords-help-grants": "L'assegnazione premmettessero ausà deritte utente elencate ca n'utenza avesse già. Premmettenno st'assegnazione ccà nun è ca ve facesse trasì int'a sti deritte, pecché 'o cunto vuosto nun 'e tenisse pe' n'atu mezzo. Vedite 'a [[Special:ListGrants|tabbella 'e ll'assegnaziune]] pe' ne mòvere cchiù nfurmaziune.",
        "botpasswords-label-grants-column": "Assegnaziune date",
        "botpasswords-bad-appid": "'O nomme bot \"$1\" nun è bbuono.",
        "botpasswords-insert-failed": "Nun se pò azzeccà 'o nomme bot \"$1\". Fosse stato già azzeccato?",
        "botpasswords-updated-body": "'A password bot \"$1\" 'a ll'utente \"$2\" fuje agghiurnata.",
        "botpasswords-deleted-title": "Password bot scancellata",
        "botpasswords-deleted-body": "'A password bot \"$1\" 'a ll'utente \"$2\" è stata scancellata.",
-       "botpasswords-newpassword": "'A password nòva pe' puté trasì cu <strong>$1</strong> è <strong>$2</strong>. <em>Pe' piacere signatevello chesto pe' ve ffà conzurtaziune future.</em>",
+       "botpasswords-newpassword": "'A password nòva pe' puté trasì cu <strong>$1</strong> è <strong>$2</strong>. <em>Pe' piacere signatevello chesto pe' ve ffà conzurtaziune future.</em> <br>('E bott viecchie addò servisse nu nomme utente comm'a chell' 'e l'utente, putite ancora ausà <strong>$3</strong> comm' 'o nomm' 'utente e <strong>$4</strong> comm' 'a password.)",
        "botpasswords-no-provider": "BotPasswordsSessionProvider nun è disponibbele.",
        "botpasswords-restriction-failed": "'E restriziune 'e password bot nun ve permettessero st'acciesso.",
        "botpasswords-invalid-name": "'O nomme utente nnecato nun cuntenesse nu spartetóre 'e bot password (\"$1\").",
        "blockedtitle": "Utente bloccato.",
        "blockedtext": "<strong>'O nomme utente o ll'IP vuosto è stato bloccato.</strong>\n\n'O blocco è stato mpustato 'a $1. 'O mutivo d' 'o blocco è chesto: ''$2''\n\n* Abbiàta d' 'o blocco: $8\n* Ammaturità d' 'o blocco: $6\n* Tiempo 'e blocco: $7\n\nPutite cuntattà $1 o n'atu [[{{MediaWiki:Grouppage-sysop}}|ammenistratore]] pe' discutere 'o blocco.\n\nVedite c' 'a funzione 'Scrivete a ll'utente' nun è attiva si nun s'è riggistrato 'o ndirizzo e-mail buono dint' 'e [[Special:Preferences|preferenze]] o pùre si ll'uso 'e tale funzione è stato bloccato.\n\n'O ndirizzo IP attuale è $3, 'o nummero ID d' 'o blocco è #$5.\nPe' piacere avite 'e specificà tutte sti dettaglie ccà ncoppa quanno facite cocche dumanna.",
        "autoblockedtext": "Ll'IP vuosto è stato bloccato pecché 'o steva piglianno n'atu utente, ch'è stato bloccato pe' $1.\n\n'O mutivo d' 'o blocco è chesto:\n\n:''$2''\n\n* Abbiàta d' 'o blocco: $8\n* Ammaturità d' 'o blocco: $6\n* Tiempo 'e blocco: $7\n\nPutite cuntattà $1 o n'atu [[{{MediaWiki:Grouppage-sysop}}|ammenistratore]] pe' discutere 'o blocco.\n\nVedite c' 'a funzione 'Scrivete a ll'utente' nun è attiva si nun s'è riggistrato 'o ndirizzo e-mail buono dint' 'e [[Special:Preferences|preferenze]] o pùre si ll'uso 'e tale funzione è stato bloccato.\n\n'O ndirizzo IP attuale è $3, 'o nummero ID d' 'o blocco è #$5.\nPe' piacere avite 'e specificà tutte sti dettaglie ccà ncoppa quanno facite cocche dumanna.",
+       "systemblockedtext": "'O nomme utente d' 'o vuosto o ll'IP address fosse stata automaticamente bluccata 'a MediaWiki.\n'O mutivo fosse chesto:\n\n:<em>$2</em>\n\n* Inizio d' 'o blocco: $8\n* Ammatura 'o blocco: $6\n* Intervall' 'e blocco: $7\n\n'O indirizzo IP 'e mò fosse $3.\nPe' piacere, facite specifice tuttuquante 'e ddettaglie ccà quanno iate a ghienchere na richiesta 'e chiarimiente.",
        "blockednoreason": "nisciuna ragione è stata indicata",
        "whitelistedittext": "Pe' cagnà 'e ppaggene è necessario $1.",
        "confirmedittext": "Pe puté cagnà paggene avite 'a cunfermà l'indirizzo e-mail.\nPe' piacere abbiate e ffà 'a validazione d' 'o ndirizzo e-mail pe' bbìa d' 'e [[Special:Preferences|preferenze d'utente]].",
        "readonlywarning": "<strong>Attenziò</strong>: 'o database è bloccato pe se ffà 'a manutenzione. P' 'o mumento nun se ponno sarvà 'e cagnamiente fatte.\nPe' nun 'e sperdere, copia sti cuntenute dint'a nu file 'e testo e sarvatillo pe' tramente c'aspiette 'o sblocco d' 'o database.\n\nL'ammenistratore 'e sistema ca mpustaje 'o blocco ave scritto sta spiegazione: $1.",
        "protectedpagewarning": "'''Attenziò: sta paggena è stata bloccata 'n modo tale ca sulamente l'utente ch' 'e privilegge d'ammenistratore 'a ponno cagnà.'''\nL'urdemo elemento d' 'o riggistro è scritto ccà abbascio pe' n'avé riferimento:",
        "semiprotectedpagewarning": "'''Nota:''' Sta paggena è stata bloccata 'n modo ca sulamente l'utente riggistrate 'a ponno cagnà.\nL'urdemo elemento d' 'o riggistro è scritto ccà abbascio pe n'avé nfurmazione:",
-       "cascadeprotectedwarning": "'''Attenziò:''' Sta paggena è stata bloccata 'n modo ca sulamente l'utente ch' 'e privilegge d'ammenistratore 'a ponno cagnà. Chesto succiere pecché 'a paggena è appennuta dint'a {{PLURAL:$1|la paggena innecata ccà abbascio, ch'è stata prutetta|'e paggene innecate ccà abbascio, che so' state prutette}} sciglienno 'a prutezione \"ricurziva\":",
+       "cascadeprotectedwarning": "<strong>Attenziò:</strong> Sta paggena è stata bloccata 'n modo ca sulamente l'utente ch' 'e [[Special:ListGroupRights|privilegge specifiche]] 'a ponno cagnà. Chesto succiere pecché 'a paggena è appennuta dint'a {{PLURAL:$1|la paggena innecata ccà abbascio, ch'è stata prutetta|'e paggene innecate ccà abbascio, che so' state prutette}} sciglienno 'a prutezione \"ricurziva\":",
        "titleprotectedwarning": "'''Attenziò: sta paggena è stata bloccata 'n modo ca fossero necessarie [[Special:ListGroupRights|deritte specifici]] p' 'a crià.'''\nL'urdemo elemento d' 'o riggistro è riportato ccà abbascio pe nfurmazione:",
        "templatesused": "{{PLURAL:$1|Template|Templates}} ausate 'a chesta paggena:",
        "templatesusedpreview": "{{PLURAL:$1|Template|Templates}} ausate dint'a st'anteprimma:",
        "invalid-content-data": "Date cuntenute nun buone",
        "content-not-allowed-here": "'O cuntenuto \"$1\" nun è permesso dint'a paggena [[$2]]",
        "editwarning-warning": "Ascenno 'e sta paggena putisse ffà sperdere 'e cagnamiente fatte.\nSi sì trasuto, allora può stutà st'avviso dint'a sezziona \"{{int:prefs-editing}}\" d' 'e preferenze.",
+       "editpage-invalidcontentmodel-title": "Mudell' 'e cuntenute nun suppurtato",
+       "editpage-invalidcontentmodel-text": "'O mudell' 'e cuntenute \"$1\" nun è suppurtato.",
        "editpage-notsupportedcontentformat-title": "Furmato d' 'o cuntenuto nun suppurtato",
        "editpage-notsupportedcontentformat-text": "'O furmato d' 'o cuntenuto $1 nun è suppurtato d' 'o mudello 'e cuntenuto $2.",
        "content-model-wikitext": "wikitesto",
        "post-expand-template-argument-warning": "'''Attenziò:''' sta paggena cuntene uno o cchiù argumente 'e template troppo gruosse pe' 'a spannere. Sti argumente se lassarranno fore.",
        "post-expand-template-argument-category": "Paggene ca cunteneno argumente nun cunziderate",
        "parser-template-loop-warning": "È stato scummigliato n'aniello d' 'o template: [[$1]]",
+       "template-loop-category": "Paggene ca chiammassero a esse stisse",
+       "template-loop-category-desc": "Sta paggena tenesse nu template ca chiammasse a essa stissa, cioè nu template addò sta mmescat' 'o template ca 'o chiammasse.",
        "parser-template-recursion-depth-warning": "È arrivato 'o lemmeto 'e ricurzione d' 'o template ($1)",
        "language-converter-depth-warning": "'O fùto d' 'o lemmeto d' 'o scagnatòre 'e lengua è appassato ($1)",
        "node-count-exceeded-category": "Paggene addò 'o nummero 'e núrece è stato appassato",
        "page_first": "primma",
        "page_last": "úrdema",
        "histlegend": "Confronto nfra verziune: sciglite 'e casciulelle c'attoccassero a 'e verziune che vulite cunfruntà e spremmite Invio o pure 'o buttóne ccà abbascio.\n\nLiggenda: '''({{int:cur}})''' = differenze c' 'a verzione 'e mmò, '''({{int:last}})''' = differenze c' 'a verzione 'e primma, '''{{int:minoreditletter}}''' = cagnamiento minore",
-       "history-fieldset-title": "Naviga dint' 'a cronologgia",
-       "history-show-deleted": "Solo chille canciellate",
+       "history-fieldset-title": "Circa pe' verziune",
+       "history-show-deleted": "Sulo 'e verziune scancellate",
        "histfirst": "primma",
        "histlast": "urdema",
        "historysize": "({{PLURAL:$1|1 byte|$1 byte}})",
        "searchprofile-advanced-tooltip": "Circa dint'e namespace perzonalizzate",
        "search-result-size": "$1 ({{PLURAL:$2|'na parola|$2 parole}})",
        "search-result-category-size": "{{PLURAL:$1|1 utente|$1 utente}} ({{PLURAL:$2|1 sottocategurìa|$2 sottocategurìe}}, {{PLURAL:$3|1 file|$3 files}})",
-       "search-redirect": "(redirect $1)",
+       "search-redirect": "(redirect 'a $1)",
        "search-section": "(sezzione $1)",
        "search-category": "(categurìa $1)",
        "search-file-match": "(currispunnenza dint' 'e cuntenute d' 'o file)",
        "search-suggest": "Prova chisto: $1",
        "search-rewritten": "Mmustann' 'e risultate pe' $1. Circa mmece pe' $2.",
-       "search-interwiki-caption": "Prugiette frate",
+       "search-interwiki-caption": "Risultate 'a prugiette frate",
        "search-interwiki-default": "Risultate 'a $1:",
        "search-interwiki-more": "(cchiù)",
+       "search-interwiki-more-results": "cchiù risultate",
        "search-relatedarticle": "Azzeccato",
        "searchrelated": "azzeccato",
        "searchall": "Tutte",
        "search-external": "Ricerca 'a fore",
        "searchdisabled": "'A ricerca dint'a {{SITENAME}} nun è attiva; pe' tramente se putesse ausà nu mutore 'e cerca sterno comm'a Google. (Avite 'e sapé però, ca sti cuntenute d' 'o {{SITENAME}} dint' 'e mutore, può darse ca nun stanno agghiurnate.)",
        "search-error": "È succiesso n'errore pe' tramente ca se faceva 'a ricerca: $1",
+       "search-warning": "È succiesso n'avvertimento pe' tramente ca se vaceva 'a ricerca: $1",
        "preferences": "Preferenze d''e mmeje",
        "mypreferences": "Preferenze d''e mmeje",
        "prefs-edits": "Cagnamiente affettuate:",
        "prefs-help-recentchangescount": "Chesto ntenne ll'urdeme cagnamiente, 'e cronologgie 'e paggena, e riggistre.",
        "prefs-help-watchlist-token2": "Chest'è 'a chiave segreta pe se ffà 'o feed web 'e l'elenco 'e cuntrolo d' 'o vuosto.\nSi coccheruno 'a cunoscesse, allora putesse vedé l'elenco 'e cuntrollo, picciò nun 'a spartite. [[Special:ResetTokens|Cliccate ccà se tenite necessità d' 'a rimpizzà]].",
        "savedprefs": "'E preferenze songo state sarvate.",
-       "savedrights": "'E dritte 'e l'utente {{GENDER:$1|$1}} sto state sarvate.",
+       "savedrights": "'E dritte 'e gruppe 'utente {{GENDER:$1|$1}} sto state sarvate.",
        "timezonelegend": "Fuso orario:",
        "localtime": "Ora lucale:",
        "timezoneuseserverdefault": "Aúsa ora predefinita d' 'o wiki ($1)",
        "youremail": "E-mail:",
        "username": "{{GENDER:$1|Nomme utente}}:",
        "prefs-memberingroups": "{{GENDER:$2|Membro}} {{PLURAL:$1|d' 'o gruppo|d' 'e gruppe}}:",
+       "group-membership-link-with-expiry": "$1 (nzin' 'a $2)",
        "prefs-registration": "Data 'e riggistrazione:",
        "yourrealname": "Nomme vero",
        "yourlanguage": "Lengua:",
        "prefs-help-prefershttps": "Sta preferenza averrà affetto 'a 'o prossimo acciesso vuosto.",
        "prefswarning-warning": "Avite fatto cagnamiente a 'e preferenze d' 'e vuoste ca nun so' stat'ancora sarvate.\nSi ascite 'a sta paggena senza clickà \"$1\" 'e preferenze d' 'e vuoste nun sarranno agghiurnate.",
        "prefs-tabs-navigation-hint": "Suggerimento: se ponno ausà 'e buttòne 'e freccia a manca e a dritta pe' ve muovere nfra 'e schede dint'a l'elenco d' 'e schede.",
-       "userrights": "Gestione d' 'e permesse 'e l'utente",
-       "userrights-lookup-user": "Gestione 'e gruppe d'utenza",
+       "userrights": "Deritte utente",
+       "userrights-lookup-user": "Sciglie n'utente",
        "userrights-user-editname": "Nzertàte nu nomme utente:",
-       "editusergroup": "Cagnate 'e gruppe d'{{GENDER:$1|utenze}}",
+       "editusergroup": "Càrreca gruppe 'utente",
        "editinguser": "Cagnamiento d' 'e deritte d'{{GENDER:$1|utente}} '''[[User:$1|$1]]''' $2",
-       "userrights-editusergroup": "Cagnate 'e gruppe d'utenze",
+       "viewinguserrights": "Verenn' 'e deritte '{{GENDER:$1|utente}} <strong>[[User:$1|$1]]</strong> $2",
+       "userrights-editusergroup": "Cagna 'e gruppe '{{GENDER:$1|utente}}",
+       "userrights-viewusergroup": "Vire gruppe {{GENDER:$1|utente}}",
        "saveusergroups": "Sarvate 'e gruppe d'{{GENDER:$1|utenza}}",
        "userrights-groupsmember": "Ffà parte {{PLURAL:$1|d' 'o gruppo|d' 'e gruppe}}:",
        "userrights-groupsmember-auto": "Membro mplicito 'e:",
-       "userrights-groups-help": "Putite cagnà 'e gruppe assegnate a l'utente:\n* Na cascia 'e spunta scigliuta significasse ca appartenenza 'e l'utente a 'o gruppo\n* Na cascia 'e spunta nun scigliuta significasse 'a nun appartenenza a 'o gruppo.\n* 'O simmolo * significasse ca nun se può scancellà l'appartenenza a 'o gruppo aropp'a ll'avé miso (o viceversa).",
+       "userrights-groups-help": "Putite cagnà 'e gruppe assegnate a l'utente:\n* Na cascia 'e spunta scigliuta significasse ca appartenenza 'e l'utente a 'o gruppo\n* Na cascia 'e spunta nun scigliuta significasse 'a nun appartenenza a 'o gruppo.\n* 'O simmolo * significasse ca nun se può scancellà l'appartenenza a 'o gruppo aropp'a ll'avé miso (o viceversa).\n* 'O # significasse ca vuje putite surtanto tirà arreto nu tiempo 'e ammatura 'e stu gruppo utente; nun 'o putite fà annanze.",
        "userrights-reason": "Mutivo:",
        "userrights-no-interwiki": "Nun tenite permesse pe' cagnà 'e deritte 'e l'utente ncopp'a l'ati wiki.",
        "userrights-nodatabase": "'O database $1 nun esiste o nun è nu database lucale.",
        "userrights-changeable-col": "Gruppe ca putite cagnà",
        "userrights-unchangeable-col": "Gruppe ca nun putite cagnà",
+       "userrights-expiry-current": "Ammatura 'o $1",
+       "userrights-expiry-none": "Nun ammaturasse",
+       "userrights-expiry": "Ammatura:",
+       "userrights-expiry-existing": "'O tiempo d'ammaturamiento esistente: $3, $2",
+       "userrights-expiry-othertime": "N'ata durata:",
+       "userrights-expiry-options": "1 juorne:1 day,1 semmana:1 week,1 mese:1 month,3 mise:3 mise,6 mesi:6 months,1 anno:1 year",
+       "userrights-invalid-expiry": "'O tiempo pe' quanno ammatura 'o gruppo \"$1\" nun è buono.",
+       "userrights-expiry-in-past": "'O tiempo pe' quanno ammatura 'o gruppo \"$1\" fosse int' 'o passato.",
+       "userrights-cannot-shorten-expiry": "Nun putite turnà arreto 'o tiempo ammatura int' 'o gruppo \"$1\". Surtanto ll'utente cu nu permesso pe' puté azzeccà o luvà stu gruppo ponno ffà annanze 'e tiempe ammaturamiento.",
        "userrights-conflict": "Conflitto 'e cagnamiento 'e deritte utente! Cuntrullate e cunfermate 'e cagnamiente vuoste.",
        "group": "Gruppo:",
        "group-user": "Utente",
        "grant-basic": "Deritte 'e base",
        "grant-viewdeleted": "Vide 'e file e paggene scancellate",
        "grant-viewmywatchlist": "Vide l'elenco 'e cuntrullate",
+       "grant-viewrestrictedlogs": "Vide 'e valure private d' 'o riggistro",
        "newuserlogpage": "Riggistro 'e nuove utente",
        "newuserlogpagetext": "Chest'è nu riggistro 'e criazione d'utenze.",
        "rightslog": "Deritte 'e ll'utente",
        "action-upload_by_url": "carreca stu file 'a n'indirizzo URL",
        "action-writeapi": "usa l'API 'n scrittura",
        "action-delete": "scancèlla chista paggena",
-       "action-deleterevision": "scancellà sta verziona",
+       "action-deleterevision": "scancellà 'e verziune",
        "action-deletedhistory": "vide 'a cronologgia scancellata 'e sta paggena",
        "action-browsearchive": "ascìa dint' 'e paggene scancellate",
        "action-undelete": "arripiglia chista paggena",
index 21533aa..7065d7b 100644 (file)
        "post-expand-template-inclusion-category": "Sider som inneheld for store malar",
        "post-expand-template-argument-warning": "Åtvaring: Sida inneheld ein eller fleire malparameterar som vert for lange når dei utvidast.\nDesse parameterane har vorte utelatne.",
        "post-expand-template-argument-category": "Sider med utelatne malparameterar",
-       "parser-template-loop-warning": "Malløkka oppdaga: [[$1]]",
+       "parser-template-loop-warning": "Mallykkje oppdaga: [[$1]]",
        "parser-template-recursion-depth-warning": "Malen er inkludert for mange gonger ($1)",
        "language-converter-depth-warning": "Språkomformaren si djubdegrense vart overstege ($1)",
        "node-count-exceeded-category": "Sider der talet på knutepunkt er overskride",
        "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..a584068 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",
        "delete-warning-toobig": "Ta strona ma bardzo długą historię edycji – ponad $1 {{PLURAL:$1|zmianę|zmiany|zmian}}.<br />\nBądź ostrożny, ponieważ usunięcie jej może spowodować zakłócenia w pracy {{GRAMMAR:D.lp|{{SITENAME}}}}.",
        "deleteprotected": "Nie możesz usunąć tej strony, ponieważ została zabezpieczona.",
        "deleting-backlinks-warning": "<strong>Uwaga:</strong> Do strony, którą masz zamiar usunąć, odwołują się [[Special:WhatLinksHere/{{FULLPAGENAME}}|inne strony]].",
+       "deleting-subpages-warning": "<strong>Ostrzeżenie:</strong> Strona którą chcesz usunąć ma [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|jedną podstronę|$1 podstrony|$1 podstron|51=ponad 50 podstron}}]].",
        "rollback": "Cofnij edycję",
        "rollbacklink": "cofnij",
        "rollbacklinkcount": "cofnij $1 {{PLURAL:$1|edycję|edycje|edycji}}",
index 81b6f72..f917ee5 100644 (file)
@@ -14,7 +14,8 @@
                        "Matma Rex",
                        "Saanvel",
                        "Satdeep gill",
-                       "Abbas dhothar"
+                       "Abbas dhothar",
+                       "Saraiki"
                ]
        },
        "tog-underline": "جوڑ تھلے لین:",
        "category-file-count-limited": "اس گٹھ چ اے {{PLURAL:$1|فائل اے|$1 فائلاں نیں}}۔",
        "listingcontinuesabbrev": "جاری",
        "index-category": "انڈیکسڈ صفے",
-       "noindex-category": "نان انڈیکسڈ صفے",
+       "noindex-category": "نان انڈیکسڈ ورقے",
        "broken-file-category": "ٹٹے ہوۓ جوڑاں آلے صفحے",
        "about": "بارے چ",
        "article": "آرٹیکل والا صفہ",
        "anontalk": "گل",
        "navigation": "کھوج",
        "and": "&#32;تے",
-       "qbfind": "کھوج",
-       "qbbrowse": "لبو",
-       "qbedit": "لکھو",
-       "qbpageoptions": "اے صفہ",
-       "qbmyoptions": "میرے صفے",
        "faq": "FAQ",
-       "faqpage": "Project:FAQ",
        "actions": "کم",
        "namespaces": "ناں تھانواں:",
        "variants": "قسماں",
        "view": "وکھالہ",
        "view-foreign": "$1 تے ویکھو",
        "edit": "لکھو",
+       "edit-local": "مقامی تفصیل درج کرو",
        "create": "بناؤ",
        "create-local": "آپنی لکھت رلاؤ",
-       "editthispage": "اس صفحہ تے لکھو",
-       "create-this-page": "اے صفحہ بناؤ",
        "delete": "مٹاؤ",
-       "deletethispage": "اے صفحہ مٹاؤ",
-       "undeletethispage": "اس صفحے نوں واپس لیاؤ",
        "undelete_short": "مٹانا واپس {{PLURAL:$1|اکتبدیلی|$1 تبدیلی}}",
        "viewdeleted_short": "ویکھو {{PLURAL:$1|اک مٹائی گئی تبدیلی|$1 مٹائیاں گئیاں تبدیلیاں}}",
        "protect": "بچاؤ",
        "protect_change": "تبدیل کرو",
-       "protectthispage": "اے صفحہ بچاؤ",
        "unprotect": "اینا بچاؤ",
-       "unprotectthispage": "اے صفحہ اینا بچاؤ",
        "newpage": "نواں صفہ",
-       "talkpage": "اس صفحے دے بارے چ گل بات کرو",
        "talkpagelinktext": "گل بات",
        "specialpage": "خاص صفحہ",
        "personaltools": "ذاتی اوزار",
-       "articlepage": "مضمون آلا صفحہ",
        "talk": "گل بات",
        "views": "وکھالے",
        "toolbox": "سَند",
-       "userpage": "ورتن آلے دا صفہ ویکھو",
-       "projectpage": "ویونت والا صفہ ویکھو",
        "imagepage": "فائل آلا صفہ ویکھو",
        "mediawikipage": "سنیعا آلا صفحہ ویکھو",
        "templatepage": "سچے آلا صفحہ ویکھو",
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 719f413..699ac96 100644 (file)
        "specialpages": "{{doc-special|SpecialPages|unlisted=1}}\nDisplay name of link to [[Special:SpecialPages]] shown on all pages in the toolbox.\n\nSee also:\n* {{msg-mw|Specialpages}}\n* {{msg-mw|Accesskey-t-specialpages}}\n* {{msg-mw|Tooltip-t-specialpages}}\n{{Identical|Special page}}",
        "specialpages-summary": "{{doc-specialpagesummary|specialpages}}",
        "specialpages-note-top": "Heading for {{msg-mw|specialpages-note}}.\n{{Identical|Legend}}",
-       "specialpages-note": "Footer note for the [[Special:SpecialPages]] page",
+       "specialpages-note-restricted": "Footer note for the [[Special:SpecialPages]] page",
+       "specialpages-note-cached": "{{ignore}}\nFooter note for the [[Special:SpecialPages]] page",
        "specialpages-group-maintenance": "{{doc-special-group|like=[[Special:DoubleRedirects]], [[Special:LonelyPages]] and [[Special:WantedPages]]}}",
        "specialpages-group-other": "{{doc-special-group|like=[[Special:AdminLinks]] and [[Special:BookSources]]}}",
        "specialpages-group-login": "{{doc-special-group|like=[[Special:UserLogin]]}}",
index 55d3bdb..cfb86b0 100644 (file)
        "rcfilters-noresults-conflict": "Nu s-au găsit rezultate deoarece criteriile de căutare sunt în conflict",
        "rcfilters-state-message-subset": "Acest filtru nu are efecte deoarece rezultatele sale sunt incluse în filtrele cu selectie mai largă {{PLURAL:$2|filtru|filtre}} (încercați să subliniați pentru a o deosebi): $1",
        "rcfilters-state-message-fullcoverage": "Selectarea tuturor filtrelor dintr-un grup este aceeași cu cea selectată, astfel încât acest filtru nu are efect. Grupul include: $1",
-       "rcfilters-filtergroup-registration": "Înregistrare utilizator",
-       "rcfilters-filter-registered-label": "Înregistrat",
-       "rcfilters-filter-registered-description": "Editorii conectați.",
-       "rcfilters-filter-unregistered-label": "Neînregistrat",
-       "rcfilters-filter-unregistered-description": "Editorii care nu sunt conectați.",
-       "rcfilters-filter-unregistered-conflicts-user-experience-level": "Acest filtru contravine {{PLURAL:$2|filtru|filtre}} de Experiență, care {{PLURAL:$2|găsesc|gasește}} doar userii inreistrați: $1",
        "rcfilters-filtergroup-authorship": "Contribuția autorului",
        "rcfilters-filter-editsbyself-label": "Modificările tale",
        "rcfilters-filter-editsbyself-description": "Contribuțiile tale.",
        "rcfilters-filter-editsbyother-label": "Contribuțiile altora",
        "rcfilters-filter-editsbyother-description": "Toate modificările mai puțin ale tale.",
        "rcfilters-filtergroup-userExpLevel": "Nivel de experiență (numai pentru utilizatorii înregistrați)",
-       "rcfilters-filtergroup-user-experience-level-conflicts-unregistered": "Filtrele Experiență găsesc numai utilizatori înregistrați, deci acest filtru este în conflict cu filtrul \"Înregistrat\".",
-       "rcfilters-filtergroup-user-experience-level-conflicts-unregistered-global": "Filtrul \"Înregistrat\" ​​este în conflict cu unul sau mai multe filtre Experiență, care găsește numai utilizatorii înregistrați. Filtrele conflictuale sunt marcate în zona Filtre active, de mai sus.",
+       "rcfilters-filter-user-experience-level-registered-label": "Înregistrat",
+       "rcfilters-filter-user-experience-level-registered-description": "Editorii conectați.",
+       "rcfilters-filter-user-experience-level-unregistered-label": "Neînregistrat",
+       "rcfilters-filter-user-experience-level-unregistered-description": "Editorii care nu sunt conectați.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Nou veniți",
        "rcfilters-filter-user-experience-level-newcomer-description": "Mai puțin de 10 editări și 4 zile de activitate.",
        "rcfilters-filter-user-experience-level-learner-label": "Cursanți",
        "logentry-delete-delete": "$1 {{GENDER:$2|a șters}} pagina $3",
        "logentry-delete-delete_redir": "$1 {{GENDER:$2|a șters}} pagina de redirecționare $3 prin suprascriere",
        "logentry-delete-restore": "$1 {{GENDER:$2|a restaurat}} pagina $3 ($4)",
-       "restore-count-files": "{{PLURAL:$1|1 fișier|$1 fișiere}}",
+       "restore-count-revisions": "{{PLURAL:$1|1 versiune|$1 versiuni|$1 de versiuni}}",
+       "restore-count-files": "{{PLURAL:$1|1 fișier|$1 fișiere|$1 de fișiere}}",
        "logentry-delete-event": "$1 {{GENDER:$2|a schimbat}} vizibilitatea {{PLURAL:$5|unui eveniment din jurnal|a $5 evenimente din jurnal|a $5 de evenimente din jurnal}} pentru $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|a schimbat}} vizibilitatea {{PLURAL:$5|unei versiuni|a $5 versiuni|a $5 de versiuni}} pentru pagina $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|a modificat}} vizibilitatea evenimentelor din jurnal pentru $3",
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..a678e3b
--- /dev/null
@@ -0,0 +1,573 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Saraiki"
+               ]
+       },
+       "tog-underline": "لنک  ہیٹھ لکیر",
+       "tog-hideminor": "چھوٹیاں تبدیلیاں لُکاؤ",
+       "tog-showtoolbar": "آلات ترمیم ݙکھاؤ",
+       "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": "{{PLURAL:$3| تہاݙے کیتے}} $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": "ماخذ ݙیکھو",
+       "viewsource-title": "$1 دا مسودہ ݙیکھو",
+       "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:",
+       "compareselectedversions": "منتخب متـن دا موازنہ",
+       "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-file-match": "فائل مواد نال ملدا ہے",
+       "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": "اجازت نامہ:",
+       "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]]\" بچایا گیا اے",
+       "modifiedarticleprotection": "«[[$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-minoredit": "ایں کوں نکی ترممیم وچ ڳݨو",
+       "tooltip-save": "تبدیلیاں محفوظ کرو",
+       "tooltip-preview": "محفوظ کرݨ کنے پہلے تبدیلیاں ݙیکھو، مہربانی ہوسی۔",
+       "tooltip-diff": "ایں لکھت وچ کیتیاں ڳیاں تبدیلیاں ݙیکھاؤ",
+       "tooltip-watch": "ایں ورقے کوں آپݨی دید آلے ورقیاں وچ رکھو",
+       "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..991aa68 100644 (file)
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "ווייזן",
        "rcfilters-activefilters": "אַקטיווע פילטערס",
+       "rcfilters-days-show-days": "$1 {{PLURAL:$1|טאג|טעג}}",
+       "rcfilters-days-show-hours": "$1 {{PLURAL:$1|שעה|שעה'ן}}",
        "rcfilters-quickfilters": "אויפֿגעהיטענע פֿילטערס",
        "rcfilters-quickfilters-placeholder-title": "קיין לינקען נאך נישט אויפֿגעהיטן",
        "rcfilters-savedqueries-defaultlabel": "אױפֿגעהיטענע פֿילטערס",
        "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 16a8aaf..813dca2 100644 (file)
        "mw-widgets-usersmultiselect-placeholder": "加入更多...",
        "date-range-from": "開始日期:",
        "date-range-to": "結束日期:",
-       "sessionmanager-tie": "ç\84¡æ³\95å\90\88ä½µå¤\9aå\80\8bè«\8bæ±\82èª\8d証類型:$1。",
+       "sessionmanager-tie": "ç\84¡æ³\95å\90\88ä½µå¤\9aå\80\8bè«\8bæ±\82èª\8dè­\89類型:$1。",
        "sessionprovider-generic": "$1 連線階段",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "以 cookie 為基礎的連線階段",
        "sessionprovider-nocookies": "Cookie 功能可能已被關閉,請確認您改開啟 Cookie 功能並重新啟動。",
        "log-action-filter-suppress-reblock": "由重新封鎖禁止顯示使用者",
        "log-action-filter-upload-upload": "新上傳",
        "log-action-filter-upload-overwrite": "重新上傳",
-       "authmanager-authn-not-in-progress": "èª\8d証尚未進行或連線階段資料已遺失,請重頭再開始。",
+       "authmanager-authn-not-in-progress": "èª\8dè­\89尚未進行或連線階段資料已遺失,請重頭再開始。",
        "authmanager-authn-no-primary": "提供的憑證無法用來認証。",
        "authmanager-authn-no-local-user": "提供的憑證沒有與任何在此 wiki 上的使用者相關聯。",
        "authmanager-authn-no-local-user-link": "提供的憑證有效但沒有與任何在此 wiki 上的使用者相關聯。請採用其他方式登入,或建立新使用者,您將會有選項可以連結您先前的憑證到新帳號。",
        "authprovider-confirmlink-ok-help": "顯示連結失敗訊息後繼續。",
        "authprovider-resetpass-skip-label": "略過",
        "authprovider-resetpass-skip-help": "略過重設密碼。",
-       "authform-nosession-login": "å·²æ\88\90å\8a\9fèª\8d証,但您的瀏覽器無法 \"記住\" 登入資訊。\n\n$1",
+       "authform-nosession-login": "å·²æ\88\90å\8a\9fèª\8dè­\89,但您的瀏覽器無法 \"記住\" 登入資訊。\n\n$1",
        "authform-nosession-signup": "已建立帳號,但您的瀏覽器無法 \"記住\" 登入資訊。\n\n$1",
        "authform-newtoken": "缺少密鑰。$1",
        "authform-notoken": "缺少密鑰",
        "linkaccounts-submit": "連結帳號",
        "unlinkaccounts": "取消連結帳號",
        "unlinkaccounts-success": "已取消連結帳號。",
-       "authenticationdatachange-ignored": "èª\8d証資料變更未被處理,可能未設定提供者?",
+       "authenticationdatachange-ignored": "èª\8dè­\89資料變更未被處理,可能未設定提供者?",
        "userjsispublic": "請注意:JavaScript 子頁面可被其他使用者檢視,不應包含機密資料。",
        "usercssispublic": "請注意:CSS 子頁面可被其他使用者檢視,不應包含機密資料。",
        "restrictionsfield-badip": "無效的 IP 位址或範圍:$1",
index 478a0c4..04565f2 100644 (file)
@@ -344,7 +344,7 @@ abstract class Maintenance {
         * @return mixed
         */
        protected function getStdin( $len = null ) {
-               if ( $len == Maintenance::STDIN_ALL ) {
+               if ( $len == self::STDIN_ALL ) {
                        return file_get_contents( 'php://stdin' );
                }
                $f = fopen( 'php://stdin', 'rt' );
@@ -457,7 +457,7 @@ abstract class Maintenance {
         * @return int
         */
        public function getDbType() {
-               return Maintenance::DB_STD;
+               return self::DB_STD;
        }
 
        /**
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 117e9cc..f14856a 100644 (file)
@@ -48,7 +48,7 @@ class Sqlite {
         * @return bool True if no error or error string in case of errors
         */
        public static function checkSqlSyntax( $files ) {
-               if ( !Sqlite::isPresent() ) {
+               if ( !self::isPresent() ) {
                        throw new MWException( "Can't check SQL syntax: SQLite not found" );
                }
                if ( !is_array( $files ) ) {
index 5d773d1..01cf3c3 100644 (file)
@@ -47,7 +47,7 @@ class UserOptions {
         */
        function __construct( $opts, $args ) {
                if ( !$this->checkOpts( $opts, $args ) ) {
-                       UserOptions::showUsageAndExit();
+                       self::showUsageAndExit();
                } else {
                        $this->mReady = $this->initializeOpts( $opts, $args );
                }
index 92a218a..d2e4fcc 100644 (file)
--- a/phpcs.xml
+++ b/phpcs.xml
        <arg name="bootstrap" value="vendor/mediawiki/mediawiki-codesniffer/utils/bootstrap-ci.php"/>
        <arg name="encoding" value="UTF-8"/>
        <arg name="extensions" value="php,php5,inc,sample"/>
-       <exclude-pattern>node_modules/</exclude-pattern>
-       <exclude-pattern>vendor/</exclude-pattern>
        <exclude-pattern type="relative">^extensions/</exclude-pattern>
        <exclude-pattern type="relative">^skins/</exclude-pattern>
-       <exclude-pattern>.git</exclude-pattern>
-       <exclude-pattern>AdminSettings.php</exclude-pattern>
-       <exclude-pattern>LocalSettings.php</exclude-pattern>
-       <exclude-pattern>StartProfiler.php</exclude-pattern>
+       <exclude-pattern>AdminSettings\.php</exclude-pattern>
+       <exclude-pattern>LocalSettings\.php</exclude-pattern>
+       <exclude-pattern>StartProfiler\.php</exclude-pattern>
 </ruleset>
index 33fb8f1..f725efe 100644 (file)
@@ -1060,6 +1060,9 @@ return [
                'targets' => [ 'desktop', 'mobile' ],
        ],
        'mediawiki.hlist' => [
+               'styles' => [
+                       'resources/src/mediawiki/mediawiki.hlist-allskins.less',
+               ],
                'skinStyles' => [
                        'default' => 'resources/src/mediawiki/mediawiki.hlist.css',
                ],
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 9a85291..b6eda0f 100644 (file)
@@ -52,6 +52,7 @@
 
                this.conflicts = config.conflicts || {};
                this.defaultParams = {};
+               this.defaultFilters = {};
 
                this.aggregate( { update: 'filterItemUpdate' } );
                this.connect( this, { filterItemUpdate: 'onFilterItemUpdate' } );
@@ -89,6 +90,7 @@
                        var subsetNames = [],
                                filterItem = new mw.rcfilters.dm.FilterItem( filter.name, model, {
                                        group: model.getName(),
+                                       useDefaultAsBaseValue: !!filter.useDefaultAsBaseValue,
                                        label: filter.label || filter.name,
                                        description: filter.description || '',
                                        labelPrefixKey: model.labelPrefixKey,
                        items.push( filterItem );
 
                        // Store default parameter state; in this case, default is defined per filter
-                       if ( model.getType() === 'send_unselected_if_any' ) {
+                       if (
+                               model.getType() === 'send_unselected_if_any' ||
+                               model.getType() === 'boolean'
+                       ) {
                                // Store the default parameter state
                                // For this group type, parameter values are direct
                                // We need to convert from a boolean to a string ('1' and '0')
                        // or select the first option
                        this.selectItemByParamName( defaultParam );
                }
+
+               // Store default filter state based on default params
+               this.defaultFilters = this.getFilterRepresentation( this.getDefaultParams() );
+
+               // Check for filters that should be initially selected by their default value
+               this.getItems().forEach( function ( item ) {
+                       if (
+                               item.isUsingDefaultAsBaseValue() &&
+                               (
+                                       // This setting can only be applied to these groups
+                                       // the other groups are way too complex for that
+                                       model.getType() === 'single_option' ||
+                                       model.getType() === 'boolean'
+                               )
+                       ) {
+                               // Apply selection
+                               item.toggleSelected( !!model.defaultFilters[ item.getName() ] );
+                       }
+               } );
        };
 
        /**
         */
        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
                ) {
                return this.defaultParams;
        };
 
+       /**
+        * Get the default filter state of this group
+        *
+        * @return {Object} Default filter state
+        */
+       mw.rcfilters.dm.FilterGroup.prototype.getDefaultFilters = function () {
+               return this.defaultFilters;
+       };
+
        /**
         * This is for a single_option and string_options group types
         * it returns the value of the default
                var values,
                        areAnySelected = false,
                        buildFromCurrentState = !filterRepresentation,
+                       defaultFilters = this.getDefaultFilters(),
                        result = {},
                        model = this,
                        filterParamNames = {},
                        } else if ( !filterRepresentation[ item.getName() ] ) {
                                // We are given a filter representation, but we have to make
                                // sure that we fill in the missing filters if there are any
-                               // we will assume they are all falsey
-                               filterRepresentation[ item.getName() ] = false;
+                               // we will assume they are all falsey, unless they have
+                               // isUsingDefaultAsBaseValue, in which case they get their
+                               // default state
+                               if (
+                                       item.isUsingDefaultAsBaseValue() &&
+                                       (
+                                               // This setting can only be applied to these groups
+                                               // the other groups are way too complex for that
+                                               model.getType() === 'single_option' ||
+                                               model.getType() === 'boolean'
+                                       )
+                               ) {
+                                       filterRepresentation[ item.getName() ] = !!defaultFilters[ item.getName() ];
+                               } else {
+                                       filterRepresentation[ item.getName() ] = false;
+                               }
                        }
 
                        if ( filterRepresentation[ item.getName() ] ) {
                } );
 
                // Build result
-               if ( this.getType() === 'send_unselected_if_any' ) {
+               if (
+                       this.getType() === 'send_unselected_if_any' ||
+                       this.getType() === 'boolean'
+               ) {
                        // First, check if any of the items are selected at all.
                        // If none is selected, we're treating it as if they are
                        // all false
                        // Go over the items and define the correct values
                        $.each( filterRepresentation, function ( name, value ) {
                                // We must store all parameter values as strings '0' or '1'
-                               result[ filterParamNames[ name ] ] = areAnySelected ?
-                                       String( Number( !value ) ) :
-                                       '0';
+                               if ( model.getType() === 'send_unselected_if_any' ) {
+                                       result[ filterParamNames[ name ] ] = areAnySelected ?
+                                               String( Number( !value ) ) :
+                                               '0';
+                               } else if ( model.getType() === 'boolean' ) {
+                                       // Representation is straight-forward and direct from
+                                       // the parameter value to the filter state
+                                       result[ filterParamNames[ name ] ] = String( Number( !!value ) );
+                               }
                        } );
                } else if ( this.getType() === 'string_options' ) {
                        values = [];
         * Get the filter representation this group would provide
         * based on given parameter states.
         *
-        * @param {Object|string} [paramRepresentation] An object defining a parameter
+        * @param {Object} [paramRepresentation] An object defining a parameter
         *  state to translate the filter state from. If not given, an object
         *  representing all filters as falsey is returned; same as if the parameter
         *  given were an empty object, or had some of the filters missing.
         * @return {Object} Filter representation
         */
        mw.rcfilters.dm.FilterGroup.prototype.getFilterRepresentation = function ( paramRepresentation ) {
-               var areAnySelected, paramValues, defaultValue, item,
+               var areAnySelected, paramValues, defaultValue, item, currentValue,
                        oneWasSelected = false,
+                       defaultParams = this.getDefaultParams(),
+                       defaultFilters = this.getDefaultFilters(),
+                       expandedParams = $.extend( true, {}, paramRepresentation ),
                        model = this,
                        paramToFilterMap = {},
                        result = {};
 
-               if ( this.getType() === 'send_unselected_if_any' ) {
-                       paramRepresentation = paramRepresentation || {};
-                       // Expand param representation to include all filters in the group
+               paramRepresentation = paramRepresentation || {};
+               if (
+                       this.getType() === 'send_unselected_if_any' ||
+                       this.getType() === 'boolean'
+               ) {
+                       // Go over param representation; map and check for selections
                        this.getItems().forEach( function ( filterItem ) {
                                var paramName = filterItem.getParamName();
 
-                               paramRepresentation[ paramName ] = paramRepresentation[ paramName ] || '0';
+                               expandedParams[ paramName ] = paramRepresentation[ paramName ] || '0';
                                paramToFilterMap[ paramName ] = filterItem;
 
                                if ( Number( paramRepresentation[ filterItem.getParamName() ] ) ) {
                                }
                        } );
 
-                       $.each( paramRepresentation, function ( paramName, paramValue ) {
-                               var filterItem = paramToFilterMap[ paramName ];
-
-                               // Flip the definition between the parameter
-                               // state and the filter state
-                               // This is what the 'toggleSelected' value of the filter is
-                               result[ filterItem.getName() ] = areAnySelected ?
-                                       !Number( paramValue ) :
-                                       // Otherwise, there are no selected items in the
-                                       // group, which means the state is false
-                                       false;
+                       $.each( expandedParams, function ( paramName, paramValue ) {
+                               var value = paramValue,
+                                       filterItem = paramToFilterMap[ paramName ];
+
+                               if ( model.getType() === 'send_unselected_if_any' ) {
+                                       // Flip the definition between the parameter
+                                       // state and the filter state
+                                       // This is what the 'toggleSelected' value of the filter is
+                                       result[ filterItem.getName() ] = areAnySelected ?
+                                               !Number( paramValue ) :
+                                               // Otherwise, there are no selected items in the
+                                               // group, which means the state is false
+                                               false;
+                               } else if ( model.getType() === 'boolean' ) {
+                                       // Straight-forward definition of state
+                                       if (
+                                               filterItem.isUsingDefaultAsBaseValue() &&
+                                               paramRepresentation[ filterItem.getParamName() ] === undefined
+                                       ) {
+                                               value = defaultParams[ filterItem.getParamName() ];
+                                       }
+                                       result[ filterItem.getName() ] = !!Number( value );
+                               }
                        } );
                } else if ( this.getType() === 'string_options' ) {
-                       paramRepresentation = paramRepresentation || '';
+                       currentValue = paramRepresentation[ this.getName() ] || '';
 
                        // Normalize the given parameter values
                        paramValues = mw.rcfilters.utils.normalizeParamOptions(
                                // Given
-                               paramRepresentation.split(
+                               currentValue.split(
                                        this.getSeparator()
                                ),
                                // Allowed values
                } else if ( this.getType() === 'single_option' ) {
                        // There is parameter that fits a single filter and if not, get the default
                        this.getItems().forEach( function ( filterItem ) {
-                               result[ filterItem.getName() ] = filterItem.getParamName() === paramRepresentation;
-                               oneWasSelected = oneWasSelected || filterItem.getParamName() === paramRepresentation;
+                               var selected = false;
+
+                               if (
+                                       filterItem.isUsingDefaultAsBaseValue() &&
+                                       paramRepresentation[ model.getName() ] === undefined
+                               ) {
+                                       selected = !!Number( paramRepresentation[ model.getName() ] );
+                               } else {
+                                       selected = filterItem.getParamName() === paramRepresentation[ model.getName() ];
+                               }
+                               result[ filterItem.getName() ] = selected;
+                               oneWasSelected = oneWasSelected || selected;
                        } );
                }
 
                // Go over result and make sure all filters are represented.
                // If any filters are missing, they will get a falsey value
                this.getItems().forEach( function ( filterItem ) {
-                       result[ filterItem.getName() ] = !!result[ filterItem.getName() ];
+                       if (
+                               (
+                                       // This setting can only be applied to these groups
+                                       // the other groups are way too complex for that
+                                       model.getType() === 'single_option' ||
+                                       model.getType() === 'boolean'
+                               ) &&
+                               result[ filterItem.getName() ] === undefined &&
+                               filterItem.isUsingDefaultAsBaseValue()
+                       ) {
+                               result[ filterItem.getName() ] = !!defaultFilters[ filterItem.getName() ];
+                       }
                        oneWasSelected = oneWasSelected || !!result[ filterItem.getName() ];
                } );
 
index 06fa0aa..a602c32 100644 (file)
 
                // Create a map between known parameters and their models
                $.each( this.groups, function ( group, groupModel ) {
-                       if ( groupModel.getType() === 'send_unselected_if_any' ) {
+                       if (
+                               groupModel.getType() === 'send_unselected_if_any' ||
+                               groupModel.getType() === 'boolean'
+                       ) {
                                // Individual filters
                                groupModel.getItems().forEach( function ( filterItem ) {
                                        model.parameterMap[ filterItem.getParamName() ] = filterItem;
                //    group2: "param4|param5"
                // }
                $.each( params, function ( paramName, paramValue ) {
-                       var itemOrGroup = model.parameterMap[ paramName ];
-
-                       if ( itemOrGroup instanceof mw.rcfilters.dm.FilterItem ) {
-                               groupMap[ itemOrGroup.getGroupName() ] = groupMap[ itemOrGroup.getGroupName() ] || {};
-                               groupMap[ itemOrGroup.getGroupName() ][ itemOrGroup.getParamName() ] = paramValue;
-                       } else if ( itemOrGroup instanceof mw.rcfilters.dm.FilterGroup ) {
-                               // This parameter represents a group (values are the filters)
-                               // this is equivalent to checking if the group is 'string_options'
-                               groupMap[ itemOrGroup.getName() ] = groupMap[ itemOrGroup.getName() ] || {};
-                               groupMap[ itemOrGroup.getName() ] = paramValue;
+                       var groupName,
+                               itemOrGroup = model.parameterMap[ paramName ];
+
+                       if ( itemOrGroup ) {
+                               groupName = itemOrGroup instanceof mw.rcfilters.dm.FilterItem ?
+                                       itemOrGroup.getGroupName() : itemOrGroup.getName();
+
+                               groupMap[ groupName ] = groupMap[ groupName ] || {};
+                               groupMap[ groupName ][ paramName ] = paramValue;
                        }
                } );
 
                // 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 aa82e21..54a4dbe 100644 (file)
@@ -32,6 +32,7 @@
                this.namePrefix = config.namePrefix || 'item_';
                this.name = this.namePrefix + param;
 
+               this.useDefaultAsBaseValue = !!config.useDefaultAsBaseValue;
                this.label = config.label || this.name;
                this.labelPrefixKey = config.labelPrefixKey;
                this.description = config.description || '';
                return this.identifiers;
        };
 
+       /**
+        * Check whether the item uses its default state as a base value
+        *
+        * @return {boolean} Use default as base value
+        */
+       mw.rcfilters.dm.ItemModel.prototype.isUsingDefaultAsBaseValue = function () {
+               return this.useDefaultAsBaseValue;
+       };
+
        /**
         * Toggle the highlight feature on and off for this filter.
         * It only works if highlight is supported for this filter.
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 6512f04..0e9e843 100644 (file)
                        this.$element.append( $message );
                } else {
                        this.$changesListContent = $changesListContent;
-                       this.$element.empty().append( this.$changesListContent );
+                       if ( !isInitialDOM ) {
+                               this.$element.empty().append( this.$changesListContent );
+                       }
                        // Set up highlight containers
                        this.setupHighlightContainers( this.$element );
 
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 );
diff --git a/resources/src/mediawiki/mediawiki.hlist-allskins.less b/resources/src/mediawiki/mediawiki.hlist-allskins.less
new file mode 100644 (file)
index 0000000..d7071e4
--- /dev/null
@@ -0,0 +1,21 @@
+.hlist {
+       dl,
+       ol,
+       ul {
+               margin: 0;
+               padding: 0;
+
+               dl,
+               ol,
+               ul {
+                       display: inline;
+               }
+       }
+
+       dd,
+       dt,
+       li {
+               margin: 0;
+               display: inline;
+       }
+}
index c0788a4..2663d87 100644 (file)
@@ -2,31 +2,6 @@
  * Stylesheet for mediawiki.hlist module
  * @author [[User:Edokter]]
  */
-.hlist dl,
-.hlist ol,
-.hlist ul {
-       margin: 0;
-       padding: 0;
-}
-/* Display list items inline */
-.hlist dd,
-.hlist dt,
-.hlist li {
-       margin: 0;
-       display: inline;
-}
-/* Display nested lists inline */
-.hlist dl dl,
-.hlist dl ol,
-.hlist dl ul,
-.hlist ol dl,
-.hlist ol ol,
-.hlist ol ul,
-.hlist ul dl,
-.hlist ul ol,
-.hlist ul ul {
-       display: inline;
-}
 /* Generate interpuncts */
 .hlist dt:after {
        content: ':';
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 9255733..8615edc 100644 (file)
@@ -168,7 +168,7 @@ class ParserTestRunner {
                global $wgParserTestFiles;
 
                // Add core test files
-               $files = array_map( function( $item ) {
+               $files = array_map( function ( $item ) {
                        return __DIR__ . "/$item";
                }, self::$coreTestFiles );
 
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 76a4f51..802f9b1 100644 (file)
@@ -39,7 +39,7 @@ class DeprecatedGlobalTest extends MediaWikiTestCase {
                global $wgDummyLazy;
 
                $called = false;
-               $factory = function() use ( &$called ) {
+               $factory = function () use ( &$called ) {
                        $called = true;
                        return new HashBagOStuff();
                };
index 89416f2..ae858f5 100644 (file)
@@ -23,7 +23,7 @@ class GitInfoTest extends MediaWikiTestCase {
        public function testValidJsonData() {
                global $IP;
 
-               $this->assertValidGitInfo( new GitInfo( "$IP/testValidJsonData") );
+               $this->assertValidGitInfo( new GitInfo( "$IP/testValidJsonData" ) );
                $this->assertValidGitInfo( new GitInfo( __DIR__ . "/../data/gitinfo/extension" ) );
        }
 
index ada516d..d78c1e7 100644 (file)
@@ -131,10 +131,9 @@ class PreferencesTest extends MediaWikiTestCase {
                        ->method( 'getConfig' )
                        ->willReturn( $configMock );
 
-               $this->setTemporaryHook( 'PreferencesFormPreSave', function(
+               $this->setTemporaryHook( 'PreferencesFormPreSave', function (
                        $formData, $form, $user, &$result, $oldUserOptions )
                        use ( $newOptions, $oldOptions, $userMock ) {
-
                        $this->assertSame( $userMock, $user );
                        foreach ( $newOptions as $option => $value ) {
                                $this->assertSame( $value, $formData[ $option ] );
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' => [
index ba38128..608d8d9 100644 (file)
@@ -47,7 +47,7 @@ class ConfigFactoryTest extends MediaWikiTestCase {
        }
 
        /**
-        * @covers ConfigFactory::register
+        * @covers ConfigFactory::salvage
         */
        public function testSalvage() {
                $oldFactory = new ConfigFactory();
@@ -83,7 +83,7 @@ class ConfigFactoryTest extends MediaWikiTestCase {
        }
 
        /**
-        * @covers ConfigFactory::register
+        * @covers ConfigFactory::getConfigNames
         */
        public function testGetConfigNames() {
                $factory = new ConfigFactory();
@@ -96,7 +96,7 @@ class ConfigFactoryTest extends MediaWikiTestCase {
        /**
         * @covers ConfigFactory::makeConfig
         */
-       public function testMakeConfig() {
+       public function testMakeConfigWithCallback() {
                $factory = new ConfigFactory();
                $factory->register( 'unittest', 'GlobalVarConfig::newInstance' );
 
@@ -105,6 +105,16 @@ class ConfigFactoryTest extends MediaWikiTestCase {
                $this->assertSame( $conf, $factory->makeConfig( 'unittest' ) );
        }
 
+       /**
+        * @covers ConfigFactory::makeConfig
+        */
+       public function testMakeConfigWithObject() {
+               $factory = new ConfigFactory();
+               $conf = new HashConfig();
+               $factory->register( 'test', $conf );
+               $this->assertSame( $conf, $factory->makeConfig( 'test' ) );
+       }
+
        /**
         * @covers ConfigFactory::makeConfig
         */
index 763bfa8..19cffa2 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use Wikimedia\TestingAccessWrapper;
+
 class EtcConfigTest extends PHPUnit_Framework_TestCase {
 
        private function createConfigMock( array $options = [] ) {
@@ -359,4 +361,155 @@ class EtcConfigTest extends PHPUnit_Framework_TestCase {
 
                $this->assertSame( 'from-cache-expired', $mock->get( 'known' ) );
        }
+
+       public static function provideFetchFromServer() {
+               return [
+                       '200 OK - Success' => [
+                               'http' => [
+                                       'code' => 200,
+                                       'reason' => 'OK',
+                                       'headers' => [],
+                                       'body' => json_encode( [ 'node' => [ 'nodes' => [
+                                               [
+                                                       'key' => '/example/foo',
+                                                       'value' => json_encode( [ 'val' => true ] )
+                                               ],
+                                       ] ] ] ),
+                                       'error' => '',
+                               ],
+                               'expect' => [
+                                       [ 'foo' => true ], // data
+                                       null,
+                                       false // retry
+                               ],
+                       ],
+                       '200 OK - Skip dir' => [
+                               'http' => [
+                                       'code' => 200,
+                                       'reason' => 'OK',
+                                       'headers' => [],
+                                       'body' => json_encode( [ 'node' => [ 'nodes' => [
+                                               [
+                                                       'key' => '/example/foo',
+                                                       'value' => json_encode( [ 'val' => true ] )
+                                               ],
+                                               [
+                                                       'key' => '/example/sub',
+                                                       'dir' => true
+                                               ],
+                                               [
+                                                       'key' => '/example/bar',
+                                                       'value' => json_encode( [ 'val' => false ] )
+                                               ],
+                                       ] ] ] ),
+                                       'error' => '',
+                               ],
+                               'expect' => [
+                                       [ 'foo' => true, 'bar' => false ], // data
+                                       null,
+                                       false // retry
+                               ],
+                       ],
+                       '200 OK - Bad value' => [
+                               'http' => [
+                                       'code' => 200,
+                                       'reason' => 'OK',
+                                       'headers' => [],
+                                       'body' => json_encode( [ 'node' => [ 'nodes' => [
+                                               [
+                                                       'key' => '/example/foo',
+                                                       'value' => ';"broken{value'
+                                               ]
+                                       ] ] ] ),
+                                       'error' => '',
+                               ],
+                               'expect' => [
+                                       null, // data
+                                       "Failed to parse value for 'foo'.",
+                                       false // retry
+                               ],
+                       ],
+                       '200 OK - Empty node list' => [
+                               'http' => [
+                                       'code' => 200,
+                                       'reason' => 'OK',
+                                       'headers' => [],
+                                       'body' => '{"node":{"nodes":[]}}',
+                                       'error' => '',
+                               ],
+                               'expect' => [
+                                       [], // data
+                                       null,
+                                       false // retry
+                               ],
+                       ],
+                       '200 OK - Invalid JSON' => [
+                               'http' => [
+                                       'code' => 200,
+                                       'reason' => 'OK',
+                                       'headers' => [ 'content-length' => 0 ],
+                                       'body' => '',
+                                       'error' => '(curl error: no status set)',
+                               ],
+                               'expect' => [
+                                       null, // data
+                                       "Unexpected JSON response; missing 'nodes' list.",
+                                       false // retry
+                               ],
+                       ],
+                       '404 Not Found' => [
+                               'http' => [
+                                       'code' => 404,
+                                       'reason' => 'Not Found',
+                                       'headers' => [ 'content-length' => 0 ],
+                                       'body' => '',
+                                       'error' => '',
+                               ],
+                               'expect' => [
+                                       null, // data
+                                       'HTTP 404 (Not Found)',
+                                       false // retry
+                               ],
+                       ],
+                       '400 Bad Request - custom error' => [
+                               'http' => [
+                                       'code' => 400,
+                                       'reason' => 'Bad Request',
+                                       'headers' => [ 'content-length' => 0 ],
+                                       'body' => '',
+                                       'error' => 'No good reason',
+                               ],
+                               'expect' => [
+                                       null, // data
+                                       'No good reason',
+                                       true // retry
+                               ],
+                       ],
+               ];
+       }
+
+       /**
+        * @covers EtcdConfig::fetchAllFromEtcdServer
+        * @covers EtcdConfig::unserialize
+        * @dataProvider provideFetchFromServer
+        */
+       public function testFetchFromServer( array $httpResponse, array $expected ) {
+               $http = $this->getMockBuilder( MultiHttpClient::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $http->expects( $this->once() )->method( 'run' )
+                       ->willReturn( array_values( $httpResponse ) );
+
+               $conf = $this->getMockBuilder( EtcdConfig::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               // Access for protected member and method
+               $conf = TestingAccessWrapper::newFromObject( $conf );
+               $conf->http = $http;
+
+               $this->assertSame(
+                       $expected,
+                       $conf->fetchAllFromEtcdServer( 'etcd-tcp.example.net' )
+               );
+       }
 }
index b9ce997..d0996e3 100644 (file)
@@ -103,16 +103,16 @@ more stuff
 
        public static function dataGetSection() {
                return [
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "0",
                                "Intro"
                        ],
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "2",
                                "== test ==
 just a test"
                        ],
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "8",
                                false
                        ],
@@ -138,38 +138,38 @@ just a test"
 
        public static function dataReplaceSection() {
                return [
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "0",
                                "No more",
                                null,
-                               trim( preg_replace( '/^Intro/sm', 'No more', WikitextContentTest::$sections ) )
+                               trim( preg_replace( '/^Intro/sm', 'No more', self::$sections ) )
                        ],
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "",
                                "No more",
                                null,
                                "No more"
                        ],
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "2",
                                "== TEST ==\nmore fun",
                                null,
                                trim( preg_replace(
                                        '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==",
-                                       WikitextContentTest::$sections
+                                       self::$sections
                                ) )
                        ],
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "8",
                                "No more",
                                null,
-                               WikitextContentTest::$sections
+                               self::$sections
                        ],
-                       [ WikitextContentTest::$sections,
+                       [ self::$sections,
                                "new",
                                "No more",
                                "New",
-                               trim( WikitextContentTest::$sections ) . "\n\n\n== New ==\n\nNo more"
+                               trim( self::$sections ) . "\n\n\n== New ==\n\nNo more"
                        ],
                ];
        }
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() );
-       }
-}
index d0121b1..1a15c26 100644 (file)
@@ -5,6 +5,10 @@
  * @author Timo Tijhof
  */
 
+/**
+ * @group ResourceLoader
+ * @group CSSMin
+ */
 class CSSMinTest extends MediaWikiTestCase {
 
        protected function setUp() {
@@ -233,6 +237,11 @@ class CSSMinTest extends MediaWikiTestCase {
                                [ 'foo { prop: url(/w/skin/images/bar.png); }', false, 'http://example.org/quux', false ],
                                'foo { prop: url(http://doc.example.org/w/skin/images/bar.png); }',
                        ],
+                       [
+                               "Don't barf at behavior: url(#default#behaviorName) - T162973",
+                               [ 'foo { behavior: url(#default#bar); }', false, '/w/', false ],
+                               'foo { behavior: url("#default#bar"); }',
+                       ],
                ];
        }
 
index 775709f..4a9f6cc 100644 (file)
@@ -81,22 +81,26 @@ class MultiWriteBagOStuffTest extends MediaWikiTestCase {
         */
        public function testSetDelayed() {
                $key = wfRandomString();
-               $value = wfRandomString();
+               $value = (object)[ 'v' => wfRandomString() ];
+               $expectValue = clone $value;
 
                // XXX: DeferredUpdates bound to transactions in CLI mode
                $dbw = wfGetDB( DB_MASTER );
                $dbw->begin();
                $this->cache->set( $key, $value );
 
+               // Test that later changes to $value don't affect the saved value (e.g. T168040)
+               $value->v = 'bogus';
+
                // Set in tier 1
-               $this->assertEquals( $value, $this->cache1->get( $key ), 'Written to tier 1' );
+               $this->assertEquals( $expectValue, $this->cache1->get( $key ), 'Written to tier 1' );
                // Not yet set in tier 2
                $this->assertEquals( false, $this->cache2->get( $key ), 'Not written to tier 2' );
 
                $dbw->commit();
 
                // Set in tier 2
-               $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
+               $this->assertEquals( $expectValue, $this->cache2->get( $key ), 'Written to tier 2' );
        }
 
        /**
index 3dc7e28..a8dbdd3 100644 (file)
@@ -8,16 +8,20 @@ use Wikimedia\Rdbms\DatabaseDomain;
 class DatabaseDomainTest extends PHPUnit_Framework_TestCase {
        public static function provideConstruct() {
                return [
-                       // All strings
-                       [ 'foo', 'bar', 'baz', 'foo-bar-baz' ],
-                       // Nothing
-                       [ null, null, '', '' ],
-                       // Invalid $database
-                       [ 0, 'bar', '', '', true ],
-                       // - in one of the fields
-                       [ 'foo-bar', 'baz', 'baa', 'foo?hbar-baz-baa' ],
-                       // ? in one of the fields
-                       [ 'foo?bar', 'baz', 'baa', 'foo??bar-baz-baa' ],
+                       'All strings' =>
+                               [ 'foo', 'bar', 'baz', 'foo-bar-baz' ],
+                       'Nothing' =>
+                               [ null, null, '', '' ],
+                       'Invalid $database' =>
+                               [ 0, 'bar', '', '', true ],
+                       'Invalid $schema' =>
+                               [ 'foo', 0, '', '', true ],
+                       'Invalid $prefix' =>
+                               [ 'foo', 'bar', 0, '', true ],
+                       'Dash' =>
+                               [ 'foo-bar', 'baz', 'baa', 'foo?hbar-baz-baa' ],
+                       'Question mark' =>
+                               [ 'foo?bar', 'baz', 'baa', 'foo??bar-baz-baa' ],
                ];
        }
 
@@ -27,6 +31,8 @@ class DatabaseDomainTest extends PHPUnit_Framework_TestCase {
        public function testConstruct( $db, $schema, $prefix, $id, $exception = false ) {
                if ( $exception ) {
                        $this->setExpectedException( InvalidArgumentException::class );
+                       new DatabaseDomain( $db, $schema, $prefix );
+                       return;
                }
 
                $domain = new DatabaseDomain( $db, $schema, $prefix );
@@ -35,23 +41,27 @@ class DatabaseDomainTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals( $schema, $domain->getSchema() );
                $this->assertEquals( $prefix, $domain->getTablePrefix() );
                $this->assertEquals( $id, $domain->getId() );
+               $this->assertEquals( $id, strval( $domain ), 'toString' );
        }
 
        public static function provideNewFromId() {
                return [
-                       // basic
-                       [ 'foo', 'foo', null, '' ],
-                       // <database>-<prefix>
-                       [ 'foo-bar', 'foo', null, 'bar' ],
-                       [ 'foo-bar-baz', 'foo', 'bar', 'baz' ],
-                       // ?h -> -
-                       [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa' ],
-                       // ?? -> ?
-                       [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
-                       // ? is left alone
-                       [ 'foo?bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
-                       // too many parts
-                       [ 'foo-bar-baz-baa', '', '', '', true ],
+                       'Basic' =>
+                               [ 'foo', 'foo', null, '' ],
+                       'db+prefix' =>
+                               [ 'foo-bar', 'foo', null, 'bar' ],
+                       'db+schema+prefix' =>
+                               [ 'foo-bar-baz', 'foo', 'bar', 'baz' ],
+                       '?h -> -' =>
+                               [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa' ],
+                       '?? -> ?' =>
+                               [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
+                       '? is left alone' =>
+                               [ 'foo?bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
+                       'too many parts' =>
+                               [ 'foo-bar-baz-baa', '', '', '', true ],
+                       'from instance' =>
+                               [ DatabaseDomain::newUnspecified(), null, null, '' ],
                ];
        }
 
@@ -61,6 +71,8 @@ class DatabaseDomainTest extends PHPUnit_Framework_TestCase {
        public function testNewFromId( $id, $db, $schema, $prefix, $exception = false ) {
                if ( $exception ) {
                        $this->setExpectedException( InvalidArgumentException::class );
+                       DatabaseDomain::newFromId( $id );
+                       return;
                }
                $domain = DatabaseDomain::newFromId( $id );
                $this->assertInstanceOf( DatabaseDomain::class, $domain );
@@ -68,4 +80,50 @@ class DatabaseDomainTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals( $schema, $domain->getSchema() );
                $this->assertEquals( $prefix, $domain->getTablePrefix() );
        }
+
+       public static function provideEquals() {
+               return [
+                       'Basic' =>
+                               [ 'foo', 'foo', null, '' ],
+                       'db+prefix' =>
+                               [ 'foo-bar', 'foo', null, 'bar' ],
+                       'db+schema+prefix' =>
+                               [ 'foo-bar-baz', 'foo', 'bar', 'baz' ],
+                       '?h -> -' =>
+                               [ 'foo?hbar-baz-baa', 'foo-bar', 'baz', 'baa' ],
+                       '?? -> ?' =>
+                               [ 'foo??bar-baz-baa', 'foo?bar', 'baz', 'baa' ],
+                       'Nothing' =>
+                               [ '', null, null, '' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideEquals
+        * @covers Wikimedia\Rdbms\DatabaseDomain::equals
+        */
+       public function testEquals( $id, $db, $schema, $prefix ) {
+               $fromId = DatabaseDomain::newFromId( $id );
+               $this->assertInstanceOf( DatabaseDomain::class, $fromId );
+
+               $constructed = new DatabaseDomain( $db, $schema, $prefix );
+
+               $this->assertTrue( $constructed->equals( $id ), 'constructed equals string' );
+               $this->assertTrue( $fromId->equals( $id ), 'fromId equals string' );
+
+               $this->assertTrue( $constructed->equals( $fromId ), 'compare constructed to newId' );
+               $this->assertTrue( $fromId->equals( $constructed ), 'compare newId to constructed' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\DatabaseDomain::newUnspecified
+        */
+       public function testNewUnspecified() {
+               $domain = DatabaseDomain::newUnspecified();
+               $this->assertInstanceOf( DatabaseDomain::class, $domain );
+               $this->assertTrue( $domain->equals( '' ) );
+               $this->assertSame( null, $domain->getDatabase() );
+               $this->assertSame( null, $domain->getSchema() );
+               $this->assertSame( '', $domain->getTablePrefix() );
+       }
 }
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..f519772
--- /dev/null
@@ -0,0 +1,1131 @@
+<?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, DatabaseTestHelper $db ) {
+               $this->assertEquals( $sqlText, $db->getLastSqls() );
+       }
+
+       /**
+        * @dataProvider provideSelect
+        * @covers Wikimedia\Rdbms\Database::select
+        * @covers Wikimedia\Rdbms\Database::selectSQLText
+        * @covers Wikimedia\Rdbms\Database::tableNamesWithIndexClauseOrJOIN
+        * @covers Wikimedia\Rdbms\Database::makeSelectOptions
+        * @covers Wikimedia\Rdbms\Database::makeOrderBy
+        * @covers Wikimedia\Rdbms\Database::makeGroupByWithHaving
+        */
+       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' with space prepended indicates pre-escaped table name
+                                       'tables' => ' table LEFT JOIN table2',
+                                       'fields' => [ 'field' ],
+                                       'conds' => [ 'field' => 'text' ],
+                               ],
+                               "SELECT field FROM  table LEFT JOIN table2 WHERE field = 'text'"
+                       ],
+                       [
+                               [
+                                       // Empty 'tables' is allowed
+                                       'tables' => '',
+                                       'fields' => [ 'SPECIAL_QUERY()' ],
+                               ],
+                               "SELECT SPECIAL_QUERY()"
+                       ],
+                       [
+                               [
+                                       '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')"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'fields' => [ 'field' ],
+                                       'options' => [ 'DISTINCT', 'LOCK IN SHARE MODE' ],
+                               ],
+                               "SELECT DISTINCT field FROM table      LOCK IN SHARE MODE"
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'fields' => [ 'field' ],
+                                       'options' => [ 'EXPLAIN' => true ],
+                               ],
+                               'EXPLAIN SELECT field FROM table'
+                       ],
+                       [
+                               [
+                                       'tables' => 'table',
+                                       'fields' => [ 'field' ],
+                                       'options' => [ 'FOR UPDATE' ],
+                               ],
+                               "SELECT field FROM table      FOR UPDATE"
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideUpdate
+        * @covers Wikimedia\Rdbms\Database::update
+        * @covers Wikimedia\Rdbms\Database::makeUpdateOptions
+        * @covers Wikimedia\Rdbms\Database::makeUpdateOptionsArray
+        */
+       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
+        * @covers Wikimedia\Rdbms\Database::makeInsertOptions
+        */
+       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
+        * @covers Wikimedia\Rdbms\Database::nativeInsertSelect
+        */
+       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
+        * @covers Wikimedia\Rdbms\Database::escapeLikeInternal
+        */
+       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
+        * @covers Wikimedia\Rdbms\Database::doCommit
+        */
+       public function testTransactionCommit() {
+               $this->database->begin( __METHOD__ );
+               $this->database->commit( __METHOD__ );
+               $this->assertLastSql( 'BEGIN; COMMIT' );
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::rollback
+        * @covers Wikimedia\Rdbms\Database::doRollback
+        */
+       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'"
+                       ],
+               ];
+       }
+
+       /**
+        * @covers Wikimedia\Rdbms\Database::registerTempTableOperation
+        */
+       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 556a348..3079d8f 100644 (file)
@@ -625,15 +625,15 @@ more stuff
                return [
                        [ 'Help:WikiPageTest_testReplaceSection',
                                CONTENT_MODEL_WIKITEXT,
-                               WikiPageTest::$sections,
+                               self::$sections,
                                "0",
                                "No more",
                                null,
-                               trim( preg_replace( '/^Intro/sm', 'No more', WikiPageTest::$sections ) )
+                               trim( preg_replace( '/^Intro/sm', 'No more', self::$sections ) )
                        ],
                        [ 'Help:WikiPageTest_testReplaceSection',
                                CONTENT_MODEL_WIKITEXT,
-                               WikiPageTest::$sections,
+                               self::$sections,
                                "",
                                "No more",
                                null,
@@ -641,29 +641,29 @@ more stuff
                        ],
                        [ 'Help:WikiPageTest_testReplaceSection',
                                CONTENT_MODEL_WIKITEXT,
-                               WikiPageTest::$sections,
+                               self::$sections,
                                "2",
                                "== TEST ==\nmore fun",
                                null,
                                trim( preg_replace( '/^== test ==.*== foo ==/sm',
                                        "== TEST ==\nmore fun\n\n== foo ==",
-                                       WikiPageTest::$sections ) )
+                                       self::$sections ) )
                        ],
                        [ 'Help:WikiPageTest_testReplaceSection',
                                CONTENT_MODEL_WIKITEXT,
-                               WikiPageTest::$sections,
+                               self::$sections,
                                "8",
                                "No more",
                                null,
-                               trim( WikiPageTest::$sections )
+                               trim( self::$sections )
                        ],
                        [ 'Help:WikiPageTest_testReplaceSection',
                                CONTENT_MODEL_WIKITEXT,
-                               WikiPageTest::$sections,
+                               self::$sections,
                                "new",
                                "No more",
                                "New",
-                               trim( WikiPageTest::$sections ) . "\n\n== New ==\n\nNo more"
+                               trim( self::$sections ) . "\n\n== New ==\n\nNo more"
                        ],
                ];
        }
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
                ];
        }
index 6597906..39c3421 100644 (file)
@@ -109,6 +109,6 @@ class TestSites {
        public static function insertIntoDb() {
                $sitesTable = \MediaWiki\MediaWikiServices::getInstance()->getSiteStore();
                $sitesTable->clear();
-               $sitesTable->saveSites( TestSites::getSites() );
+               $sitesTable->saveSites( self::getSites() );
        }
 }
index 85becff..a9a612d 100644 (file)
@@ -27,6 +27,8 @@ class SpecialRecentchangesTest extends AbstractChangesListSpecialPageTestCase {
 
                        [ 'days=3', [ 'days' => '3' ] ],
 
+                       [ 'days=0.25', [ 'days' => '0.25'] ],
+
                        [ 'namespace=5', [ 'namespace' => '5' ] ],
 
                        [ 'namespace=5|3', [ 'namespace' => '5|3' ] ],
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 2f19c81..251a4a2 100644 (file)
@@ -68,7 +68,6 @@
                        <directory suffix=".php">../../includes</directory>
                        <directory suffix=".php">../../languages</directory>
                        <directory suffix=".php">../../maintenance</directory>
-                       <directory suffix=".php">../../skins</directory>
                </whitelist>
        </filter>
 </phpunit>
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 ) );
index edaef79..da7bafd 100644 (file)
                                { name: 'option2', label: 'group5option2-label', description: 'group5option2-desc' },
                                { name: 'option3', label: 'group5option3-label', description: 'group5option3-desc' }
                        ]
+               }, {
+                       name: 'group6',
+                       type: 'boolean',
+                       filters: [
+                               { name: 'group6option1', label: 'group6option1-label', description: 'group5option1-desc' },
+                               { name: 'group6option2', label: 'group6option2-label', description: 'group5option2-desc', default: true, useDefaultAsBaseValue: true },
+                               { name: 'group6option3', label: 'group6option3-label', description: 'group5option3-desc', default: true }
+                       ]
                } ],
                viewsDefinition = {
                        namespaces: {
                        group3: 'filter8',
                        group4: 'option2',
                        group5: 'option1',
+                       group6option1: '0',
+                       group6option2: '1',
+                       group6option3: '1',
                        namespace: ''
                },
                baseParamRepresentation = {
                        group3: '',
                        group4: 'option2',
                        group5: 'option1',
+                       group6option1: '0',
+                       group6option2: '1',
+                       group6option3: '0',
                        namespace: ''
                },
                baseFilterRepresentation = {
                        group5__option1: true, // No default set, first item is default value
                        group5__option2: false,
                        group5__option3: false,
+                       group6__group6option1: false,
+                       group6__group6option2: true,
+                       group6__group6option3: false,
                        namespace__0: false,
                        namespace__1: false,
                        namespace__2: false,
                        group5__option1: { selected: true, conflicted: false, included: false },
                        group5__option2: { selected: false, conflicted: false, included: false },
                        group5__option3: { selected: false, conflicted: false, included: false },
+                       group6__group6option1: { selected: false, conflicted: false, included: false },
+                       group6__group6option2: { selected: true, conflicted: false, included: false },
+                       group6__group6option3: { selected: false, conflicted: false, included: false },
                        namespace__0: { selected: false, conflicted: false, included: false },
                        namespace__1: { selected: false, conflicted: false, included: false },
                        namespace__2: { selected: false, conflicted: false, included: false },