Merge "Hygiene: Add wrapHTML method"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 8 Mar 2016 21:13:17 +0000 (21:13 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 8 Mar 2016 21:13:17 +0000 (21:13 +0000)
137 files changed:
RELEASE-NOTES-1.27
docs/hooks.txt
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/MovePage.php
includes/OutputPage.php
includes/Title.php
includes/WatchedItem.php
includes/WatchedItemStore.php
includes/WebResponse.php
includes/actions/HistoryAction.php
includes/actions/RollbackAction.php
includes/actions/WatchAction.php
includes/api/ApiBase.php
includes/api/ApiContinuationManager.php
includes/api/ApiEditPage.php
includes/api/ApiExpandTemplates.php
includes/api/ApiFeedContributions.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatXml.php
includes/api/ApiHelp.php
includes/api/ApiImageRotate.php
includes/api/ApiImport.php
includes/api/ApiLogin.php
includes/api/ApiMain.php
includes/api/ApiOpenSearch.php
includes/api/ApiOptions.php
includes/api/ApiPageSet.php
includes/api/ApiParamInfo.php
includes/api/ApiParse.php
includes/api/ApiQuery.php
includes/api/ApiQueryAllLinks.php
includes/api/ApiQueryBacklinks.php
includes/api/ApiQueryBacklinksprop.php
includes/api/ApiQueryFileRepoInfo.php
includes/api/ApiQueryImageInfo.php
includes/api/ApiQueryRevisionsBase.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiQueryStashImageInfo.php
includes/api/ApiResult.php
includes/api/ApiStashEdit.php
includes/api/ApiTokens.php
includes/api/ApiUpload.php
includes/api/ApiWatch.php
includes/api/i18n/gl.json
includes/api/i18n/it.json
includes/api/i18n/ja.json
includes/api/i18n/lt.json
includes/api/i18n/nap.json
includes/api/i18n/pt.json
includes/changes/ChangesList.php
includes/content/JsonContent.php
includes/context/RequestContext.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabaseOracle.php
includes/db/DatabaseUtility.php
includes/db/IDatabase.php
includes/db/loadbalancer/LoadMonitor.php
includes/filebackend/FileBackendMultiWrite.php
includes/filerepo/FileRepo.php
includes/filerepo/ForeignAPIRepo.php
includes/installer/MysqlUpdater.php
includes/installer/i18n/ar.json
includes/installer/i18n/en.json
includes/installer/i18n/lt.json
includes/installer/i18n/nap.json
includes/jobqueue/JobQueueDB.php
includes/jobqueue/JobQueueFederated.php
includes/mail/EmailNotification.php
includes/parser/Parser.php
includes/search/SearchMssql.php
includes/session/BotPasswordSessionProvider.php
includes/session/Session.php
includes/session/SessionManager.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialBlock.php
includes/specials/SpecialImport.php
includes/specials/SpecialUserlogin.php
includes/upload/UploadBase.php
includes/upload/UploadFromChunks.php
includes/user/User.php
includes/utils/MWRestrictions.php
languages/classes/LanguageCu.php
languages/classes/LanguageHy.php
languages/classes/LanguageUk.php
languages/i18n/ar.json
languages/i18n/arq.json
languages/i18n/be-tarask.json
languages/i18n/bgn.json
languages/i18n/bn.json
languages/i18n/de.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/fa.json
languages/i18n/fo.json
languages/i18n/fr.json
languages/i18n/frp.json
languages/i18n/gom-deva.json
languages/i18n/gom-latn.json
languages/i18n/he.json
languages/i18n/id.json
languages/i18n/inh.json
languages/i18n/it.json
languages/i18n/la.json
languages/i18n/lt.json
languages/i18n/lv.json
languages/i18n/mg.json
languages/i18n/my.json
languages/i18n/nap.json
languages/i18n/pl.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/sl.json
languages/i18n/sv.json
languages/i18n/ta.json
languages/i18n/tr.json
languages/i18n/uk.json
load.php
maintenance/benchmarks/Benchmarker.php
maintenance/getConfiguration.php
maintenance/initSiteStats.php
resources/src/mediawiki.special/mediawiki.special.preferences.js
tests/phpunit/includes/WatchedItemIntegrationTest.php [new file with mode: 0644]
tests/phpunit/includes/WatchedItemStoreIntegrationTest.php [new file with mode: 0644]
tests/phpunit/includes/WatchedItemStoreTest.php [deleted file]
tests/phpunit/includes/WatchedItemStoreUnitTest.php [new file with mode: 0644]
tests/phpunit/includes/WatchedItemUnitTest.php [new file with mode: 0644]
tests/phpunit/includes/api/RandomImageGenerator.php
tests/phpunit/includes/changes/OldChangesListTest.php
tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
tests/phpunit/includes/libs/MemoizedCallableTest.php
tests/phpunit/includes/media/WebPTest.php
tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php
tests/phpunit/structure/ApiDocumentationTest.php
tests/qunit/data/generateJqueryMsgData.php

index 437f8e6..b64bf40 100644 (file)
@@ -217,7 +217,10 @@ HHVM 3.1.
   ApiQueryBase::keyPartToTitle() all removed (deprecated since 1.24).
 * ApiQueryBase::checkRowCount() was removed (deprecated since 1.24).
 * ApiQueryBase::getDirectionDescription() was removed (deprecated since 1.25).
+* ApiQuery::getGenerators() was removed (deprecated since 1.21).
 * ApiQuery::getModules() was removed (deprecated since 1.21).
+* ApiQuery::getModuleType() was removed (deprecated since 1.21).
+* ApiQuery::setGeneratorContinue() was removed (deprecated since 1.24).
 * ApiMain::getModules() was removed (deprecated since 1.21).
 * ApiBase::getVersion() was removed (deprecated since 1.21).
 
@@ -324,6 +327,18 @@ changes to languages because of Phabricator reports.
   does not support categories.
 * wikidiff difference engine is no longer supported, anyone still using it are encouraged
   to upgrade to wikidiff2 which is actively maintained and has better package availability.
+* Database logic was removed from WatchedItem and a WatchedItemStore was created:
+** WatchedItem::IGNORE_USER_RIGHTS and WatchedItem::CHECK_USER_RIGHTS were deprecated.
+   User::IGNORE_USER_RIGHTS and User::CHECK_USER_RIGHTS were introduced.
+** WatchedItem::fromUserTitle was deprecated in favour of the constructor.
+** WatchedItem::resetNotificationTimestamp was deprecated.
+** WatchedItem::batchAddWatch was deprecated.
+** WatchedItem::addWatch was deprecated.
+** WatchedItem::removeWatch was deprecated.
+** WatchedItem::isWatched was deprecated.
+** WatchedItem::duplicateEntries was deprecated.
+** EmailNotification::updateWatchlistTimestamp was deprecated.
+** User::getWatchedItem was removed.
 
 == Compatibility ==
 
index c5f2424..a431f1b 100644 (file)
@@ -178,7 +178,8 @@ once for 'TimStarling', and once for 'brion'.
 
 Hooks can return three possible values:
 
-  * true: the hook has operated successfully
+  * No return value (or null): the hook has operated successfully. Previously,
+    true was required. This is the default since MediaWiki 1.23.
   * "some string": an error occurred; processing should stop and the error
                    should be shown to the user
   * false: the hook has successfully done the work necessary and the calling
index 2a9986e..c04602c 100644 (file)
@@ -2096,7 +2096,7 @@ $wgTransactionalTimeLimit = 120;
 
 /**
  * Directory for caching data in the local filesystem. Should not be accessible
- * from the web. Set this to false to not use any local caches.
+ * from the web.
  *
  * Note: if multiple wikis share the same localisation cache directory, they
  * must all have the same set of extensions. You can set a directory just for
index 482fcc6..3268700 100644 (file)
@@ -2109,7 +2109,7 @@ class EditPage {
                $watch = $this->watchthis;
                // Do this in its own transaction to reduce contention...
                DeferredUpdates::addCallableUpdate( function () use ( $user, $title, $watch ) {
-                       if ( $watch == $user->isWatched( $title, WatchedItem::IGNORE_USER_RIGHTS ) ) {
+                       if ( $watch == $user->isWatched( $title, User::IGNORE_USER_RIGHTS ) ) {
                                return; // nothing to change
                        }
                        WatchAction::doWatchOrUnwatch( $watch, $title, $user );
index e48a399..3fa91fa 100644 (file)
@@ -1738,7 +1738,7 @@ function wfEscapeWikiText( $text ) {
                                $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' );
                        }
                }
-               $repl2 = $repl2 ? '/\b(' . join( '|', $repl2 ) . '):/i' : '/^(?!)/';
+               $repl2 = $repl2 ? '/\b(' . implode( '|', $repl2 ) . '):/i' : '/^(?!)/';
        }
        $text = substr( strtr( "\n$text", $repl ), 1 );
        $text = preg_replace( $repl2, '$1&#58;', $text );
index afa4e1c..321b7e3 100644 (file)
@@ -369,7 +369,8 @@ class MovePage {
                $oldsnamespace = MWNamespace::getSubject( $this->oldTitle->getNamespace() );
                $newsnamespace = MWNamespace::getSubject( $this->newTitle->getNamespace() );
                if ( $oldsnamespace != $newsnamespace || $oldtitle != $newtitle ) {
-                       WatchedItem::duplicateEntries( $this->oldTitle, $this->newTitle );
+                       $store = WatchedItemStore::getDefaultInstance();
+                       $store->duplicateAllAssociatedEntries( $this->oldTitle, $this->newTitle );
                }
 
                Hooks::run(
index 5d1d5d0..11c23f0 100644 (file)
@@ -2069,7 +2069,7 @@ class OutputPage extends ContextSource {
                foreach ( SessionManager::singleton()->getVaryHeaders() as $header => $options ) {
                        $this->addVaryHeader( $header, $options );
                }
-               return 'Vary: ' . join( ', ', array_keys( $this->mVaryHeader ) );
+               return 'Vary: ' . implode( ', ', array_keys( $this->mVaryHeader ) );
        }
 
        /**
@@ -2213,8 +2213,12 @@ class OutputPage extends ContextSource {
 
                if ( $this->mEnableClientCache ) {
                        if (
-                               $config->get( 'UseSquid' ) && !SessionManager::getGlobalSession()->isPersistent() &&
-                               !$this->isPrintable() && $this->mCdnMaxage != 0 && !$this->haveCacheVaryCookies()
+                               $config->get( 'UseSquid' ) &&
+                               !$response->hasCookies() &&
+                               !SessionManager::getGlobalSession()->isPersistent() &&
+                               !$this->isPrintable() &&
+                               $this->mCdnMaxage != 0 &&
+                               !$this->haveCacheVaryCookies()
                        ) {
                                if ( $config->get( 'UseESI' ) ) {
                                        # We'll purge the proxy cache explicitly, but require end user agents
index c0ec97f..0ac3e46 100644 (file)
@@ -174,7 +174,7 @@ class Title implements LinkTarget {
                // make sure we are using the right one. To detect changes over the course
                // of a request, we remember a fingerprint of the config used to create the
                // codec singleton, and re-create it if the fingerprint doesn't match.
-               $fingerprint = spl_object_hash( $wgContLang ) . '|' . join( '+', $wgLocalInterwikis );
+               $fingerprint = spl_object_hash( $wgContLang ) . '|' . implode( '+', $wgLocalInterwikis );
 
                if ( $fingerprint !== $titleCodecFingerprint ) {
                        $titleCodec = null;
@@ -4466,8 +4466,12 @@ class Title implements LinkTarget {
                        $this->mNotificationTimestamp = [];
                }
 
-               $watchedItem = WatchedItem::fromUserTitle( $user, $this );
-               $this->mNotificationTimestamp[$uid] = $watchedItem->getNotificationTimestamp();
+               $watchedItem = WatchedItemStore::getDefaultInstance()->getWatchedItem( $user, $this );
+               if ( $watchedItem ) {
+                       $this->mNotificationTimestamp[$uid] = $watchedItem->getNotificationTimestamp();
+               } else {
+                       $this->mNotificationTimestamp[$uid] = false;
+               }
 
                return $this->mNotificationTimestamp[$uid];
        }
index b597f99..f2633d9 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 /**
- * Accessor and mutator for watchlist entries.
- *
  * 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
  * @file
  * @ingroup Watchlist
  */
+use Wikimedia\Assert\Assert;
 
 /**
  * Representation of a pair of user and title for watchlist entries.
  *
+ * @author Tim Starling
+ * @author Addshore
+ *
  * @ingroup Watchlist
  */
 class WatchedItem {
-       /** @var Title */
-       private $mTitle;
-
-       /** @var User */
-       private $mUser;
-
-       /** @var int */
-       private $mCheckRights;
-
-       /** @var bool */
-       private $loaded = false;
-
-       /** @var bool */
-       private $watched;
-
-       /** @var string */
-       private $timestamp;
 
        /**
-        * Constant to specify that user rights 'editmywatchlist' and
-        * 'viewmywatchlist' should not be checked.
-        * @since 1.22
+        * @deprecated since 1.27, see User::IGNORE_USER_RIGHTS
         */
-       const IGNORE_USER_RIGHTS = 0;
+       const IGNORE_USER_RIGHTS = User::IGNORE_USER_RIGHTS;
 
        /**
-        * Constant to specify that user rights 'editmywatchlist' and
-        * 'viewmywatchlist' should be checked.
-        * @since 1.22
+        * @deprecated since 1.27, see User::CHECK_USER_RIGHTS
         */
-       const CHECK_USER_RIGHTS = 1;
+       const CHECK_USER_RIGHTS = User::CHECK_USER_RIGHTS;
 
        /**
-        * Create a WatchedItem object with the given user and title
-        * @since 1.22 $checkRights parameter added
-        * @param User $user The user to use for (un)watching
-        * @param Title $title The title we're going to (un)watch
-        * @param int $checkRights Whether to check the 'viewmywatchlist' and 'editmywatchlist' rights.
-        *     Pass either WatchedItem::IGNORE_USER_RIGHTS or WatchedItem::CHECK_USER_RIGHTS.
-        * @return WatchedItem
+        * @deprecated Internal class use only
         */
-       public static function fromUserTitle( $user, $title,
-               $checkRights = WatchedItem::CHECK_USER_RIGHTS
-       ) {
-               $wl = new WatchedItem;
-               $wl->mUser = $user;
-               $wl->mTitle = $title;
-               $wl->mCheckRights = $checkRights;
-
-               return $wl;
-       }
+       const DEPRECATED_USAGE_TIMESTAMP = -100;
 
        /**
-        * Title being watched
-        * @return Title
+        * @var bool
+        * @deprecated Internal class use only
         */
-       protected function getTitle() {
-               return $this->mTitle;
-       }
+       public $checkRights = User::CHECK_USER_RIGHTS;
 
        /**
-        * Helper to retrieve the title namespace
-        * @return int
+        * @var Title
+        * @deprecated Internal class use only
         */
-       protected function getTitleNs() {
-               return $this->getTitle()->getNamespace();
-       }
+       private $title;
 
        /**
-        * Helper to retrieve the title DBkey
-        * @return string
+        * @var LinkTarget
         */
-       protected function getTitleDBkey() {
-               return $this->getTitle()->getDBkey();
-       }
+       private $linkTarget;
 
        /**
-        * Helper to retrieve the user id
-        * @return int
+        * @var User
         */
-       protected function getUserId() {
-               return $this->mUser->getId();
-       }
+       private $user;
 
        /**
-        * Return an array of conditions to select or update the appropriate database
-        * row.
-        *
-        * @return array
+        * @var null|string the value of the wl_notificationtimestamp field
         */
-       private function dbCond() {
-               return [
-                       'wl_user' => $this->getUserId(),
-                       'wl_namespace' => $this->getTitleNs(),
-                       'wl_title' => $this->getTitleDBkey(),
-               ];
-       }
+       private $notificationTimestamp;
 
        /**
-        * Load the object from the database
+        * @param User $user
+        * @param LinkTarget $linkTarget
+        * @param null|string $notificationTimestamp the value of the wl_notificationtimestamp field
+        * @param bool|null $checkRights DO NOT USE - used internally for backward compatibility
         */
-       private function load() {
-               if ( $this->loaded ) {
-                       return;
-               }
-               $this->loaded = true;
-
-               // Only loggedin user can have a watchlist
-               if ( $this->mUser->isAnon() ) {
-                       $this->watched = false;
-                       return;
-               }
-
-               // some pages cannot be watched
-               if ( !$this->getTitle()->isWatchable() ) {
-                       $this->watched = false;
-                       return;
-               }
-
-               # Pages and their talk pages are considered equivalent for watching;
-               # remember that talk namespaces are numbered as page namespace+1.
-
-               $dbr = wfGetDB( DB_SLAVE );
-               $row = $dbr->selectRow( 'watchlist', 'wl_notificationtimestamp',
-                       $this->dbCond(), __METHOD__ );
-
-               if ( $row === false ) {
-                       $this->watched = false;
-               } else {
-                       $this->watched = true;
-                       $this->timestamp = $row->wl_notificationtimestamp;
+       public function __construct(
+               User $user,
+               LinkTarget $linkTarget,
+               $notificationTimestamp,
+               $checkRights = null
+       ) {
+               $this->user = $user;
+               $this->linkTarget = $linkTarget;
+               $this->notificationTimestamp = $notificationTimestamp;
+               if ( $checkRights !== null ) {
+                       $this->checkRights = $checkRights;
                }
        }
 
        /**
-        * Check permissions
-        * @param string $what 'viewmywatchlist' or 'editmywatchlist'
-        * @return bool
+        * @return User
         */
-       private function isAllowed( $what ) {
-               return !$this->mCheckRights || $this->mUser->isAllowed( $what );
+       public function getUser() {
+               return $this->user;
        }
 
        /**
-        * Is mTitle being watched by mUser?
-        * @return bool
+        * @return LinkTarget
         */
-       public function isWatched() {
-               if ( !$this->isAllowed( 'viewmywatchlist' ) ) {
-                       return false;
-               }
-
-               $this->load();
-               return $this->watched;
+       public function getLinkTarget() {
+               return $this->linkTarget;
        }
 
        /**
         * Get the notification timestamp of this entry.
         *
-        * @return bool|null|string False if the page is not watched, the value of
-        *   the wl_notificationtimestamp field otherwise
+        * @return bool|null|string
         */
        public function getNotificationTimestamp() {
-               if ( !$this->isAllowed( 'viewmywatchlist' ) ) {
-                       return false;
-               }
-
-               $this->load();
-               if ( $this->watched ) {
-                       return $this->timestamp;
-               } else {
-                       return false;
+               // Back compat for objects constructed using self::fromUserTitle
+               if ( $this->notificationTimestamp === self::DEPRECATED_USAGE_TIMESTAMP ) {
+                       // wfDeprecated( __METHOD__, '1.27' );
+                       if ( $this->checkRights && !$this->user->isAllowed( 'viewmywatchlist' ) ) {
+                               return false;
+                       }
+                       $item = WatchedItemStore::getDefaultInstance()
+                               ->loadWatchedItem( $this->user, $this->linkTarget );
+                       if ( $item ) {
+                               $this->notificationTimestamp = $item->getNotificationTimestamp();
+                       } else {
+                               $this->notificationTimestamp = false;
+                       }
                }
+               return $this->notificationTimestamp;
        }
 
        /**
-        * Reset the notification timestamp of this entry
-        *
-        * @param bool $force Whether to force the write query to be executed even if the
-        *    page is not watched or the notification timestamp is already NULL.
-        * @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
+        * Back compat pre 1.27 with the WatchedItemStore introduction
+        * @todo remove in 1.28/9
+        * -------------------------------------------------
         */
-       public function resetNotificationTimestamp(
-               $force = '', $oldid = 0
-       ) {
-               // Only loggedin user can have a watchlist
-               if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
-                       return;
-               }
 
-               if ( $force != 'force' ) {
-                       $this->load();
-                       if ( !$this->watched || $this->timestamp === null ) {
-                               return;
+       /**
+        * @return Title
+        * @deprecated Internal class use only
+        */
+       public function getTitle() {
+               if ( !$this->title ) {
+                       if ( $this->linkTarget instanceof Title ) {
+                               $this->title = $this->linkTarget;
+                       } else {
+                               $this->title = Title::newFromLinkTarget( $this->linkTarget );
                        }
                }
+               return $this->title;
+       }
 
-               $title = $this->getTitle();
-               if ( !$oldid ) {
-                       // No oldid given, assuming latest revision; clear the timestamp.
-                       $notificationTimestamp = null;
-               } elseif ( !$title->getNextRevisionID( $oldid ) ) {
-                       // Oldid given and is the latest revision for this title; clear the timestamp.
-                       $notificationTimestamp = null;
-               } else {
-                       // See if the version marked as read is more recent than the one we're viewing.
-                       // Call load() if it wasn't called before due to $force.
-                       $this->load();
-
-                       if ( $this->timestamp === null ) {
-                               // This can only happen if $force is enabled.
-                               $notificationTimestamp = null;
-                       } else {
-                               // Oldid given and isn't the latest; update the timestamp.
-                               // This will result in no further notification emails being sent!
-                               $notificationTimestamp = Revision::getTimestampFromId( $title, $oldid );
-                               // We need to go one second to the future because of various strict comparisons
-                               // throughout the codebase
-                               $ts = new MWTimestamp( $notificationTimestamp );
-                               $ts->timestamp->add( new DateInterval( 'PT1S' ) );
-                               $notificationTimestamp = $ts->getTimestamp( TS_MW );
+       /**
+        * @deprecated since 1.27 Use the constructor, WatchedItemStore::getWatchedItem()
+        *             or WatchedItemStore::loadWatchedItem()
+        */
+       public static function fromUserTitle( $user, $title, $checkRights = User::CHECK_USER_RIGHTS ) {
+               // wfDeprecated( __METHOD__, '1.27' );
+               return new self( $user, $title, self::DEPRECATED_USAGE_TIMESTAMP, (bool)$checkRights );
+       }
 
-                               if ( $notificationTimestamp < $this->timestamp ) {
-                                       if ( $force != 'force' ) {
-                                               return;
-                                       } else {
-                                               // This is a little silly…
-                                               $notificationTimestamp = $this->timestamp;
-                                       }
-                               }
-                       }
+       /**
+        * @deprecated since 1.27 Use WatchedItemStore::resetNotificationTimestamp()
+        */
+       public function resetNotificationTimestamp( $force = '', $oldid = 0 ) {
+               // wfDeprecated( __METHOD__, '1.27' );
+               if ( $this->checkRights && !$this->user->isAllowed( 'editmywatchlist' ) ) {
+                       return;
                }
-
-               // If the page is watched by the user (or may be watched), update the timestamp
-               $job = new ActivityUpdateJob(
-                       $title,
-                       [
-                               'type'      => 'updateWatchlistNotification',
-                               'userid'    => $this->getUserId(),
-                               'notifTime' => $notificationTimestamp,
-                               'curTime'   => time()
-                       ]
+               WatchedItemStore::getDefaultInstance()->resetNotificationTimestamp(
+                       $this->user,
+                       $this->getTitle(),
+                       $force,
+                       $oldid
                );
-               // Try to run this post-send
-               DeferredUpdates::addCallableUpdate( function() use ( $job ) {
-                       $job->run();
-               } );
-
-               $this->timestamp = null;
        }
 
        /**
-        * @param WatchedItem[] $items
-        * @return bool
+        * @deprecated since 1.27 Use WatchedItemStore::addWatchBatch()
         */
        public static function batchAddWatch( array $items ) {
-
-               if ( wfReadOnly() ) {
-                       return false;
-               }
-
-               $rows = [];
-               foreach ( $items as $item ) {
-                       // Only loggedin user can have a watchlist
-                       if ( $item->mUser->isAnon() || !$item->isAllowed( 'editmywatchlist' ) ) {
+               // wfDeprecated( __METHOD__, '1.27' );
+               $userTargetCombinations = [];
+               /** @var WatchedItem $watchedItem */
+               foreach ( $items as $watchedItem ) {
+                       if ( $watchedItem->checkRights && !$watchedItem->getUser()->isAllowed( 'editmywatchlist' ) ) {
                                continue;
                        }
-                       $rows[] = [
-                               'wl_user' => $item->getUserId(),
-                               'wl_namespace' => MWNamespace::getSubject( $item->getTitleNs() ),
-                               'wl_title' => $item->getTitleDBkey(),
-                               'wl_notificationtimestamp' => null,
+                       $userTargetCombinations[] = [
+                               $watchedItem->getUser(),
+                               $watchedItem->getTitle()->getSubjectPage()
                        ];
-                       // Every single watched page needs now to be listed in watchlist;
-                       // namespace:page and namespace_talk:page need separate entries:
-                       $rows[] = [
-                               'wl_user' => $item->getUserId(),
-                               'wl_namespace' => MWNamespace::getTalk( $item->getTitleNs() ),
-                               'wl_title' => $item->getTitleDBkey(),
-                               'wl_notificationtimestamp' => null
+                       $userTargetCombinations[] = [
+                               $watchedItem->getUser(),
+                               $watchedItem->getTitle()->getTalkPage()
                        ];
-                       $item->watched = true;
-               }
-
-               if ( !$rows ) {
-                       return false;
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-               foreach ( array_chunk( $rows, 100 ) as $toInsert ) {
-                       // Use INSERT IGNORE to avoid overwriting the notification timestamp
-                       // if there's already an entry for this page
-                       $dbw->insert( 'watchlist', $toInsert, __METHOD__, 'IGNORE' );
                }
-
-               return true;
+               $store = WatchedItemStore::getDefaultInstance();
+               return $store->addWatchBatch( $userTargetCombinations );
        }
 
        /**
-        * Given a title and user (assumes the object is setup), add the watch to the database.
+        * @deprecated since 1.27 Use User::addWatch()
         * @return bool
         */
        public function addWatch() {
-               return self::batchAddWatch( [ $this ] );
+               // wfDeprecated( __METHOD__, '1.27' );
+               $this->user->addWatch( $this->getTitle(), $this->checkRights );
+               return true;
        }
 
        /**
-        * Same as addWatch, only the opposite.
+        * @deprecated since 1.27 Use User::removeWatch()
         * @return bool
         */
        public function removeWatch() {
-
-               // Only loggedin user can have a watchlist
-               if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
+               // wfDeprecated( __METHOD__, '1.27' );
+               if ( $this->checkRights && !$this->user->isAllowed( 'editmywatchlist' ) ) {
                        return false;
                }
+               $this->user->removeWatch( $this->getTitle(), $this->checkRights );
+               return true;
+       }
 
-               $success = false;
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->delete( 'watchlist',
-                       [
-                               'wl_user' => $this->getUserId(),
-                               'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ),
-                               'wl_title' => $this->getTitleDBkey(),
-                       ], __METHOD__
-               );
-               if ( $dbw->affectedRows() ) {
-                       $success = true;
-               }
-
-               # the following code compensates the new behavior, introduced by the
-               # enotif patch, that every single watched page needs now to be listed
-               # in watchlist namespace:page and namespace_talk:page had separate
-               # entries: clear them
-               $dbw->delete( 'watchlist',
-                       [
-                               'wl_user' => $this->getUserId(),
-                               'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ),
-                               'wl_title' => $this->getTitleDBkey(),
-                       ], __METHOD__
-               );
-
-               if ( $dbw->affectedRows() ) {
-                       $success = true;
-               }
-
-               $this->watched = false;
-
-               return $success;
+       /**
+        * @deprecated since 1.27 Use User::isWatched()
+        * @return bool
+        */
+       public function isWatched() {
+               // wfDeprecated( __METHOD__, '1.27' );
+               return $this->user->isWatched( $this->getTitle(), $this->checkRights );
        }
 
        /**
-        * @deprecated since 1.27. See WatchedItemStore::duplicateEntry
-        *
-        * @param Title $oldTitle
-        * @param Title $newTitle
+        * @deprecated since 1.27 Use WatchedItemStore::duplicateAllAssociatedEntries()
         */
        public static function duplicateEntries( Title $oldTitle, Title $newTitle ) {
+               // wfDeprecated( __METHOD__, '1.27' );
                $store = WatchedItemStore::getDefaultInstance();
-               $store->duplicateEntry( $oldTitle->getSubjectPage(), $newTitle->getSubjectPage() );
-               $store->duplicateEntry( $oldTitle->getTalkPage(), $newTitle->getTalkPage() );
+               $store->duplicateAllAssociatedEntries( $oldTitle, $newTitle );
        }
 
 }
index 83a5856..1aed8e0 100644 (file)
@@ -1,8 +1,10 @@
 <?php
 
+use Wikimedia\Assert\Assert;
+
 /**
  * Storage layer class for WatchedItems.
- * Database interaction
+ * Database interaction.
  *
  * @author Addshore
  *
@@ -15,19 +17,465 @@ class WatchedItemStore {
         */
        private $loadBalancer;
 
-       public function __construct( LoadBalancer $loadBalancer ) {
+       /**
+        * @var BagOStuff
+        */
+       private $cache;
+
+       /**
+        * @var callable|null
+        */
+       private $deferredUpdatesAddCallableUpdateCallback;
+
+       /**
+        * @var callable|null
+        */
+       private $revisionGetTimestampFromIdCallback;
+
+       /**
+        * @var self|null
+        */
+       private static $instance;
+
+       public function __construct( LoadBalancer $loadBalancer, BagOStuff $cache ) {
                $this->loadBalancer = $loadBalancer;
+               $this->cache = $cache;
+               $this->deferredUpdatesAddCallableUpdateCallback = [ 'DeferredUpdates', 'addCallableUpdate' ];
+               $this->revisionGetTimestampFromIdCallback = [ 'Revision', 'getTimestampFromId' ];
+       }
+
+       /**
+        * Overrides the DeferredUpdates::addCallableUpdate callback
+        * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined.
+        *
+        * @param callable $callback
+        * @see DeferredUpdates::addCallableUpdate for callback signiture
+        *
+        * @throws MWException
+        */
+       public function overrideDeferredUpdatesAddCallableUpdateCallback( $callback ) {
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       throw new MWException(
+                               'Cannot override DeferredUpdates::addCallableUpdate callback in operation.'
+                       );
+               }
+               Assert::parameterType( 'callable', $callback, '$callback' );
+               $this->deferredUpdatesAddCallableUpdateCallback = $callback;
+       }
+
+       /**
+        * Overrides the Revision::getTimestampFromId callback
+        * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined.
+        *
+        * @param callable $callback
+        * @see Revision::getTimestampFromId for callback signiture
+        *
+        * @throws MWException
+        */
+       public function overrideRevisionGetTimestampFromIdCallback( $callback ) {
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       throw new MWException(
+                               'Cannot override Revision::getTimestampFromId callback in operation.'
+                       );
+               }
+               Assert::parameterType( 'callable', $callback, '$callback' );
+               $this->revisionGetTimestampFromIdCallback = $callback;
+       }
+
+       /**
+        * Overrides the default instance of this class
+        * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined.
+        *
+        * @param WatchedItemStore $store
+        *
+        * @throws MWException
+        */
+       public static function overrideDefaultInstance( WatchedItemStore $store ) {
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       throw new MWException(
+                               'Cannot override ' . __CLASS__ . 'default instance in operation.'
+                       );
+               }
+               self::$instance = $store;
        }
 
        /**
         * @return self
         */
        public static function getDefaultInstance() {
-               static $instance;
-               if ( !$instance ) {
-                       $instance = new self( wfGetLB() );
+               if ( !self::$instance ) {
+                       self::$instance = new self(
+                               wfGetLB(),
+                               new HashBagOStuff( [ 'maxKeys' => 100 ] )
+                       );
+               }
+               return self::$instance;
+       }
+
+       private function getCacheKey( User $user, LinkTarget $target ) {
+               return $this->cache->makeKey(
+                       (string)$target->getNamespace(),
+                       $target->getDBkey(),
+                       (string)$user->getId()
+               );
+       }
+
+       private function cache( WatchedItem $item ) {
+               $this->cache->set(
+                       $this->getCacheKey( $item->getUser(), $item->getLinkTarget() ),
+                       $item
+               );
+       }
+
+       private function uncache( User $user, LinkTarget $target ) {
+               $this->cache->delete( $this->getCacheKey( $user, $target ) );
+       }
+
+       /**
+        * @param User $user
+        * @param LinkTarget $target
+        *
+        * @return WatchedItem|null
+        */
+       private function getCached( User $user, LinkTarget $target ) {
+               return $this->cache->get( $this->getCacheKey( $user, $target ) );
+       }
+
+       /**
+        * Return an array of conditions to select or update the appropriate database
+        * row.
+        *
+        * @param User $user
+        * @param LinkTarget $target
+        *
+        * @return array
+        */
+       private function dbCond( User $user, LinkTarget $target ) {
+               return [
+                       'wl_user' => $user->getId(),
+                       'wl_namespace' => $target->getNamespace(),
+                       'wl_title' => $target->getDBkey(),
+               ];
+       }
+
+       /**
+        * Get an item (may be cached)
+        *
+        * @param User $user
+        * @param LinkTarget $target
+        *
+        * @return WatchedItem|false
+        */
+       public function getWatchedItem( User $user, LinkTarget $target ) {
+               $cached = $this->getCached( $user, $target );
+               if ( $cached ) {
+                       return $cached;
+               }
+               return $this->loadWatchedItem( $user, $target );
+       }
+
+       /**
+        * Loads an item from the db
+        *
+        * @param User $user
+        * @param LinkTarget $target
+        *
+        * @return WatchedItem|false
+        */
+       public function loadWatchedItem( User $user, LinkTarget $target ) {
+               // Only loggedin user can have a watchlist
+               if ( $user->isAnon() ) {
+                       return false;
+               }
+
+               $dbr = $this->loadBalancer->getConnection( DB_SLAVE, [ 'watchlist' ] );
+               $row = $dbr->selectRow(
+                       'watchlist',
+                       'wl_notificationtimestamp',
+                       $this->dbCond( $user, $target ),
+                       __METHOD__
+               );
+               $this->loadBalancer->reuseConnection( $dbr );
+
+               if ( !$row ) {
+                       return false;
+               }
+
+               $item = new WatchedItem(
+                       $user,
+                       $target,
+                       $row->wl_notificationtimestamp
+               );
+               $this->cache( $item );
+
+               return $item;
+       }
+
+       /**
+        * Must be called separately for Subject & Talk namespaces
+        *
+        * @param User $user
+        * @param LinkTarget $target
+        *
+        * @return bool
+        */
+       public function isWatched( User $user, LinkTarget $target ) {
+               return (bool)$this->getWatchedItem( $user, $target );
+       }
+
+       /**
+        * Must be called separately for Subject & Talk namespaces
+        *
+        * @param User $user
+        * @param LinkTarget $target
+        */
+       public function addWatch( User $user, LinkTarget $target ) {
+               $this->addWatchBatch( [ [ $user, $target ] ] );
+       }
+
+       /**
+        * @param array[] $userTargetCombinations array of arrays containing [0] => User [1] => LinkTarget
+        *
+        * @return bool success
+        */
+       public function addWatchBatch( array $userTargetCombinations ) {
+               if ( $this->loadBalancer->getReadOnlyReason() !== false ) {
+                       return false;
+               }
+
+               $rows = [];
+               foreach ( $userTargetCombinations as list( $user, $target ) ) {
+                       /**
+                        * @var User $user
+                        * @var LinkTarget $target
+                        */
+
+                       // Only loggedin user can have a watchlist
+                       if ( $user->isAnon() ) {
+                               continue;
+                       }
+                       $rows[] = [
+                               'wl_user' => $user->getId(),
+                               'wl_namespace' => $target->getNamespace(),
+                               'wl_title' => $target->getDBkey(),
+                               'wl_notificationtimestamp' => null,
+                       ];
+                       $this->uncache( $user, $target );
+               }
+
+               if ( !$rows ) {
+                       return false;
+               }
+
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER, [ 'watchlist' ] );
+               foreach ( array_chunk( $rows, 100 ) as $toInsert ) {
+                       // Use INSERT IGNORE to avoid overwriting the notification timestamp
+                       // if there's already an entry for this page
+                       $dbw->insert( 'watchlist', $toInsert, __METHOD__, 'IGNORE' );
+               }
+               $this->loadBalancer->reuseConnection( $dbw );
+
+               return true;
+       }
+
+       /**
+        * Removes the an entry for the User watching the LinkTarget
+        * Must be called separately for Subject & Talk namespaces
+        *
+        * @param User $user
+        * @param LinkTarget $target
+        *
+        * @return bool success
+        * @throws DBUnexpectedError
+        * @throws MWException
+        */
+       public function removeWatch( User $user, LinkTarget $target ) {
+               // Only logged in user can have a watchlist
+               if ( $this->loadBalancer->getReadOnlyReason() !== false || $user->isAnon() ) {
+                       return false;
                }
-               return $instance;
+
+               $this->uncache( $user, $target );
+
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER, [ 'watchlist' ] );
+               $dbw->delete( 'watchlist',
+                       [
+                               'wl_user' => $user->getId(),
+                               'wl_namespace' => $target->getNamespace(),
+                               'wl_title' => $target->getDBkey(),
+                       ], __METHOD__
+               );
+               $success = (bool)$dbw->affectedRows();
+               $this->loadBalancer->reuseConnection( $dbw );
+
+               return $success;
+       }
+
+       /**
+        * @param User $editor The editor that triggered the update. Their notification
+        *  timestamp will not be updated(they have already seen it)
+        * @param LinkTarget $target The target to update timestamps for
+        * @param string $timestamp Set the update timestamp to this value
+        *
+        * @return int[] Array of user IDs the timestamp has been updated for
+        */
+       public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) {
+               $dbw = $this->loadBalancer->getConnection( DB_MASTER, [ 'watchlist' ] );
+               $res = $dbw->select( [ 'watchlist' ],
+                       [ 'wl_user' ],
+                       [
+                               'wl_user != ' . intval( $editor->getId() ),
+                               'wl_namespace' => $target->getNamespace(),
+                               'wl_title' => $target->getDBkey(),
+                               'wl_notificationtimestamp IS NULL',
+                       ], __METHOD__
+               );
+
+               $watchers = [];
+               foreach ( $res as $row ) {
+                       $watchers[] = intval( $row->wl_user );
+               }
+
+               if ( $watchers ) {
+                       // Update wl_notificationtimestamp for all watching users except the editor
+                       $fname = __METHOD__;
+                       $dbw->onTransactionIdle(
+                               function () use ( $dbw, $timestamp, $watchers, $target, $fname ) {
+                                       $dbw->update( 'watchlist',
+                                               [ /* SET */
+                                                       'wl_notificationtimestamp' => $dbw->timestamp( $timestamp )
+                                               ], [ /* WHERE */
+                                                       'wl_user' => $watchers,
+                                                       'wl_namespace' => $target->getNamespace(),
+                                                       'wl_title' => $target->getDBkey(),
+                                               ], $fname
+                                       );
+                               }
+                       );
+               }
+
+               $this->loadBalancer->reuseConnection( $dbw );
+
+               return $watchers;
+       }
+
+       /**
+        * Reset the notification timestamp of this entry
+        *
+        * @param User $user
+        * @param Title $title
+        * @param string $force Whether to force the write query to be executed even if the
+        *    page is not watched or the notification timestamp is already NULL.
+        *    'force' in order to force
+        * @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
+        *
+        * @return bool success
+        */
+       public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 ) {
+               // Only loggedin user can have a watchlist
+               if ( $this->loadBalancer->getReadOnlyReason() !== false || $user->isAnon() ) {
+                       return false;
+               }
+
+               $item = null;
+               if ( $force != 'force' ) {
+                       $item = $this->loadWatchedItem( $user, $title );
+                       if ( !$item || $item->getNotificationTimestamp() === null ) {
+                               return false;
+                       }
+               }
+
+               // If the page is watched by the user (or may be watched), update the timestamp
+               $job = new ActivityUpdateJob(
+                       $title,
+                       [
+                               'type'      => 'updateWatchlistNotification',
+                               'userid'    => $user->getId(),
+                               'notifTime' => $this->getNotificationTimestamp( $user, $title, $item, $force, $oldid ),
+                               'curTime'   => time()
+                       ]
+               );
+
+               // Try to run this post-send
+               // Calls DeferredUpdates::addCallableUpdate in normal operation
+               call_user_func(
+                       $this->deferredUpdatesAddCallableUpdateCallback,
+                       function() use ( $job ) {
+                               $job->run();
+                       }
+               );
+
+               $this->uncache( $user, $title );
+
+               return true;
+       }
+
+       private function getNotificationTimestamp( User $user, Title $title, $item, $force, $oldid ) {
+               if ( !$oldid ) {
+                       // No oldid given, assuming latest revision; clear the timestamp.
+                       return null;
+               }
+
+               if ( !$title->getNextRevisionID( $oldid ) ) {
+                       // Oldid given and is the latest revision for this title; clear the timestamp.
+                       return null;
+               }
+
+               if ( $item === null ) {
+                       $item = $this->loadWatchedItem( $user, $title );
+               }
+
+               if ( !$item ) {
+                       // This can only happen if $force is enabled.
+                       return null;
+               }
+
+               // Oldid given and isn't the latest; update the timestamp.
+               // This will result in no further notification emails being sent!
+               // Calls Revision::getTimestampFromId in normal operation
+               $notificationTimestamp = call_user_func(
+                       $this->revisionGetTimestampFromIdCallback,
+                       $title,
+                       $oldid
+               );
+
+               // We need to go one second to the future because of various strict comparisons
+               // throughout the codebase
+               $ts = new MWTimestamp( $notificationTimestamp );
+               $ts->timestamp->add( new DateInterval( 'PT1S' ) );
+               $notificationTimestamp = $ts->getTimestamp( TS_MW );
+
+               if ( $notificationTimestamp < $item->getNotificationTimestamp() ) {
+                       if ( $force != 'force' ) {
+                               return false;
+                       } else {
+                               // This is a little silly…
+                               return $item->getNotificationTimestamp();
+                       }
+               }
+
+               return $notificationTimestamp;
+       }
+
+       /**
+        * Check if the given title already is watched by the user, and if so
+        * add a watch for the new title.
+        *
+        * To be used for page renames and such.
+        *
+        * @param LinkTarget $oldTarget
+        * @param LinkTarget $newTarget
+        */
+       public function duplicateAllAssociatedEntries( LinkTarget $oldTarget, LinkTarget $newTarget ) {
+               if ( !$oldTarget instanceof Title ) {
+                       $oldTarget = Title::newFromLinkTarget( $oldTarget );
+               }
+               if ( !$newTarget instanceof Title ) {
+                       $newTarget = Title::newFromLinkTarget( $newTarget );
+               }
+
+               $this->duplicateEntry( $oldTarget->getSubjectPage(), $newTarget->getSubjectPage() );
+               $this->duplicateEntry( $oldTarget->getTalkPage(), $newTarget->getTalkPage() );
        }
 
        /**
index c7d0a5b..458c207 100644 (file)
@@ -179,6 +179,16 @@ class WebResponse {
        public function clearCookie( $name, $options = [] ) {
                $this->setCookie( $name, '', time() - 31536000 /* 1 year */, $options );
        }
+
+       /**
+        * Checks whether this request is performing cookie operations
+        *
+        * @return bool
+        * @since 1.27
+        */
+       public function hasCookies() {
+               return (bool)self::$setCookies;
+       }
 }
 
 /**
index 6f1f3e8..5ec10e6 100644 (file)
@@ -682,7 +682,7 @@ class HistoryPager extends ReverseChronologicalPager {
                $s .= $dirmark;
 
                if ( $rev->isMinor() ) {
-                       $s .= ' ' . ChangesList::flag( 'minor' );
+                       $s .= ' ' . ChangesList::flag( 'minor', $this->getContext() );
                }
 
                # Sometimes rev_len isn't populated
index db8c82d..d002da8 100644 (file)
@@ -103,7 +103,7 @@ class RollbackAction extends FormlessAction {
                        ->parseAsBlock() );
 
                if ( $user->getBoolOption( 'watchrollback' ) ) {
-                       $user->addWatch( $this->page->getTitle(), WatchedItem::IGNORE_USER_RIGHTS );
+                       $user->addWatch( $this->page->getTitle(), User::IGNORE_USER_RIGHTS );
                }
 
                $this->getOutput()->returnToMain( false, $this->getTitle() );
index 8f13456..890740f 100644 (file)
@@ -82,12 +82,12 @@ class WatchAction extends FormAction {
         */
        public static function doWatchOrUnwatch( $watch, Title $title, User $user ) {
                if ( $user->isLoggedIn() &&
-                       $user->isWatched( $title, WatchedItem::IGNORE_USER_RIGHTS ) != $watch
+                       $user->isWatched( $title, User::IGNORE_USER_RIGHTS ) != $watch
                ) {
                        // If the user doesn't have 'editmywatchlist', we still want to
                        // allow them to add but not remove items via edits and such.
                        if ( $watch ) {
-                               return self::doWatch( $title, $user, WatchedItem::IGNORE_USER_RIGHTS );
+                               return self::doWatch( $title, $user, User::IGNORE_USER_RIGHTS );
                        } else {
                                return self::doUnwatch( $title, $user );
                        }
@@ -101,15 +101,16 @@ class WatchAction extends FormAction {
         * @since 1.22 Returns Status, $checkRights parameter added
         * @param Title $title Page to watch/unwatch
         * @param User $user User who is watching/unwatching
-        * @param int $checkRights Passed through to $user->addWatch()
+        * @param bool $checkRights Passed through to $user->addWatch()
+        *     Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
         * @return Status
         */
-       public static function doWatch( Title $title, User $user,
-               $checkRights = WatchedItem::CHECK_USER_RIGHTS
+       public static function doWatch(
+               Title $title,
+               User $user,
+               $checkRights = User::CHECK_USER_RIGHTS
        ) {
-               if ( $checkRights !== WatchedItem::IGNORE_USER_RIGHTS &&
-                       !$user->isAllowed( 'editmywatchlist' )
-               ) {
+               if ( $checkRights && !$user->isAllowed( 'editmywatchlist' ) ) {
                        return User::newFatalPermissionDeniedStatus( 'editmywatchlist' );
                }
 
index 76fae6b..85dee2b 100644 (file)
@@ -302,7 +302,7 @@ abstract class ApiBase extends ContextSource {
                                        $qs = $k;
                                        $msg = self::escapeWikiText( $v );
                                        if ( is_array( $msg ) ) {
-                                               $msg = join( " ", $msg );
+                                               $msg = implode( ' ', $msg );
                                        }
                                }
 
@@ -547,13 +547,13 @@ abstract class ApiBase extends ContextSource {
                        $parent = $module;
                        $manager = $parent->getModuleManager();
                        if ( $manager === null ) {
-                               $errorPath = join( '+', array_slice( $parts, 0, $i ) );
+                               $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
                                $this->dieUsage( "The module \"$errorPath\" has no submodules", 'badmodule' );
                        }
                        $module = $manager->getModule( $parts[$i] );
 
                        if ( $module === null ) {
-                               $errorPath = $i ? join( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
+                               $errorPath = $i ? implode( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
                                $this->dieUsage(
                                        "The module \"$errorPath\" does not have a submodule \"{$parts[$i]}\"",
                                        'badmodule'
@@ -711,7 +711,7 @@ abstract class ApiBase extends ContextSource {
                $p = $this->getModulePrefix();
 
                $intersection = array_intersect( array_keys( array_filter( $params,
-                       [ $this, "parameterNotEmpty" ] ) ), $required );
+                       [ $this, 'parameterNotEmpty' ] ) ), $required );
 
                if ( count( $intersection ) > 1 ) {
                        $this->dieUsage(
@@ -737,7 +737,7 @@ abstract class ApiBase extends ContextSource {
                $p = $this->getModulePrefix();
 
                $intersection = array_intersect( array_keys( array_filter( $params,
-                       [ $this, "parameterNotEmpty" ] ) ), $required );
+                       [ $this, 'parameterNotEmpty' ] ) ), $required );
 
                if ( count( $intersection ) > 1 ) {
                        $this->dieUsage(
@@ -760,7 +760,7 @@ abstract class ApiBase extends ContextSource {
                $p = $this->getModulePrefix();
 
                $intersection = array_intersect(
-                       array_keys( array_filter( $params, [ $this, "parameterNotEmpty" ] ) ),
+                       array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
                        $required
                );
 
@@ -830,7 +830,7 @@ abstract class ApiBase extends ContextSource {
         */
        protected function getWatchlistValue( $watchlist, $titleObj, $userOption = null ) {
 
-               $userWatching = $this->getUser()->isWatched( $titleObj, WatchedItem::IGNORE_USER_RIGHTS );
+               $userWatching = $this->getUser()->isWatched( $titleObj, User::IGNORE_USER_RIGHTS );
 
                switch ( $watchlist ) {
                        case 'watch':
@@ -917,7 +917,7 @@ abstract class ApiBase extends ContextSource {
                                ApiBase::dieDebug(
                                        __METHOD__,
                                        "Boolean param $encParamName's default is set to '$default'. " .
-                                               "Boolean parameters must default to false."
+                                               'Boolean parameters must default to false.'
                                );
                        }
 
@@ -942,8 +942,8 @@ abstract class ApiBase extends ContextSource {
                                if ( $value !== null ) {
                                        $this->dieUsage(
                                                "File upload param $encParamName is not a file upload; " .
-                                                       "be sure to use multipart/form-data for your POST and include " .
-                                                       "a filename in the Content-Disposition header.",
+                                                       'be sure to use multipart/form-data for your POST and include ' .
+                                                       'a filename in the Content-Disposition header.',
                                                "badupload_{$encParamName}"
                                        );
                                }
@@ -1157,7 +1157,7 @@ abstract class ApiBase extends ContextSource {
                        if ( count( $unknown ) ) {
                                if ( $allowMultiple ) {
                                        $s = count( $unknown ) > 1 ? 's' : '';
-                                       $vals = implode( ", ", $unknown );
+                                       $vals = implode( ', ', $unknown );
                                        $this->setWarning( "Unrecognized value$s for parameter '$valueName': $vals" );
                                } else {
                                        $this->dieUsage(
@@ -1615,15 +1615,15 @@ abstract class ApiBase extends ContextSource {
                ],
                'badaccess-group0' => [
                        'code' => 'permissiondenied',
-                       'info' => "Permission denied"
+                       'info' => 'Permission denied'
                ], // Generic permission denied message
                'badaccess-groups' => [
                        'code' => 'permissiondenied',
-                       'info' => "Permission denied"
+                       'info' => 'Permission denied'
                ],
                'titleprotected' => [
                        'code' => 'protectedtitle',
-                       'info' => "This title has been protected from creation"
+                       'info' => 'This title has been protected from creation'
                ],
                'nocreate-loggedin' => [
                        'code' => 'cantcreate',
@@ -1643,15 +1643,15 @@ abstract class ApiBase extends ContextSource {
                ],
                'confirmedittext' => [
                        'code' => 'confirmemail',
-                       'info' => "You must confirm your email address before you can edit"
+                       'info' => 'You must confirm your email address before you can edit'
                ],
                'blockedtext' => [
                        'code' => 'blocked',
-                       'info' => "You have been blocked from editing"
+                       'info' => 'You have been blocked from editing'
                ],
                'autoblockedtext' => [
                        'code' => 'autoblocked',
-                       'info' => "Your IP address has been blocked automatically, because it was used by a blocked user"
+                       'info' => 'Your IP address has been blocked automatically, because it was used by a blocked user'
                ],
 
                // Miscellaneous interface messages
@@ -1661,19 +1661,19 @@ abstract class ApiBase extends ContextSource {
                ],
                'alreadyrolled' => [
                        'code' => 'alreadyrolled',
-                       'info' => "The page you tried to rollback was already rolled back"
+                       'info' => 'The page you tried to rollback was already rolled back'
                ],
                'cantrollback' => [
                        'code' => 'onlyauthor',
-                       'info' => "The page you tried to rollback only has one author"
+                       'info' => 'The page you tried to rollback only has one author'
                ],
                'readonlytext' => [
                        'code' => 'readonly',
-                       'info' => "The wiki is currently in read-only mode"
+                       'info' => 'The wiki is currently in read-only mode'
                ],
                'sessionfailure' => [
                        'code' => 'badtoken',
-                       'info' => "Invalid token" ],
+                       'info' => 'Invalid token' ],
                'cannotdelete' => [
                        'code' => 'cantdelete',
                        'info' => "Couldn't delete \"\$1\". Maybe it was deleted already by someone else"
@@ -1686,11 +1686,11 @@ abstract class ApiBase extends ContextSource {
                ],
                'immobile_namespace' => [
                        'code' => 'immobilenamespace',
-                       'info' => "You tried to move pages from or to a namespace that is protected from moving"
+                       'info' => 'You tried to move pages from or to a namespace that is protected from moving'
                ],
                'articleexists' => [
                        'code' => 'articleexists',
-                       'info' => "The destination article already exists and is not a redirect to the source article"
+                       'info' => 'The destination article already exists and is not a redirect to the source article'
                ],
                'protectedpage' => [
                        'code' => 'protectedpage',
@@ -1698,11 +1698,11 @@ abstract class ApiBase extends ContextSource {
                ],
                'hookaborted' => [
                        'code' => 'hookaborted',
-                       'info' => "The modification you tried to make was aborted by an extension hook"
+                       'info' => 'The modification you tried to make was aborted by an extension hook'
                ],
                'cantmove-titleprotected' => [
                        'code' => 'protectedtitle',
-                       'info' => "The destination article has been protected from creation"
+                       'info' => 'The destination article has been protected from creation'
                ],
                'imagenocrossnamespace' => [
                        'code' => 'nonfilenamespace',
@@ -1714,20 +1714,20 @@ abstract class ApiBase extends ContextSource {
                ],
                // 'badarticleerror' => shouldn't happen
                // 'badtitletext' => shouldn't happen
-               'ip_range_invalid' => [ 'code' => 'invalidrange', 'info' => "Invalid IP range" ],
+               'ip_range_invalid' => [ 'code' => 'invalidrange', 'info' => 'Invalid IP range' ],
                'range_block_disabled' => [
                        'code' => 'rangedisabled',
-                       'info' => "Blocking IP ranges has been disabled"
+                       'info' => 'Blocking IP ranges has been disabled'
                ],
                'nosuchusershort' => [
                        'code' => 'nosuchuser',
                        'info' => "The user you specified doesn't exist"
                ],
-               'badipaddress' => [ 'code' => 'invalidip', 'info' => "Invalid IP address specified" ],
-               'ipb_expiry_invalid' => [ 'code' => 'invalidexpiry', 'info' => "Invalid expiry time" ],
+               'badipaddress' => [ 'code' => 'invalidip', 'info' => 'Invalid IP address specified' ],
+               'ipb_expiry_invalid' => [ 'code' => 'invalidexpiry', 'info' => 'Invalid expiry time' ],
                'ipb_already_blocked' => [
                        'code' => 'alreadyblocked',
-                       'info' => "The user you tried to block was already blocked"
+                       'info' => 'The user you tried to block was already blocked'
                ],
                'ipb_blocked_as_range' => [
                        'code' => 'blockedasrange',
@@ -1735,11 +1735,11 @@ abstract class ApiBase extends ContextSource {
                ],
                'ipb_cant_unblock' => [
                        'code' => 'cantunblock',
-                       'info' => "The block you specified was not found. It may have been unblocked already"
+                       'info' => 'The block you specified was not found. It may have been unblocked already'
                ],
                'mailnologin' => [
                        'code' => 'cantsend',
-                       'info' => "You are not logged in, you do not have a confirmed email address, or you are not allowed to send email to other users, so you cannot send email"
+                       'info' => 'You are not logged in, you do not have a confirmed email address, or you are not allowed to send email to other users, so you cannot send email'
                ],
                'ipbblocked' => [
                        'code' => 'ipbblocked',
@@ -1751,23 +1751,23 @@ abstract class ApiBase extends ContextSource {
                ],
                'usermaildisabled' => [
                        'code' => 'usermaildisabled',
-                       'info' => "User email has been disabled"
+                       'info' => 'User email has been disabled'
                ],
                'blockedemailuser' => [
                        'code' => 'blockedfrommail',
-                       'info' => "You have been blocked from sending email"
+                       'info' => 'You have been blocked from sending email'
                ],
                'notarget' => [
                        'code' => 'notarget',
-                       'info' => "You have not specified a valid target for this action"
+                       'info' => 'You have not specified a valid target for this action'
                ],
                'noemail' => [
                        'code' => 'noemail',
-                       'info' => "The user has not specified a valid email address, or has chosen not to receive email from other users"
+                       'info' => 'The user has not specified a valid email address, or has chosen not to receive email from other users'
                ],
                'rcpatroldisabled' => [
                        'code' => 'patroldisabled',
-                       'info' => "Patrolling is disabled on this wiki"
+                       'info' => 'Patrolling is disabled on this wiki'
                ],
                'markedaspatrollederror-noautopatrol' => [
                        'code' => 'noautopatrol',
@@ -1804,7 +1804,7 @@ abstract class ApiBase extends ContextSource {
                // API-specific messages
                'readrequired' => [
                        'code' => 'readapidenied',
-                       'info' => "You need read permission to use this module"
+                       'info' => 'You need read permission to use this module'
                ],
                'writedisabled' => [
                        'code' => 'noapiwrite',
@@ -1843,7 +1843,7 @@ abstract class ApiBase extends ContextSource {
                ],
                'unblock-notarget' => [
                        'code' => 'notarget',
-                       'info' => "Either the id or the user parameter must be set"
+                       'info' => 'Either the id or the user parameter must be set'
                ],
                'unblock-idanduser' => [
                        'code' => 'idanduser',
@@ -1863,7 +1863,7 @@ abstract class ApiBase extends ContextSource {
                ],
                'createonly-exists' => [
                        'code' => 'articleexists',
-                       'info' => "The article you tried to create has been created already"
+                       'info' => 'The article you tried to create has been created already'
                ],
                'nocreate-missing' => [
                        'code' => 'missingtitle',
@@ -1992,17 +1992,17 @@ abstract class ApiBase extends ContextSource {
                'noedit' => [ 'code' => 'noedit', 'info' => "You don't have permission to edit pages" ],
                'wasdeleted' => [
                        'code' => 'pagedeleted',
-                       'info' => "The page has been deleted since you fetched its timestamp"
+                       'info' => 'The page has been deleted since you fetched its timestamp'
                ],
                'blankpage' => [
                        'code' => 'emptypage',
-                       'info' => "Creating new, empty pages is not allowed"
+                       'info' => 'Creating new, empty pages is not allowed'
                ],
-               'editconflict' => [ 'code' => 'editconflict', 'info' => "Edit conflict detected" ],
-               'hashcheckfailed' => [ 'code' => 'badmd5', 'info' => "The supplied MD5 hash was incorrect" ],
+               'editconflict' => [ 'code' => 'editconflict', 'info' => 'Edit conflict detected' ],
+               'hashcheckfailed' => [ 'code' => 'badmd5', 'info' => 'The supplied MD5 hash was incorrect' ],
                'missingtext' => [
                        'code' => 'notext',
-                       'info' => "One of the text, appendtext, prependtext and undo parameters must be set"
+                       'info' => 'One of the text, appendtext, prependtext and undo parameters must be set'
                ],
                'emptynewsection' => [
                        'code' => 'emptynewsection',
@@ -2024,13 +2024,13 @@ abstract class ApiBase extends ContextSource {
                // Messages from WikiPage::doEit(]
                'edit-hook-aborted' => [
                        'code' => 'edit-hook-aborted',
-                       'info' => "Your edit was aborted by an ArticleSave hook"
+                       'info' => 'Your edit was aborted by an ArticleSave hook'
                ],
                'edit-gone-missing' => [
                        'code' => 'edit-gone-missing',
                        'info' => "The page you tried to edit doesn't seem to exist anymore"
                ],
-               'edit-conflict' => [ 'code' => 'editconflict', 'info' => "Edit conflict detected" ],
+               'edit-conflict' => [ 'code' => 'editconflict', 'info' => 'Edit conflict detected' ],
                'edit-already-exists' => [
                        'code' => 'edit-already-exists',
                        'info' => 'It seems the page you tried to create already exist'
@@ -2223,7 +2223,7 @@ abstract class ApiBase extends ContextSource {
                Hooks::run( 'APIGetDescription', [ &$this, &$desc ] );
                $desc = self::escapeWikiText( $desc );
                if ( is_array( $desc ) ) {
-                       $desc = join( "\n", $desc );
+                       $desc = implode( "\n", $desc );
                } else {
                        $desc = (string)$desc;
                }
@@ -2309,7 +2309,7 @@ abstract class ApiBase extends ContextSource {
                                        }
                                        return $line;
                                }, $d );
-                               $d = join( ' ', $d );
+                               $d = implode( ' ', $d );
                        }
 
                        if ( isset( $settings[ApiBase::PARAM_HELP_MSG] ) ) {
@@ -2323,18 +2323,18 @@ abstract class ApiBase extends ContextSource {
                        $msg = ApiBase::makeMessage( $msg, $this->getContext(),
                                [ $prefix, $param, $name, $path ] );
                        if ( !$msg ) {
-                               $this->dieDebug( __METHOD__,
+                               self::dieDebug( __METHOD__,
                                        'Value in ApiBase::PARAM_HELP_MSG is not valid' );
                        }
                        $msgs[$param] = [ $msg ];
 
                        if ( isset( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
                                if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
-                                       $this->dieDebug( __METHOD__,
+                                       self::dieDebug( __METHOD__,
                                                'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
                                }
                                if ( !is_array( $settings[ApiBase::PARAM_TYPE] ) ) {
-                                       $this->dieDebug( __METHOD__,
+                                       self::dieDebug( __METHOD__,
                                                'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
                                                'ApiBase::PARAM_TYPE is an array' );
                                }
@@ -2356,7 +2356,7 @@ abstract class ApiBase extends ContextSource {
                                                );
                                                $msgs[$param][] = $m->setContext( $this->getContext() );
                                        } else {
-                                               $this->dieDebug( __METHOD__,
+                                               self::dieDebug( __METHOD__,
                                                        "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
                                        }
                                }
@@ -2364,7 +2364,7 @@ abstract class ApiBase extends ContextSource {
 
                        if ( isset( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
                                if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
-                                       $this->dieDebug( __METHOD__,
+                                       self::dieDebug( __METHOD__,
                                                'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
                                }
                                foreach ( $settings[ApiBase::PARAM_HELP_MSG_APPEND] as $m ) {
@@ -2373,7 +2373,7 @@ abstract class ApiBase extends ContextSource {
                                        if ( $m ) {
                                                $msgs[$param][] = $m;
                                        } else {
-                                               $this->dieDebug( __METHOD__,
+                                               self::dieDebug( __METHOD__,
                                                        'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
                                        }
                                }
@@ -2740,7 +2740,7 @@ abstract class ApiBase extends ContextSource {
                                                $examples
                                        ];
                                }
-                               $msg .= "Example" . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
+                               $msg .= 'Example' . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
                                foreach ( $examples as $k => $v ) {
                                        if ( is_numeric( $k ) ) {
                                                $msg .= "  $v\n";
@@ -2750,7 +2750,7 @@ abstract class ApiBase extends ContextSource {
                                                } else {
                                                        $msgExample = "  $v";
                                                }
-                                               $msgExample .= ":";
+                                               $msgExample .= ':';
                                                $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n    $k\n";
                                        }
                                }
@@ -2766,7 +2766,7 @@ abstract class ApiBase extends ContextSource {
         * @return string
         */
        private function indentExampleText( $item ) {
-               return "  " . $item;
+               return '  ' . $item;
        }
 
        /**
@@ -2849,7 +2849,7 @@ abstract class ApiBase extends ContextSource {
                                if ( isset( $paramSettings[self::PARAM_REQUIRED] )
                                        && $paramSettings[self::PARAM_REQUIRED]
                                ) {
-                                       $desc .= $paramPrefix . "This parameter is required";
+                                       $desc .= $paramPrefix . 'This parameter is required';
                                }
 
                                $type = isset( $paramSettings[self::PARAM_TYPE] )
@@ -2925,7 +2925,7 @@ abstract class ApiBase extends ContextSource {
                                                                }
                                                                break;
                                                        case 'upload':
-                                                               $desc .= $paramPrefix . "Must be posted as a file upload using multipart/form-data";
+                                                               $desc .= $paramPrefix . 'Must be posted as a file upload using multipart/form-data';
                                                                break;
                                                }
                                        }
@@ -2939,8 +2939,8 @@ abstract class ApiBase extends ContextSource {
                                                if ( !$isArray
                                                        || $isArray && count( $type ) > self::LIMIT_SML1
                                                ) {
-                                                       $desc .= $paramPrefix . "Maximum number of values " .
-                                                               self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)";
+                                                       $desc .= $paramPrefix . 'Maximum number of values ' .
+                                                               self::LIMIT_SML1 . ' (' . self::LIMIT_SML2 . ' for bots)';
                                                }
                                        }
                                }
index 25407bf..8f1bd19 100644 (file)
@@ -137,7 +137,7 @@ class ApiContinuationManager {
                }
                $paramName = $module->encodeParamName( $paramName );
                if ( is_array( $paramValue ) ) {
-                       $paramValue = join( '|', $paramValue );
+                       $paramValue = implode( '|', $paramValue );
                }
                $this->continuationData[$name][$paramName] = $paramValue;
        }
@@ -152,7 +152,7 @@ class ApiContinuationManager {
                $name = $module->getModuleName();
                $paramName = $module->encodeParamName( $paramName );
                if ( is_array( $paramValue ) ) {
-                       $paramValue = join( '|', $paramValue );
+                       $paramValue = implode( '|', $paramValue );
                }
                $this->generatorContinuationData[$name][$paramName] = $paramValue;
        }
@@ -193,7 +193,7 @@ class ApiContinuationManager {
                                $data += $kvp;
                        }
                        $data += $this->generatorParams;
-                       $generatorKeys = join( '|', array_keys( $this->generatorParams ) );
+                       $generatorKeys = implode( '|', array_keys( $this->generatorParams ) );
                } elseif ( $this->generatorContinuationData ) {
                        // All the generator-using modules are complete, but the
                        // generator isn't. Continue the generator and restart the
@@ -204,7 +204,7 @@ class ApiContinuationManager {
                        }
                        $data += $generatorParams;
                        $finishedModules = array_diff( $finishedModules, $this->generatedModules );
-                       $generatorKeys = join( '|', array_keys( $generatorParams ) );
+                       $generatorKeys = implode( '|', array_keys( $generatorParams ) );
                        $batchcomplete = true;
                } else {
                        // Generator and prop modules are all done. Mark it so.
@@ -215,7 +215,7 @@ class ApiContinuationManager {
                // Set 'continue' if any continuation data is set or if the generator
                // still needs to run
                if ( $data || $generatorKeys !== '-' ) {
-                       $data['continue'] = $generatorKeys . '||' . join( '|', $finishedModules );
+                       $data['continue'] = $generatorKeys . '||' . implode( '|', $finishedModules );
                }
 
                return [ $data, $batchcomplete ];
index f32bab0..08aba94 100644 (file)
@@ -335,7 +335,7 @@ class ApiEditPage extends ApiBase {
                        $section = $params['section'];
                        if ( !preg_match( '/^((T-)?\d+|new)$/', $section ) ) {
                                $this->dieUsage( "The section parameter must be a valid section id or 'new'",
-                                       "invalidsection" );
+                                       'invalidsection' );
                        }
                        $content = $pageObj->getContent();
                        if ( $section !== '0' && $section != 'new'
index 6611a09..286fe88 100644 (file)
@@ -158,7 +158,7 @@ class ApiExpandTemplates extends ApiBase {
                                        !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
                                        $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
                                                "or 'encodedjsconfigvars'. Configuration variables are necessary " .
-                                               "for proper module usage." );
+                                               'for proper module usage.' );
                                }
                        }
                }
index dacf828..e28b068 100644 (file)
@@ -173,7 +173,7 @@ class ApiFeedContributions extends ApiBase {
 
                        return '<p>' . htmlspecialchars( $revision->getUserText() ) . $msg .
                                htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
-                               "</p>\n<hr />\n<div>" . $html . "</div>";
+                               "</p>\n<hr />\n<div>" . $html . '</div>';
                }
 
                return '';
index 7c203d9..c826bba 100644 (file)
@@ -151,7 +151,7 @@ abstract class ApiFormatBase extends ApiBase {
         * Initialize the printer function and prepare the output headers.
         * @param bool $unused Always false since 1.25
         */
-       function initPrinter( $unused = false ) {
+       public function initPrinter( $unused = false ) {
                if ( $this->mDisabled ) {
                        return;
                }
index be9b6d0..a45dbeb 100644 (file)
@@ -266,7 +266,7 @@ class ApiFormatXml extends ApiFormatBase {
                );
        }
 
-       function addXslt() {
+       protected function addXslt() {
                $nt = Title::newFromText( $this->mXslt );
                if ( is_null( $nt ) || !$nt->exists() ) {
                        $this->setWarning( 'Invalid or non-existent stylesheet specified' );
index 349a34d..f2d6329 100644 (file)
@@ -268,7 +268,7 @@ class ApiHelp extends ApiBase {
                                        'level' => $level,
                                        'anchor' => $anchor,
                                        'line' => $header,
-                                       'number' => join( '.', $tocnumber ),
+                                       'number' => implode( '.', $tocnumber ),
                                        'index' => false,
                                ];
                                if ( empty( $options['noheader'] ) ) {
@@ -618,7 +618,7 @@ class ApiHelp extends ApiBase {
                                                                        ->parse();
                                                        }
                                                        if ( $extra ) {
-                                                               $info[] = join( ' ', $extra );
+                                                               $info[] = implode( ' ', $extra );
                                                        }
                                                }
                                        }
@@ -655,7 +655,7 @@ class ApiHelp extends ApiBase {
                                        }
 
                                        if ( $description ) {
-                                               $description = join( '', $description );
+                                               $description = implode( '', $description );
                                                $description = preg_replace( '!\s*</([oud]l)>\s*<\1>\s*!', "\n", $description );
                                                $help['parameters'] .= Html::rawElement( 'dd',
                                                        [ 'class' => 'description' ], $description );
@@ -744,7 +744,7 @@ class ApiHelp extends ApiBase {
 
                        Hooks::run( 'APIHelpModifyOutput', [ $module, &$help, $suboptions, &$haveModules ] );
 
-                       $out .= join( "\n", $help );
+                       $out .= implode( "\n", $help );
                }
 
                return $out;
index b309149..2b99353 100644 (file)
@@ -111,9 +111,9 @@ class ApiImageRotate extends ApiBase {
                        $tmpFile = TempFSFile::factory( 'rotate_', $ext );
                        $dstPath = $tmpFile->getPath();
                        $err = $handler->rotate( $file, [
-                               "srcPath" => $srcPath,
-                               "dstPath" => $dstPath,
-                               "rotation" => $rotation
+                               'srcPath' => $srcPath,
+                               'dstPath' => $dstPath,
+                               'rotation' => $rotation
                        ] );
                        if ( !$err ) {
                                $comment = wfMessage(
index 8574dce..10106ff 100644 (file)
@@ -175,7 +175,7 @@ class ApiImportReporter extends ImportReporter {
         * @param array $pageInfo
         * @return void
         */
-       function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
+       public function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
                // Add a result entry
                $r = [];
 
@@ -194,7 +194,7 @@ class ApiImportReporter extends ImportReporter {
                parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
        }
 
-       function getData() {
+       public function getData() {
                return $this->mResultArr;
        }
 }
index a6e6c49..02aae06 100644 (file)
@@ -208,7 +208,6 @@ class ApiLogin extends ApiBase {
 
                        case LoginForm::THROTTLED:
                                $result['result'] = 'Throttled';
-                               $throttle = $this->getConfig()->get( 'PasswordAttemptThrottle' );
                                $result['wait'] = intval( $loginForm->mThrottleWait );
                                break;
 
index 9e56819..f09c6f2 100644 (file)
@@ -978,7 +978,7 @@ class ApiMain extends ApiBase {
                if ( $module->needsToken() === true ) {
                        throw new MWException(
                                "Module '{$module->getModuleName()}' must be updated for the new token handling. " .
-                               "See documentation for ApiBase::needsToken for details."
+                               'See documentation for ApiBase::needsToken for details.'
                        );
                }
                if ( $module->needsToken() ) {
@@ -1174,7 +1174,7 @@ class ApiMain extends ApiBase {
                                $this->dieUsageMsg( 'writerequired' );
                        } elseif ( $this->getRequest()->getHeader( 'Promise-Non-Write-API-Action' ) ) {
                                $this->dieUsage(
-                                       "Promise-Non-Write-API-Action HTTP header cannot be sent to write API modules",
+                                       'Promise-Non-Write-API-Action HTTP header cannot be sent to write API modules',
                                        'promised-nonwrite-api'
                                );
                        }
@@ -1225,7 +1225,7 @@ class ApiMain extends ApiBase {
                // If a majority of slaves are too lagged then disallow writes
                $slaveCount = wfGetLB()->getServerCount() - 1;
                if ( $numLagged >= ceil( $slaveCount / 2 ) ) {
-                       $laggedServers = join( ', ', $laggedServers );
+                       $laggedServers = implode( ', ', $laggedServers );
                        wfDebugLog(
                                'api-readonly',
                                "Api request failed as read only because the following DBs are lagged: $laggedServers"
@@ -1443,7 +1443,7 @@ class ApiMain extends ApiBase {
                $ret = $this->getRequest()->getVal( $name );
                if ( $ret === null ) {
                        if ( $this->getRequest()->getArray( $name ) !== null ) {
-                               // See bug 10262 for why we don't just join( '|', ... ) the
+                               // See bug 10262 for why we don't just implode( '|', ... ) the
                                // array.
                                $this->setWarning(
                                        "Parameter '$name' uses unsupported PHP array syntax"
@@ -1637,7 +1637,7 @@ class ApiMain extends ApiBase {
                                        'level' => $level,
                                        'anchor' => 'main/datatypes',
                                        'line' => $header,
-                                       'number' => join( '.', $tocnumber ),
+                                       'number' => implode( '.', $tocnumber ),
                                        'index' => false,
                                ];
                        }
@@ -1656,7 +1656,7 @@ class ApiMain extends ApiBase {
                                        'level' => $level,
                                        'anchor' => 'main/credits',
                                        'line' => $header,
-                                       'number' => join( '.', $tocnumber ),
+                                       'number' => implode( '.', $tocnumber ),
                                        'index' => false,
                                ];
                        }
@@ -1771,7 +1771,7 @@ class ApiMain extends ApiBase {
                                ->inLanguage( 'en' )
                                ->text();
                        $groups = User::getGroupsWithPermission( $right );
-                       $msg .= "* " . $right . " *\n  $rightsMsg" .
+                       $msg .= '* ' . $right . " *\n  $rightsMsg" .
                                "\nGranted to:\n  " . str_replace( '*', 'all', implode( ', ', $groups ) ) . "\n\n";
                }
 
index 304b2d6..effa520 100644 (file)
@@ -358,7 +358,7 @@ class ApiOpenSearch extends ApiBase {
 
                $ns = implode( '|', SearchEngine::defaultNamespaces() );
                if ( !$ns ) {
-                       $ns = "0";
+                       $ns = '0';
                }
 
                switch ( $type ) {
index 1dde9c2..e51d46d 100644 (file)
@@ -99,19 +99,19 @@ class ApiOptions extends ApiBase {
                                case 'userjs':
                                        // Allow non-default preferences prefixed with 'userjs-', to be set by user scripts
                                        if ( strlen( $key ) > 255 ) {
-                                               $validation = "key too long (no more than 255 bytes allowed)";
-                                       } elseif ( preg_match( "/[^a-zA-Z0-9_-]/", $key ) !== 0 ) {
-                                               $validation = "invalid key (only a-z, A-Z, 0-9, _, - allowed)";
+                                               $validation = 'key too long (no more than 255 bytes allowed)';
+                                       } elseif ( preg_match( '/[^a-zA-Z0-9_-]/', $key ) !== 0 ) {
+                                               $validation = 'invalid key (only a-z, A-Z, 0-9, _, - allowed)';
                                        } else {
                                                $validation = true;
                                        }
                                        break;
                                case 'special':
-                                       $validation = "cannot be set by this module";
+                                       $validation = 'cannot be set by this module';
                                        break;
                                case 'unused':
                                default:
-                                       $validation = "not a valid preference";
+                                       $validation = 'not a valid preference';
                                        break;
                        }
                        if ( $validation === true ) {
index 1441a45..6bab762 100644 (file)
@@ -595,22 +595,22 @@ class ApiPageSet extends ApiBase {
                'special', 'missingIds', 'missingRevIds', 'missingTitles', 'interwikiTitles' ]
        ) {
                $result = [];
-               if ( in_array( "invalidTitles", $invalidChecks ) ) {
+               if ( in_array( 'invalidTitles', $invalidChecks ) ) {
                        self::addValues( $result, $this->getInvalidTitlesAndReasons(), 'invalid' );
                }
-               if ( in_array( "special", $invalidChecks ) ) {
+               if ( in_array( 'special', $invalidChecks ) ) {
                        self::addValues( $result, $this->getSpecialTitles(), 'special', 'title' );
                }
-               if ( in_array( "missingIds", $invalidChecks ) ) {
+               if ( in_array( 'missingIds', $invalidChecks ) ) {
                        self::addValues( $result, $this->getMissingPageIDs(), 'missing', 'pageid' );
                }
-               if ( in_array( "missingRevIds", $invalidChecks ) ) {
+               if ( in_array( 'missingRevIds', $invalidChecks ) ) {
                        self::addValues( $result, $this->getMissingRevisionIDs(), 'missing', 'revid' );
                }
-               if ( in_array( "missingTitles", $invalidChecks ) ) {
+               if ( in_array( 'missingTitles', $invalidChecks ) ) {
                        self::addValues( $result, $this->getMissingTitles(), 'missing' );
                }
-               if ( in_array( "interwikiTitles", $invalidChecks ) ) {
+               if ( in_array( 'interwikiTitles', $invalidChecks ) ) {
                        self::addValues( $result, $this->getInterwikiTitlesAsResult() );
                }
 
index 6e44f82..c3c9e21 100644 (file)
@@ -137,7 +137,7 @@ class ApiParamInfo extends ApiBase {
                                foreach ( $msgs as $m ) {
                                        $ret[] = $m->setContext( $this->context )->text();
                                }
-                               $res[$key] = join( "\n\n", $ret );
+                               $res[$key] = implode( "\n\n", $ret );
                                if ( $joinLists ) {
                                        $res[$key] = preg_replace( '!^(([*#:;])[^\n]*)\n\n(?=\2)!m', "$1\n", $res[$key] );
                                }
@@ -148,7 +148,7 @@ class ApiParamInfo extends ApiBase {
                                foreach ( $msgs as $m ) {
                                        $ret[] = $m->setContext( $this->context )->parseAsBlock();
                                }
-                               $ret = join( "\n", $ret );
+                               $ret = implode( "\n", $ret );
                                if ( $joinLists ) {
                                        $ret = preg_replace( '!\s*</([oud]l)>\s*<\1>\s*!', "\n", $ret );
                                }
index 872876d..fe418e3 100644 (file)
@@ -72,7 +72,7 @@ class ApiParse extends ApiBase {
                        $this->section = $params['section'];
                        if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
                                $this->dieUsage(
-                                       "The section parameter must be a valid section id or 'new'", "invalidsection"
+                                       'The section parameter must be a valid section id or "new"', 'invalidsection'
                                );
                        }
                } else {
@@ -275,7 +275,7 @@ class ApiParse extends ApiBase {
                $result_array = [];
 
                $result_array['title'] = $titleObj->getPrefixedText();
-               $result_array['pageid'] = $pageid ? $pageid : $pageObj->getId();
+               $result_array['pageid'] = $pageid ?: $pageObj->getId();
 
                if ( !is_null( $oldid ) ) {
                        $result_array['revid'] = intval( $oldid );
@@ -341,8 +341,7 @@ class ApiParse extends ApiBase {
                }
 
                if ( isset( $prop['displaytitle'] ) ) {
-                       $result_array['displaytitle'] = $p_result->getDisplayTitle() ?
-                               $p_result->getDisplayTitle() :
+                       $result_array['displaytitle'] = $p_result->getDisplayTitle() ?:
                                $titleObj->getPrefixedText();
                }
 
@@ -390,9 +389,9 @@ class ApiParse extends ApiBase {
 
                if ( isset( $prop['modules'] ) &&
                        !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
-                       $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
-                               "or 'encodedjsconfigvars'. Configuration variables are necessary " .
-                               "for proper module usage." );
+                       $this->setWarning( 'Property "modules" was set but not "jsconfigvars" ' .
+                               'or "encodedjsconfigvars". Configuration variables are necessary ' .
+                               'for proper module usage.' );
                }
 
                if ( isset( $prop['indicators'] ) ) {
@@ -428,7 +427,7 @@ class ApiParse extends ApiBase {
 
                if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
                        if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
-                               $this->dieUsage( "parsetree is only supported for wikitext content", "notwikitext" );
+                               $this->dieUsage( 'parsetree is only supported for wikitext content', 'notwikitext' );
                        }
 
                        $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
@@ -545,10 +544,10 @@ class ApiParse extends ApiBase {
                // Not cached (save or load)
                $section = $content->getSection( $this->section );
                if ( $section === false ) {
-                       $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
+                       $this->dieUsage( "There is no section {$this->section} in $what", 'nosuchsection' );
                }
                if ( $section === null ) {
-                       $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
+                       $this->dieUsage( "Sections are not supported by $what", 'nosuchsection' );
                        $section = false;
                }
 
index 58b670a..4336907 100644 (file)
@@ -185,33 +185,6 @@ class ApiQuery extends ApiBase {
                return $this->mPageSet;
        }
 
-       /**
-        * Get the generators array mapping module names to class names
-        * @deprecated since 1.21, list of generators is maintained by ApiPageSet
-        * @return array Array(modulename => classname)
-        */
-       public function getGenerators() {
-               wfDeprecated( __METHOD__, '1.21' );
-               $gens = [];
-               foreach ( $this->mModuleMgr->getNamesWithClasses() as $name => $class ) {
-                       if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
-                               $gens[$name] = $class;
-                       }
-               }
-
-               return $gens;
-       }
-
-       /**
-        * Get whether the specified module is a prop, list or a meta query module
-        * @deprecated since 1.21, use getModuleManager()->getModuleGroup()
-        * @param string $moduleName Name of the module to find type for
-        * @return string|null
-        */
-       function getModuleType( $moduleName ) {
-               return $this->getModuleManager()->getModuleGroup( $moduleName );
-       }
-
        /**
         * @return ApiFormatRaw|null
         */
@@ -451,22 +424,6 @@ class ApiQuery extends ApiBase {
                }
        }
 
-       /**
-        * This method is called by the generator base when generator in the smart-continue
-        * mode tries to set 'query-continue' value. ApiQuery stores those values separately
-        * until the post-processing when it is known if the generation should continue or repeat.
-        * @deprecated since 1.24
-        * @param ApiQueryGeneratorBase $module Generator module
-        * @param string $paramName
-        * @param mixed $paramValue
-        * @return bool True if processed, false if this is a legacy continue
-        */
-       public function setGeneratorContinue( $module, $paramName, $paramValue ) {
-               wfDeprecated( __METHOD__, '1.24' );
-               $this->getContinuationManager()->addGeneratorContinueParam( $module, $paramName, $paramValue );
-               return !$this->getParameter( 'rawcontinue' );
-       }
-
        /**
         * @param ApiPageSet $pageSet Pages to be exported
         * @param ApiResult $result Result to output to
index 94707da..ac90605 100644 (file)
@@ -117,7 +117,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
                        if ( $matches ) {
                                $p = $this->getModulePrefix();
                                $this->dieUsage(
-                                       "Cannot use {$p}prop=" . join( '|', array_keys( $matches ) ) . " with {$p}unique",
+                                       "Cannot use {$p}prop=" . implode( '|', array_keys( $matches ) ) . " with {$p}unique",
                                        'params'
                                );
                        }
index 97b122a..fb502e4 100644 (file)
@@ -296,7 +296,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
                                // Note we must keep the parameters for the first query constant
                                // This may be overridden at a later step
                                $title = $row->{$this->bl_title};
-                               $this->continueStr = join( '|', array_slice( $this->cont, 0, 2 ) ) .
+                               $this->continueStr = implode( '|', array_slice( $this->cont, 0, 2 ) ) .
                                        "|$ns|$title|{$row->from_ns}|{$row->page_id}";
                                break;
                        }
@@ -451,7 +451,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
                                                [ 'query', $this->getModuleName() ],
                                                $idx, array_diff_key( $arr, [ 'redirlinks' => '' ] ) );
                                        if ( !$fit ) {
-                                               $this->continueStr = join( '|', array_slice( $this->cont, 0, 6 ) ) .
+                                               $this->continueStr = implode( '|', array_slice( $this->cont, 0, 6 ) ) .
                                                        "|$pageID";
                                                break;
                                        }
@@ -474,7 +474,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
                                                        [ 'query', $this->getModuleName(), $idx, 'redirlinks' ],
                                                        null, $redir );
                                                if ( !$fit ) {
-                                                       $this->continueStr = join( '|', array_slice( $this->cont, 0, 6 ) ) .
+                                                       $this->continueStr = implode( '|', array_slice( $this->cont, 0, 6 ) ) .
                                                                "|$pageID|$key";
                                                        break;
                                                }
index 17b51da..3810e90 100644 (file)
@@ -164,22 +164,14 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                        $this->dieContinueUsageIf( count( $cont ) != count( $sortby ) );
                        $where = '';
                        $i = count( $sortby ) - 1;
-                       $cont_ns = 0;
-                       $cont_title = '';
                        foreach ( array_reverse( $sortby, true ) as $field => $type ) {
                                $v = $cont[$i];
                                switch ( $type ) {
                                        case 'ns':
-                                               $cont_ns = (int)$v;
-                                               /* fall through */
                                        case 'int':
                                                $v = (int)$v;
                                                $this->dieContinueUsageIf( $v != $cont[$i] );
                                                break;
-
-                                       case 'title':
-                                               $cont_title = $v;
-                                               /* fall through */
                                        default:
                                                $v = $db->addQuotes( $v );
                                                break;
@@ -321,7 +313,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                foreach ( $sortby as $field => $v ) {
                        $cont[] = $row->$field;
                }
-               $this->setContinueEnumParameter( 'continue', join( '|', $cont ) );
+               $this->setContinueEnumParameter( 'continue', implode( '|', $cont ) );
        }
 
        public function getCacheMode( $params ) {
index 7848bc8..c491236 100644 (file)
@@ -78,7 +78,7 @@ class ApiQueryFileRepoInfo extends ApiQueryBase {
 
                return [
                        'prop' => [
-                               ApiBase::PARAM_DFLT => join( '|', $props ),
+                               ApiBase::PARAM_DFLT => implode( '|', $props ),
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => $props,
                        ],
index 6890046..ab94574 100644 (file)
@@ -308,7 +308,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
 
                foreach ( $paramList as $name => $value ) {
                        if ( !$h->validateParam( $name, $value ) ) {
-                               $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", "urlparam" );
+                               $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", 'urlparam' );
                        }
                }
 
@@ -357,7 +357,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
         *    'revdelUser': User to use when checking whether to show revision-deleted fields.
         * @return array Result array
         */
-       static function getInfo( $file, $prop, $result, $thumbParams = null, $opts = false ) {
+       public static function getInfo( $file, $prop, $result, $thumbParams = null, $opts = false ) {
                global $wgContLang;
 
                $anyHidden = false;
index c12393d..266d699 100644 (file)
@@ -294,9 +294,9 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                        $vals['parsetree'] = $xml;
                                } else {
                                        $vals['badcontentformatforparsetree'] = true;
-                                       $this->setWarning( "Conversion to XML is supported for wikitext only, " .
+                                       $this->setWarning( 'Conversion to XML is supported for wikitext only, ' .
                                                $title->getPrefixedDBkey() .
-                                               " uses content model " . $content->getModel() );
+                                               ' uses content model ' . $content->getModel() );
                                }
                        }
                }
@@ -315,9 +315,9 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                                ParserOptions::newFromContext( $this->getContext() )
                                        );
                                } else {
-                                       $this->setWarning( "Template expansion is supported for wikitext only, " .
+                                       $this->setWarning( 'Template expansion is supported for wikitext only, ' .
                                                $title->getPrefixedDBkey() .
-                                               " uses content model " . $content->getModel() );
+                                               ' uses content model ' . $content->getModel() );
                                        $vals['badcontentformat'] = true;
                                        $text = false;
                                }
@@ -332,7 +332,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        }
 
                        if ( $text === null ) {
-                               $format = $this->contentFormat ? $this->contentFormat : $content->getDefaultFormat();
+                               $format = $this->contentFormat ?: $content->getDefaultFormat();
                                $model = $content->getModel();
 
                                if ( !$content->isSupportedFormat( $format ) ) {
index 4befad6..f05556e 100644 (file)
@@ -652,8 +652,8 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                }
 
                $data = [
-                       'url' => $url ? $url : '',
-                       'text' => $text ? $text : ''
+                       'url' => $url ?: '',
+                       'text' => $text ?: ''
                ];
 
                return $this->getResult()->addValue( 'query', $property, $data );
index 51f4862..6d1540b 100644 (file)
@@ -42,7 +42,7 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
                $result = $this->getResult();
 
                if ( !$params['filekey'] && !$params['sessionkey'] ) {
-                       $this->dieUsage( "One of filekey or sessionkey must be supplied", 'nofilekey' );
+                       $this->dieUsage( 'One of filekey or sessionkey must be supplied', 'nofilekey' );
                }
 
                // Alias sessionkey to filekey, but give an existing filekey precedence.
@@ -62,9 +62,9 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
                        }
                // @todo Update exception handling here to understand current getFile exceptions
                } catch ( UploadStashFileNotFoundException $e ) {
-                       $this->dieUsage( "File not found: " . $e->getMessage(), "invalidsessiondata" );
+                       $this->dieUsage( 'File not found: ' . $e->getMessage(), 'invalidsessiondata' );
                } catch ( UploadStashBadPathException $e ) {
-                       $this->dieUsage( "Bad path: " . $e->getMessage(), "invalidsessiondata" );
+                       $this->dieUsage( 'Bad path: ' . $e->getMessage(), 'invalidsessiondata' );
                }
        }
 
index f70bbe7..3436320 100644 (file)
@@ -312,7 +312,7 @@ class ApiResult implements ApiSerializable {
                        if ( !$conflicts ) {
                                $arr[$name] += $value;
                        } else {
-                               $keys = join( ', ', array_keys( $conflicts ) );
+                               $keys = implode( ', ', array_keys( $conflicts ) );
                                throw new RuntimeException(
                                        "Conflicting keys ($keys) when attempting to merge element $name"
                                );
@@ -340,7 +340,7 @@ class ApiResult implements ApiSerializable {
                                $value = $value->serializeForApiResult();
                                if ( is_object( $value ) ) {
                                        throw new UnexpectedValueException(
-                                               get_class( $oldValue ) . "::serializeForApiResult() returned an object of class " .
+                                               get_class( $oldValue ) . '::serializeForApiResult() returned an object of class ' .
                                                        get_class( $value )
                                        );
                                }
@@ -351,7 +351,7 @@ class ApiResult implements ApiSerializable {
                                        return self::validateValue( $value );
                                } catch ( Exception $ex ) {
                                        throw new UnexpectedValueException(
-                                               get_class( $oldValue ) . "::serializeForApiResult() returned an invalid value: " .
+                                               get_class( $oldValue ) . '::serializeForApiResult() returned an invalid value: ' .
                                                        $ex->getMessage(),
                                                0,
                                                $ex
@@ -372,7 +372,7 @@ class ApiResult implements ApiSerializable {
                        }
                        $value = $tmp;
                } elseif ( is_float( $value ) && !is_finite( $value ) ) {
-                       throw new InvalidArgumentException( "Cannot add non-finite floats to ApiResult" );
+                       throw new InvalidArgumentException( 'Cannot add non-finite floats to ApiResult' );
                } elseif ( is_string( $value ) ) {
                        $value = $wgContLang->normalize( $value );
                } elseif ( $value !== null && !is_scalar( $value ) ) {
@@ -538,7 +538,7 @@ class ApiResult implements ApiSerializable {
                ) {
                        throw new RuntimeException(
                                "Attempting to set content element as $name when " . $arr[self::META_CONTENT] .
-                                       " is already set as the content element"
+                                       ' is already set as the content element'
                        );
                }
                $arr[self::META_CONTENT] = $name;
@@ -1132,12 +1132,12 @@ class ApiResult implements ApiSerializable {
                                                $tmp = [];
                                                return $tmp;
                                        default:
-                                               $fail = join( '.', array_slice( $path, 0, $i + 1 ) );
+                                               $fail = implode( '.', array_slice( $path, 0, $i + 1 ) );
                                                throw new InvalidArgumentException( "Path $fail does not exist" );
                                }
                        }
                        if ( !is_array( $ret[$k] ) ) {
-                               $fail = join( '.', array_slice( $path, 0, $i + 1 ) );
+                               $fail = implode( '.', array_slice( $path, 0, $i + 1 ) );
                                throw new InvalidArgumentException( "Path $fail is not an array" );
                        }
                        $ret = &$ret[$k];
index d8562b0..3c02c9c 100644 (file)
@@ -50,7 +50,7 @@ class ApiStashEdit extends ApiBase {
                if ( !ContentHandler::getForModelID( $params['contentmodel'] )
                        ->isSupportedFormat( $params['contentformat'] )
                ) {
-                       $this->dieUsage( "Unsupported content model/format", 'badmodelformat' );
+                       $this->dieUsage( 'Unsupported content model/format', 'badmodelformat' );
                }
 
                // Trim and fix newlines so the key SHA1's match (see RequestContext::getText())
@@ -77,7 +77,7 @@ class ApiStashEdit extends ApiBase {
                                $baseRev->getId()
                        );
                        if ( !$editContent ) {
-                               $this->dieUsage( "Could not merge updated section.", 'replacefailed' );
+                               $this->dieUsage( 'Could not merge updated section.', 'replacefailed' );
                        }
                        if ( $currentRev->getId() == $baseRev->getId() ) {
                                // Base revision was still the latest; nothing to merge
@@ -433,19 +433,19 @@ class ApiStashEdit extends ApiBase {
                ];
        }
 
-       function needsToken() {
+       public function needsToken() {
                return 'csrf';
        }
 
-       function mustBePosted() {
+       public function mustBePosted() {
                return true;
        }
 
-       function isWriteMode() {
+       public function isWriteMode() {
                return true;
        }
 
-       function isInternal() {
+       public function isInternal() {
                return true;
        }
 }
index 63bae9d..4940394 100644 (file)
@@ -32,9 +32,9 @@ class ApiTokens extends ApiBase {
 
        public function execute() {
                $this->setWarning(
-                       "action=tokens has been deprecated. Please use action=query&meta=tokens instead."
+                       'action=tokens has been deprecated. Please use action=query&meta=tokens instead.'
                );
-               $this->logFeatureUsage( "action=tokens" );
+               $this->logFeatureUsage( 'action=tokens' );
 
                $params = $this->extractRequestParams();
                $res = [
index 79e88c6..326f8ba 100644 (file)
@@ -542,9 +542,9 @@ class ApiUpload extends ApiBase {
                                ];
                                ApiResult::setIndexedTagName( $extradata['allowed'], 'ext' );
 
-                               $msg = "Filetype not permitted: ";
+                               $msg = 'Filetype not permitted: ';
                                if ( isset( $verification['blacklistedExt'] ) ) {
-                                       $msg .= join( ', ', $verification['blacklistedExt'] );
+                                       $msg .= implode( ', ', $verification['blacklistedExt'] );
                                        $extradata['blacklisted'] = array_values( $verification['blacklistedExt'] );
                                        ApiResult::setIndexedTagName( $extradata['blacklisted'], 'ext' );
                                } else {
@@ -664,7 +664,7 @@ class ApiUpload extends ApiBase {
                                $this->dieUsage( 'No such filekey: ' . $e->getMessage(), 'stashnosuchfilekey' );
                                break;
                        default:
-                               $this->dieUsage( $exceptionType . ": " . $e->getMessage(), 'stasherror' );
+                               $this->dieUsage( $exceptionType . ': ' . $e->getMessage(), 'stasherror' );
                                break;
                }
        }
@@ -714,7 +714,7 @@ class ApiUpload extends ApiBase {
                if ( $this->mParams['async'] ) {
                        $progress = UploadBase::getSessionStatus( $this->getUser(), $this->mParams['filekey'] );
                        if ( $progress && $progress['result'] === 'Poll' ) {
-                               $this->dieUsage( "Upload from stash already in progress.", 'publishfailed' );
+                               $this->dieUsage( 'Upload from stash already in progress.', 'publishfailed' );
                        }
                        UploadBase::setSessionStatus(
                                $this->getUser(),
index 4e5e000..f09fdcb 100644 (file)
@@ -80,7 +80,7 @@ class ApiWatch extends ApiBase {
                        if ( $extraParams ) {
                                $p = $this->getModulePrefix();
                                $this->dieUsage(
-                                       "The parameter {$p}title can not be used with " . implode( ", ", $extraParams ),
+                                       "The parameter {$p}title can not be used with " . implode( ', ', $extraParams ),
                                        'invalidparammix'
                                );
                        }
index caa5aaf..6841ab7 100644 (file)
        "apihelp-patrol-description": "Patrullar unha páxina ou edición.",
        "apihelp-patrol-param-rcid": "ID de modificación recente a vixiar.",
        "apihelp-patrol-param-revid": "ID de revisión a vixiar.",
+       "apihelp-patrol-param-tags": "Cambiar as etiquetas a aplicar na entrada do rexistro de patrullas.",
        "apihelp-patrol-example-rcid": "Patrullar un cambio recente",
        "apihelp-patrol-example-revid": "Patrullar unha revisión",
        "apihelp-protect-description": "Cambiar o nivel de protección dunha páxina.",
        "apihelp-protect-param-protections": "Lista dos niveis de protección, con formato <kbd>action=level</kbd> (p.ex. <kbd>edit=sysop</kbd>).\n\n<strong>Nota:</strong> Todas as accións que non estean listadas terán restriccións para ser eliminadas.",
        "apihelp-protect-param-expiry": "Selos de tempo de caducidade. Se só se indica un selo de tempo, usarase para todas as proteccións. Use <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, ou <kbd>never</kbd>, para unha protección sen caducidade.",
        "apihelp-protect-param-reason": "Razón para (des)protexer.",
+       "apihelp-protect-param-tags": "Cambiar as etiquetas a aplicar na entrada do rexistro de protección.",
        "apihelp-protect-param-cascade": "Activar a protección en cascada (por exemplo, protexer os modelos transcluídos e as imaxes usadas nesta páxina). Ignórase se ningún dos niveis de protección soporta a protección en cascada.",
        "apihelp-protect-param-watch": "Se se define este parámetro, engadir a páxina que se (des)protexe á lista de vixilancia do usuario actual.",
        "apihelp-protect-param-watchlist": "Engadir ou eliminar sen condicións a páxina da lista de vixiancia do usuario actual, use as preferencias ou non cambie a vixiancia.",
        "apihelp-unblock-param-id": "ID do bloque a desbloquear (obtido de <kbd>list=blocks</kbd>). Non pode usarse xunto con <var>$1user</var>.",
        "apihelp-unblock-param-user": "Nome de usuario, dirección IP ou rango de direccións IP a desbloquear. Non pode usarse xunto con <var>$1id</var>.",
        "apihelp-unblock-param-reason": "Razón para desbloquear.",
+       "apihelp-unblock-param-tags": "Cambiar as etiquetas a aplicar na entrada do rexistro de bloqueo.",
        "apihelp-unblock-example-id": "Desbloquear bloqueo ID #<kbd>105</kbd>.",
        "apihelp-unblock-example-user": "Desbloquear usuario <kbd>Bob</kbd> con razón <kbd>Síntoo Bob</kbd>.",
        "apihelp-undelete-description": "Restaurar modificacións dunha páxina borrada.\n\nUnha lista de modificacións borradas (incluíndo os seus selos de tempo) pode consultarse a través de [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], e unha lista de IDs de ficheiros borrados pode consultarse a través de [[Special:ApiHelp/query+filearchive|list=filearchive]].",
        "apihelp-undelete-param-title": "Título da páxina a restaurar.",
        "apihelp-undelete-param-reason": "Razón para restaurar.",
+       "apihelp-undelete-param-tags": "Cambiar as etiquetas a aplicar na entrada do rexistro de borrado.",
        "apihelp-undelete-param-timestamps": "Selos de tempo das modificacións a restaurar. Se <var>$1timestamps</var> e <var>$1fileids</var> están baleiras, restaurarase todo.",
        "apihelp-undelete-param-fileids": "IDs das modificacións de ficheiro a restaurar. Se <var>$1timestamps</var> e <var>$1fileids</var> están baleiras, serán restauradas todas.",
        "apihelp-undelete-param-watchlist": "Engadir ou eliminar a páxina da lista de vixiancia do usuario actual sen condicións, use as preferencias ou non cambie a vixiancia.",
index ae4c71a..927509c 100644 (file)
        "apihelp-parse-example-text": "Analizza wikitext.",
        "apihelp-parse-example-texttitle": "Analizza wikitext, specificando il titolo della pagina.",
        "apihelp-parse-example-summary": "Analizza un oggetto.",
+       "apihelp-patrol-param-tags": "Modifica etichette da applicare all'elemento del registro delle verifiche.",
+       "apihelp-protect-param-tags": "Modifica etichette da applicare all'elemento del registro delle protezioni.",
        "apihelp-protect-example-protect": "Proteggi una pagina.",
        "apihelp-query-param-export": "Esporta la versione attuale di tutte le pagine ottenute o generate.",
        "apihelp-query+allcategories-param-dir": "Direzione dell'ordinamento.",
        "apihelp-tokens-param-type": "Tipi di token da richiedere.",
        "apihelp-tokens-example-edit": "Recupera un token di modifica (il predefinito).",
        "apihelp-unblock-description": "Sblocca un utente",
+       "apihelp-unblock-param-tags": "Modifica etichette da applicare all'elemento del registro dei blocchi.",
        "apihelp-undelete-param-title": "Titolo della pagina da ripristinare.",
+       "apihelp-undelete-param-tags": "Modifica etichette da applicare all'elemento del registro delle cancellazioni.",
        "apihelp-upload-example-url": "Carica da un URL.",
        "apihelp-userrights-param-user": "Nome utente.",
        "apihelp-userrights-param-userid": "ID utente.",
index ef97535..04a7554 100644 (file)
        "apihelp-paraminfo-param-querymodules": "クエリモジュール名のリスト (<var>prop</var>, <var>meta</var> or <var>list</var> パラメータの値)。<kbd>$1querymodules=foo</kbd> の代わりに <kbd>$1modules=query+foo</kbd> を使用してください。",
        "apihelp-paraminfo-example-1": "<kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>, and <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> に関する情報を表示する。",
        "apihelp-parse-param-summary": "構文解析のための要約",
+       "apihelp-parse-param-page": "このページの内容を構文解析します。<var>$1text</var> および <var>$1title</var> とは同時に使用できません。",
        "apihelp-parse-param-redirects": "もし <var>$1page</var> や <var>$1pageid</var> に転送ページが指定された場合、それを解決する。",
        "apihelp-parse-param-prop": "どの情報を取得するか:",
        "apihelp-parse-paramvalue-prop-text": "ウィキテキストの解析されたテキストを提供します。",
        "apihelp-parse-example-page": "ページをパース",
        "apihelp-parse-example-text": "ウィキテキストをパース",
        "apihelp-parse-example-summary": "要約を構文解析します。",
-       "apihelp-patrol-description": "ã\83\9aã\83¼ã\82¸ã\81¾ã\81\9fã\81¯ç\89\88ã\82\92å·¡å\9b\9eæ¸\88ã\81¿ã\81«ã\81\97ã\81¾ã\81\99。",
+       "apihelp-patrol-description": "ã\83\9aã\83¼ã\82¸ã\81¾ã\81\9fã\81¯ç\89\88ã\82\92å·¡å\9b\9eæ¸\88ã\81¿ã\81«ã\81\99ã\82\8b。",
        "apihelp-patrol-param-rcid": "巡回済みにする最近の更新ID。",
        "apihelp-patrol-param-revid": "巡回済みにする版ID。",
+       "apihelp-patrol-param-tags": "巡回記録の項目に適用する変更タグ。",
        "apihelp-patrol-example-rcid": "最近の更新を巡回",
        "apihelp-patrol-example-revid": "版を巡回済みにする。",
        "apihelp-protect-description": "ページの保護レベルを変更します。",
        "apihelp-protect-param-protections": "<kbd>action=level</kbd> の形式 (例えば、<kbd>edit=sysop</kbd>) で整形された、保護レベルの一覧。\n\n<strong>注意: </strong> ここに列挙されなかった操作の制限は解除されます。",
        "apihelp-protect-param-expiry": "有効期限です。タイムスタンプがひとつだけ指定された場合は、それがすべての保護に適用されます。無期限の保護を行う場合は<kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, または <kbd>never</kbd> を指定します。",
        "apihelp-protect-param-reason": "保護(解除)の理由。",
+       "apihelp-protect-param-tags": "保護記録の項目に適用する変更タグ。",
        "apihelp-protect-param-watch": "指定されると、保護(解除)するページが現在の利用者のウォッチリストに追加されます。",
        "apihelp-protect-example-protect": "ページを保護する。",
        "apihelp-protect-example-unprotect": "制限値を <kbd>all</kbd> にしてページの保護を解除する。",
        "apihelp-query+deletedrevs-param-excludeuser": "この利用者による版を一覧表示しない。",
        "apihelp-query+deletedrevs-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
        "apihelp-query+deletedrevs-param-limit": "一覧表示する版の最大量。",
+       "apihelp-query+deletedrevs-param-prop": "どの情報を取得するか:\n;revid:削除された版の版IDを追加します。\n;parentid:ページの前の版の版IDを追加します。\n;user:版を作成した利用者を追加します。\n;userid:版を作成した利用者のIDを追加します。\n;comment:版のコメントを追加します。\n;parsedcomment:版のコメントを構文解析して追加します。\n;minor:版が細部の編集かどうか印をつけます。\n;len:版の長さ (バイト) を追加します。\n;sha1:版のSHA-1 (base 16) を追加します。\n;content:版の内容を追加します。\n;token:<span class=\"apihelp-deprecated\">廃止予定です。</span>編集トークンを返します。\n;tags:版のタグです。",
        "apihelp-query+deletedrevs-example-mode1": "ページ <kbd>Main Page</kbd> および <kbd>Talk:Main Page</kbd> の最後に削除された版を内容と共に一覧表示する(モード 1)。",
        "apihelp-query+deletedrevs-example-mode2": "<kbd>Bob</kbd> による、削除された最後の50投稿を一覧表示する(モード 2)。",
        "apihelp-query+deletedrevs-example-mode3-main": "標準名前空間にある削除された最初の50版を一覧表示する(モード 3)。",
        "apihelp-unblock-param-id": "解除するブロックのID (<kbd>list=blocks</kbd>で取得できます)。<var>$1user</var> とは同時に使用できません。",
        "apihelp-unblock-param-user": "ブロックを解除する利用者名、IPアドレスまたはIPレンジ。<var>$1id</var>とは同時に使用できません。",
        "apihelp-unblock-param-reason": "ブロック解除の理由。",
+       "apihelp-unblock-param-tags": "ブロック記録の項目に適用する変更タグ。",
        "apihelp-unblock-example-id": "ブロックID #<kbd>105</kbd> を解除する。",
        "apihelp-unblock-example-user": "<kbd>Sorry Bob</kbd> という理由で利用者 <kbd>Bob</kbd> のブロックを解除する。",
        "apihelp-undelete-description": "削除されたページの版を復元します。\n\n削除された版の一覧 (タイムスタンプを含む) は[[Special:ApiHelp/query+deletedrevs|list=deletedrevs]]に、また削除されたファイルのID一覧は[[Special:ApiHelp/query+filearchive|list=filearchive]]で見つけることができます。",
        "apihelp-undelete-param-title": "復元するページ名。",
        "apihelp-undelete-param-reason": "復元の理由。",
+       "apihelp-undelete-param-tags": "削除記録の項目に適用する変更タグ。",
        "apihelp-undelete-param-timestamps": "復元する版のタイムスタンプ。<var>$1timestamps</var> と <var>$1fileids</var> の両方が空の場合、すべての版が復元されます。",
        "apihelp-undelete-example-page": "<kbd>Main Page</kbd> を復元する。",
        "apihelp-undelete-example-revisions": "<kbd>Main Page</kbd> の2つの版を復元する。",
index 5ad108b..da676a1 100644 (file)
@@ -4,6 +4,13 @@
                        "Zygimantus"
                ]
        },
+       "apihelp-createaccount-param-name": "Naudotojo vardas.",
+       "apihelp-createaccount-param-realname": "Vardas (nebūtina).",
+       "apihelp-delete-description": "Ištrinti puslapį.",
+       "apihelp-edit-param-text": "Puslapio turinys.",
+       "apihelp-emailuser-description": "Siųsti el. laišką naudotojui.",
+       "apihelp-expandtemplates-param-title": "Puslapio pavadinimas.",
+       "apihelp-feedrecentchanges-example-simple": "Parodyti naujausius keitimus.",
        "apihelp-query+alldeletedrevisions-example-user": "Sąrašas paskutinių 50 ištrintų indėlių pagal vartotoją\n<kbd>Pavyzdys</kbd>.",
        "apihelp-query+allrevisions-param-namespace": "Rodyti puslapius tik šioje vardų srityje.",
        "apihelp-query+backlinks-example-simple": "Rodyti nuorodas <kbd>Pagrindinis puslapis</kbd>.",
index 1991ea9..a43d840 100644 (file)
        "apihelp-createaccount-param-mailpassword": "Si mpustato a qualunque valore, na password casuale sarrà mannat'a ll'utente.",
        "apihelp-createaccount-param-reason": "Raggiona, a facoltativa, d' 'a criaziona 'e nu cunto a mpizzà int' 'e reggistre.",
        "apihelp-createaccount-param-language": "Codece 'e llengua a mpustà comme predefinita pe' n'utente (opzionale, 'e default fosse 'a lengue d' 'e cuntenute).",
+       "apihelp-createaccount-example-pass": "Crèa utente <kbd>testuser</kbd> c' 'a password <kbd>test123</kbd>.",
+       "apihelp-createaccount-example-mail": "Crea utente <kbd>testmailuser</kbd> e manna na mail cu na password criat' 'a ccaso.",
        "apihelp-delete-description": "Scancella 'na paggena.",
+       "apihelp-delete-param-title": "Titolo d' 'a paggena a scancellà. Nun se pò ausà nziem'a <var>$1pageid</var>.",
+       "apihelp-delete-param-pageid": "ID d' 'a paggena a scancellà. Nun se pò ausà nziem'a <var>$1title</var>.",
+       "apihelp-delete-param-reason": "Raggione p' 'o scancellà. Si nun s'è mpustato, na raggione generata automaticamente s'add'ausà.",
+       "apihelp-delete-param-tags": "Càgna 'e tag pe' puté apprecà l'entrata dint' 'o riggistro 'e scancellazione.",
        "apihelp-delete-param-watch": "Azzecc' 'a paggena â lista 'e paggene cuntrullate.",
        "apihelp-delete-param-watchlist": "Senza condizione, azzeccà o luvà 'a paggena 'a l'elenco 'e paggene cuntrullate 'e ll'utente, ausà mpustaziune o nun 'o cagnà l'elenco.",
        "apihelp-delete-param-unwatch": "Liev' 'a paggena â lista 'e paggene cuntrullate.",
        "apihelp-delete-example-reason": "Scancella 'a <kbd>Main Page</kbd> c' 'o mutivo <kbd>Preparing for move</kbd>.",
        "apihelp-disabled-description": "Stu modulo è stato stutato.",
        "apihelp-edit-description": "Crèa e cagna paggene.",
+       "apihelp-edit-param-title": "Titolo d' 'a paggena a cagnà. Nun se pò ausà nziem'a <var>$1pageid</var>.",
+       "apihelp-edit-param-pageid": "ID d' 'a paggena a cagnà. Nun se pò ausà nziem'a <var>$1title</var>.",
+       "apihelp-edit-param-section": "Nummero 'e sezione. <kbd>0</kbd> p' 'a sezione ncoppa, <kbd>new</kbd> pe' na seziona nova.",
+       "apihelp-edit-param-sectiontitle": "'O titolo pe' na seziona nova.",
+       "apihelp-edit-param-text": "Cuntenuto 'e paggena.",
+       "apihelp-edit-param-summary": "Oggetto d' 'a modifica. Pure 'o titolo ra sezione quanno $1sezione=new e $1sectiontitle nun è mpustato.",
+       "apihelp-edit-param-tags": "Cagna 'e tag ca s'avesser'applicà 'a verziona.",
+       "apihelp-edit-param-minor": "Cagnamiento piccerillo.",
+       "apihelp-edit-param-notminor": "Cagnamiento nun-piccerillo.",
+       "apihelp-edit-param-bot": "Nzegna stu cagnamiento comm' 'e bot.",
+       "apihelp-edit-param-basetimestamp": "Nzegna 'o tiempo d' 'a verzione bbase, ausato pe' puté ffà scummiglià cunflitte 'edizione. Se putesse piglià pe' bbìa 'e [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
+       "apihelp-edit-param-starttimestamp": "Nzegna 'o tiempo d' 'a verzione bbase, ausato pe' puté ffà scummiglià cunflitte 'edizione. Nu valore buono se putess'arrepiglià pe' bbìa 'e <var>[[Special:ApiHelp/main|curtimestamp]]</var> quann'accummencia 'o prucess' 'edizione (e.g. quanno se stà a carrecà 'o contenuto 'e na paggena p' 'a cagnà).",
+       "apihelp-edit-param-recreate": "Scrive ncopp'a cocch'errore ncopp'a paggena avenno scancellato chesto a nu certo punto.",
+       "apihelp-edit-param-createonly": "Nun cagnà 'a paggena si esiste già.",
+       "apihelp-edit-param-nocreate": "Ietta 'errore si 'a paggena nun esiste.",
+       "apihelp-edit-param-watch": "Azzecc' 'a paggena â lista 'e paggene cuntrullate.",
+       "apihelp-edit-param-unwatch": "Liev' 'a paggena â lista 'e paggene cuntrullate.",
+       "apihelp-edit-param-watchlist": "Senza condizione, azzeccà o luvà 'a paggena 'a l'elenco 'e paggene cuntrullate 'e ll'utente, ausà mpustaziune o nun 'o cagnà l'elenco.",
+       "apihelp-edit-param-md5": "'O hash MD5 d' 'o parammetro 'e $1text, o chill' 'e $1prependtext e $1appendtext concatenate. Si mpustato, 'o cagnamiento nun fosse fatto... 'o cuntrario succeresse si 'o hash fosse curretto.",
        "apihelp-edit-param-prependtext": "Azzecca stu testo addò 'o cap' 'e paggena. Se mettesse ncuoll'a $1text.",
        "apihelp-edit-param-appendtext": "Azzecca stu testo addò 'o cap' 'e paggena. Se mettesse ncuoll'a $1text.\n\nAusate $1section=new pe' ne puté appennere na seziona nova, ato che ausà stu parammetro.",
        "apihelp-edit-param-undo": "Torna arrèto sta verziona. Miette ncuollo 'o $1text, $1prependtext e $1appendtext.",
        "apihelp-expandtemplates-paramvalue-prop-properties": "'E pruprietà 'e pagena definite p' 'e parole magiche spannute dint' 'o wikitesto.",
        "apihelp-expandtemplates-paramvalue-prop-volatile": "Si l'output fosse volatile e nun s'avess'ausà n'atavota addò servesse dint' 'a paggena.",
        "apihelp-expandtemplates-paramvalue-prop-ttl": "'O tiempo massimo aropp' 'o quale 'e caches d' 'o risultato s'avessero a nzegnà invalide.",
+       "apihelp-expandtemplates-paramvalue-prop-modules": "Ogne modulo ResourceLoader ch' 'e funzione parser addimannajero a s'azzeccà a ll'output. Fosse <kbd>jsconfigvars</kbd> o pure <kbd>encodedjsconfigvars</kbd> s'avesser'addimannà tutte 'nzieme pe' bbìa d' 'e <kbd>modules</kbd>.",
+       "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Dà nfurmaziune 'e variabbele 'e mpustaziona JavaScript specifiche 'a paggena.",
+       "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Dà 'e variabbele 'e mpustaziona 'e JavaScript specifiche 'a na paggena comm'a na stringa JSON.",
+       "apihelp-expandtemplates-paramvalue-prop-parsetree": "L'albero 'e parse XML 'a ll'input.",
+       "apihelp-expandtemplates-param-includecomments": "Si s'avess'azzeccà cocche cummento HTML dint'a ll'output.",
+       "apihelp-expandtemplates-param-generatexml": "Generà ll'albero XML (scagnato 'a $1prop=parsetree).",
+       "apihelp-expandtemplates-example-simple": "Spanne 'o wikitesto <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
+       "apihelp-feedcontributions-description": "Tuorna nu feed 'e cuntribbute 'utente.",
+       "apihelp-feedcontributions-param-feedformat": "'O furmatto d' 'o feed.",
+       "apihelp-feedcontributions-param-user": "'A quale 'utente nc'avimm'a piglià cuntribbute.",
+       "apihelp-feedcontributions-param-namespace": "'A qualu namespace s'avesser'a filtrà 'e cuntribbute.",
+       "apihelp-feedcontributions-param-year": "'E ll'anno (e primma).",
+       "apihelp-feedcontributions-param-month": "D' 'o mese (e pure cchiù primma).",
        "apihelp-feedwatchlist-param-feedformat": "'O furmato d' 'o feed.",
        "apihelp-login-example-login": "Tràse.",
        "apihelp-move-description": "Mòve paggena.",
index 6aa5ece..254f1c8 100644 (file)
        "apihelp-watch-example-unwatch": "Deixar de vigiar a página <kbd>Página Principal</kbd>.",
        "apihelp-json-description": "Dados de saída em formato JSON.",
        "api-help-title": "Ajuda API da MediaWiki",
+       "api-help-lead": "Esta é uma página de documentação API do MediaWiki gerada automaticamente.\n\nDocumentação e exemplos: https://www.mediawiki.org/wiki/API",
        "api-help-main-header": "Módulo principal",
        "api-help-flag-deprecated": "Este módulo está obsoleto.",
+       "api-help-source": "Fonte: $1",
        "api-help-license": "Licença: [[$1|$2]]",
        "api-help-license-noname": "Licença: [[$1|Ver ligação]]",
        "api-help-license-unknown": "Licença: <span class=\"apihelp-unknown\">desconhecida</span>",
        "api-help-param-deprecated": "Obsoleto.",
        "api-help-param-required": "Este parâmetro é obrigatório.",
        "api-help-datatypes-header": "Tipo de dados",
+       "api-help-param-type-limit": "Tipo: inteiro ou <kbd>max</kbd>",
+       "api-help-param-type-boolean": "Tipo: boolean ([[Special:ApiHelp/main#main/datatypes|detalhes]])",
+       "api-help-param-type-user": "Tipo: {{PLURAL:$1|1=nome de utilizador|2=lista de nomes de utilizadores}}",
        "api-help-param-list": "{{PLURAL:$1|1=Um dos seguintes valores|2=Valores (separar com <kbd>{{!}}</kbd>)}}: $2",
        "api-help-param-multi-separate": "Separe os valores com <kbd>|</kbd>.",
        "api-help-param-default": "Padrão: $1",
        "api-help-examples": "{{PLURAL:$1|Exemplo|Exemplos}}:",
        "api-help-permissions": "{{PLURAL:$1|Permissão|Permissiões}}:",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Concedida a|Concedidas a}}: $2",
+       "api-help-open-in-apisandbox": "<small>[abrir na página de testes]</small>",
        "api-credits-header": "Créditos",
        "api-credits": "Programadores API:\n* Roan Kattouw (programador principal Set 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (criador, programador-líder Set 2006–Set 2007)\n* Brad Jorsch (programador-líder 2013–presente)\n\nPor favor, envie os seus comentários, sugestões e perguntas para mediawiki-api@lists.wikimedia.org ou reporte um erro técnico em https://phabricator.wikimedia.org/."
 }
index 15432da..637eb88 100644 (file)
@@ -132,7 +132,7 @@ class ChangesList extends ContextSource {
                $f = '';
                foreach ( array_keys( $this->getConfig()->get( 'RecentChangesFlags' ) ) as $flag ) {
                        $f .= isset( $flags[$flag] ) && $flags[$flag]
-                               ? self::flag( $flag )
+                               ? self::flag( $flag, $this->getContext() )
                                : $nothing;
                }
 
@@ -168,40 +168,40 @@ class ChangesList extends ContextSource {
        }
 
        /**
-        * Provide the "<abbr>" element appropriate to a given abbreviated flag,
-        * namely the flag indicating a new page, a minor edit, a bot edit, or an
-        * unpatrolled edit.  By default in English it will contain "N", "m", "b",
-        * "!" respectively, plus it will have an appropriate title and class.
+        * Make an "<abbr>" element for a given change flag. The flag indicating a new page, minor edit,
+        * bot edit, or unpatrolled edit. In English it typically contains "N", "m", "b", or "!".
         *
         * @param string $flag One key of $wgRecentChangesFlags
-        * @return string Raw HTML
+        * @param IContextSource $context
+        * @return string HTML
         */
-       public static function flag( $flag ) {
+       public static function flag( $flag, IContextSource $context = null ) {
+               static $map = [ 'minoredit' => 'minor', 'botedit' => 'bot' ];
                static $flagInfos = null;
+
                if ( is_null( $flagInfos ) ) {
                        global $wgRecentChangesFlags;
                        $flagInfos = [];
                        foreach ( $wgRecentChangesFlags as $key => $value ) {
-                               $flagInfos[$key]['letter'] = wfMessage( $value['letter'] )->escaped();
-                               $flagInfos[$key]['title'] = wfMessage( $value['title'] )->escaped();
+                               $flagInfos[$key]['letter'] = $value['letter'];
+                               $flagInfos[$key]['title'] = $value['title'];
                                // Allow customized class name, fall back to flag name
-                               $flagInfos[$key]['class'] = Sanitizer::escapeClass(
-                                       isset( $value['class'] ) ? $value['class'] : $key );
+                               $flagInfos[$key]['class'] = isset( $value['class'] ) ? $value['class'] : $key;
                        }
                }
 
-               // Inconsistent naming, bleh, kepted for b/c
-               $map = [
-                       'minoredit' => 'minor',
-                       'botedit' => 'bot',
-               ];
+               $context = $context ?: RequestContext::getMain();
+
+               // Inconsistent naming, kepted for b/c
                if ( isset( $map[$flag] ) ) {
                        $flag = $map[$flag];
                }
 
-               return "<abbr class='" . $flagInfos[$flag]['class'] . "' title='" .
-                       $flagInfos[$flag]['title'] . "'>" . $flagInfos[$flag]['letter'] .
-                       '</abbr>';
+               $info = $flagInfos[$flag];
+               return Html::element( 'abbr', [
+                       'class' => $info['class'],
+                       'title' => wfMessage( $info['title'] )->setContext( $context )->text(),
+               ], wfMessage( $info['letter'] )->setContext( $context )->text() );
        }
 
        /**
@@ -337,7 +337,7 @@ class ChangesList extends ContextSource {
         */
        public function insertLog( &$s, $title, $logtype ) {
                $page = new LogPage( $logtype );
-               $logname = $page->getName()->escaped();
+               $logname = $page->getName()->setContext( $this->getContext() )->escaped();
                $s .= $this->msg( 'parentheses' )->rawParams( Linker::linkKnown( $title, $logname ) )->escaped();
        }
 
index b9215fc..40d9277 100644 (file)
@@ -161,7 +161,7 @@ class JsonContent extends TextContent {
                        );
                }
                return Html::rawElement( 'table', [ 'class' => 'mw-json' ],
-                       Html::rawElement( 'tbody', [], join( '', $rows ) )
+                       Html::rawElement( 'tbody', [], implode( '', $rows ) )
                );
        }
 
@@ -200,7 +200,7 @@ class JsonContent extends TextContent {
                        );
                }
                return Html::rawElement( 'table', [ 'class' => 'mw-json' ],
-                       Html::rawElement( 'tbody', [], join( "\n", $rows ) )
+                       Html::rawElement( 'tbody', [], implode( "\n", $rows ) )
                );
        }
 
index 35ee1b7..c8b8108 100644 (file)
@@ -167,7 +167,7 @@ class RequestContext implements IContextSource, MutableContext {
         *
         * @param Title $title
         */
-       public function setTitle( Title $title ) {
+       public function setTitle( Title $title = null ) {
                $this->title = $title;
                // Erase the WikiPage so a new one with the new title gets created.
                $this->wikipage = null;
index 7058061..1e27205 100644 (file)
@@ -757,19 +757,13 @@ abstract class DatabaseMysqlBase extends Database {
                return $approxLag;
        }
 
-       /**
-        * Wait for the slave to catch up to a given master position.
-        * @todo Return values for this and base class are rubbish
-        *
-        * @param DBMasterPos|MySQLMasterPos $pos
-        * @param int $timeout The maximum number of seconds to wait for synchronisation
-        * @return int Zero if the slave was past that position already,
-        *   greater than zero if we waited for some period of time, less than
-        *   zero if we timed out.
-        */
        function masterPosWait( DBMasterPos $pos, $timeout ) {
+               if ( !( $pos instanceof MySQLMasterPos ) ) {
+                       throw new InvalidArgumentException( "Position not an instance of MySQLMasterPos" );
+               }
+
                if ( $this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached( $pos ) ) {
-                       return '0'; // http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html
+                       return 0;
                }
 
                # Commit any open transactions
@@ -778,18 +772,28 @@ abstract class DatabaseMysqlBase extends Database {
                # Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
                $encFile = $this->addQuotes( $pos->file );
                $encPos = intval( $pos->pos );
-               $sql = "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)";
-               $res = $this->doQuery( $sql );
-
-               $status = false;
-               if ( $res ) {
-                       $row = $this->fetchRow( $res );
-                       if ( $row ) {
-                               $status = $row[0]; // can be NULL, -1, or 0+ per the MySQL manual
-                               if ( ctype_digit( $status ) ) { // success
-                                       $this->lastKnownSlavePos = $pos;
-                               }
+               $res = $this->doQuery( "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)" );
+
+               $row = $res ? $this->fetchRow( $res ) : false;
+               if ( !$row ) {
+                       throw new DBExpectedError( $this, "Failed to query MASTER_POS_WAIT()" );
+               }
+
+               // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
+               $status = ( $row[0] !== null ) ? intval( $row[0] ) : null;
+               if ( $status === null ) {
+                       // T126436: jobs programmed to wait on master positions might be referencing binlogs
+                       // with an old master hostname. Such calls make MASTER_POS_WAIT() return null. Try
+                       // to detect this and treat the slave as having reached the position; a proper master
+                       // switchover already requires that the new master be caught up before the switch.
+                       $slavePos = $this->getSlavePos();
+                       if ( $slavePos && !$slavePos->channelsMatch( $pos ) ) {
+                               $this->lastKnownSlavePos = $slavePos;
+                               $status = 0;
                        }
+               } elseif ( $status >= 0 ) {
+                       // Remember that this position was reached to save queries next time
+                       $this->lastKnownSlavePos = $pos;
                }
 
                return $status;
@@ -1446,11 +1450,34 @@ class MySQLMasterPos implements DBMasterPos {
                return ( $thisPos && $thatPos && $thisPos >= $thatPos );
        }
 
+       function channelsMatch( DBMasterPos $pos ) {
+               if ( !( $pos instanceof self ) ) {
+                       throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ );
+               }
+
+               $thisBinlog = $this->getBinlogName();
+               $thatBinlog = $pos->getBinlogName();
+
+               return ( $thisBinlog !== false && $thisBinlog === $thatBinlog );
+       }
+
        function __toString() {
                // e.g db1034-bin.000976/843431247
                return "{$this->file}/{$this->pos}";
        }
 
+       /**
+        * @return string|bool
+        */
+       protected function getBinlogName() {
+               $m = [];
+               if ( preg_match( '!^(.+)\.(\d+)/(\d+)$!', (string)$this, $m ) ) {
+                       return $m[1];
+               }
+
+               return false;
+       }
+
        /**
         * @return array|bool (int, int)
         */
index 9b301a9..9e53653 100644 (file)
@@ -618,7 +618,7 @@ class DatabaseOracle extends Database {
 
                $table = $this->tableName( $table );
                // "INSERT INTO tables (a, b, c)"
-               $sql = "INSERT INTO " . $table . " (" . join( ',', array_keys( $row ) ) . ')';
+               $sql = "INSERT INTO " . $table . " (" . implode( ',', array_keys( $row ) ) . ')';
                $sql .= " VALUES (";
 
                // for each value, append ":key"
index 6fa8bf0..b6c37ee 100644 (file)
@@ -332,6 +332,13 @@ interface DBMasterPos {
         */
        public function hasReached( DBMasterPos $pos );
 
+       /**
+        * @param DBMasterPos $pos
+        * @return bool Whether this position appears to be for the same channel as another
+        * @since 1.27
+        */
+       public function channelsMatch( DBMasterPos $pos );
+
        /**
         * @return string
         * @since 1.27
index 7855861..8b1c3df 100644 (file)
@@ -1183,14 +1183,13 @@ interface IDatabase {
        public function wasReadOnlyError();
 
        /**
-        * Wait for the slave to catch up to a given master position.
+        * Wait for the slave to catch up to a given master position
         *
         * @param DBMasterPos $pos
-        * @param int $timeout The maximum number of seconds to wait for
-        *   synchronisation
-        * @return int Zero if the slave was past that position already,
+        * @param int $timeout The maximum number of seconds to wait for synchronisation
+        * @return int|null Zero if the slave was past that position already,
         *   greater than zero if we waited for some period of time, less than
-        *   zero if we timed out.
+        *   zero if it timed out, and null on error
         */
        public function masterPosWait( DBMasterPos $pos, $timeout );
 
index d5cd017..e68cf1a 100644 (file)
@@ -36,7 +36,7 @@ interface LoadMonitor {
 
        /**
         * Perform pre-connection load ratio adjustment.
-        * @param array $loads
+        * @param array &$loads
         * @param string|bool $group The selected query group. Default: false
         * @param string|bool $wiki Default: false
         */
index 5a103c6..6f40bda 100644 (file)
@@ -202,11 +202,17 @@ class FileBackendMultiWrite extends FileBackend {
                                if ( $this->asyncWrites && !$this->hasVolatileSources( $ops ) ) {
                                        // Bind $scopeLock to the callback to preserve locks
                                        DeferredUpdates::addCallableUpdate(
-                                               function() use ( $backend, $realOps, $opts, $scopeLock ) {
+                                               function() use ( $backend, $realOps, $opts, $scopeLock, $relevantPaths ) {
+                                                       wfDebugLog( 'FileOperationReplication',
+                                                               "'{$backend->getName()}' async replication; paths: " .
+                                                               FormatJson::encode( $relevantPaths ) );
                                                        $backend->doOperations( $realOps, $opts );
                                                }
                                        );
                                } else {
+                                       wfDebugLog( 'FileOperationReplication',
+                                               "'{$backend->getName()}' sync replication; paths: " .
+                                               FormatJson::encode( $relevantPaths ) );
                                        $status->merge( $backend->doOperations( $realOps, $opts ) );
                                }
                        }
index 789803f..f3c2abf 100644 (file)
@@ -1115,7 +1115,7 @@ class FileRepo {
         * @param array $srcPaths Ordered list of source virtual URLs/storage paths
         * @param string $dstPath Target file system path
         * @param int $flags Bitwise combination of the following flags:
-        *   self::DELETE_SOURCE     Delete the source files
+        *   self::DELETE_SOURCE     Delete the source files on success
         * @return FileRepoStatus
         */
        public function concatenate( array $srcPaths, $dstPath, $flags = 0 ) {
index d29cd7d..cc9099c 100644 (file)
@@ -537,7 +537,7 @@ class ForeignAPIRepo extends FileRepo {
         * @since 1.23
         */
        protected static function getIIProps() {
-               return join( '|', self::$imageInfoProps );
+               return implode( '|', self::$imageInfoProps );
        }
 
        /**
index 57eaffe..154f7c3 100644 (file)
@@ -516,7 +516,7 @@ class MysqlUpdater extends DatabaseUpdater {
                                $prev_title = $row->cur_title;
                                $prev_namespace = $row->cur_namespace;
                        }
-                       $sql = "DELETE FROM $cur WHERE cur_id IN ( " . join( ',', $deleteId ) . ')';
+                       $sql = "DELETE FROM $cur WHERE cur_id IN ( " . implode( ',', $deleteId ) . ')';
                        $this->db->query( $sql, __METHOD__ );
                        $this->output( wfTimestamp( TS_DB ) );
                        $this->output( "......<b>Deleted</b> " . $this->db->affectedRows() . " records.\n" );
index fdb52a8..b6bc521 100644 (file)
@@ -83,6 +83,7 @@
        "config-mysql-charset": "مجموعة محارف قاعدة البيانات",
        "config-mysql-binary": "ثنائي",
        "config-mysql-utf8": "يو تي إف-8",
+       "config-mssql-auth": "نوع الاستيثاق:",
        "config-site-name": "اسم الويكي:",
        "config-site-name-blank": "أدخل اسم موقع.",
        "config-project-namespace": "نطاق المشروع:",
        "config-profile": "ملف صلاحيات المستخدم:",
        "config-profile-wiki": "افتح ويكي",
        "config-profile-no-anon": "إنشاء الحساب مطلوب",
+       "config-profile-fishbowl": "المحررون المخولون فقط",
        "config-profile-private": "ويكي خاص",
        "config-license": "حقوق النسخ والترخيص:",
        "config-license-none": "لا تذييل ترخيص",
        "config-install-mainpage": "إنشاء صفحة رئيسية بالمحتوى الافتراضي",
        "config-install-extension-tables": "إنشاء جداول للامتدادات المفعلة",
        "config-install-mainpage-failed": "لم يتمكن من إدراج الصفحة الرئيسية: $1",
+       "config-download-localsettings": "تنزيل <code>LocalSettings.php</code>",
        "config-help": "مساعدة",
        "config-help-tooltip": "اضغط للتوسيع",
+       "config-nofile": "لا يمكن العثور على الملف \"$1\". هل حُذف؟",
        "mainpagetext": "'''تم تثبيت ميدياويكي بنجاح.'''",
        "mainpagedocfooter": "استشر [//meta.wikimedia.org/wiki/Help:Contents دليل المستخدم] لمعلومات حول استخدام برنامج الويكي.\n\n== البداية ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings قائمة إعدادات الضبط]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ أسئلة متكررة حول ميدياويكي]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce القائمة البريدية الخاصة بإصدار ميدياويكي]"
 }
index 865447a..6fa5930 100644 (file)
        "config-install-mainpage": "Creating main page with default content",
        "config-install-extension-tables": "Creating tables for enabled extensions",
        "config-install-mainpage-failed": "Could not insert main page: $1",
-       "config-install-done": "<strong>Congratulations!</strong>\nYou have successfully installed MediaWiki.\n\nThe installer has generated a <code>LocalSettings.php</code> file.\nIt contains all your configuration.\n\nYou will need to download it and put it in the base of your wiki installation (the same directory as index.php). The download should have started automatically.\n\nIf the download was not offered, or if you cancelled it, you can restart the download by clicking the link below:\n\n$3\n\n<strong>Note:</strong> If you do not do this now, this generated configuration file will not be available to you later if you exit the installation without downloading it.\n\nWhen that has been done, you can <strong>[$2 enter your wiki]</strong>.",
+       "config-install-done": "<strong>Congratulations!</strong>\nYou have installed MediaWiki.\n\nThe installer has generated a <code>LocalSettings.php</code> file.\nIt contains all your configuration.\n\nYou will need to download it and put it in the base of your wiki installation (the same directory as index.php). The download should have started automatically.\n\nIf the download was not offered, or if you cancelled it, you can restart the download by clicking the link below:\n\n$3\n\n<strong>Note:</strong> If you do not do this now, this generated configuration file will not be available to you later if you exit the installation without downloading it.\n\nWhen that has been done, you can <strong>[$2 enter your wiki]</strong>.",
        "config-download-localsettings": "Download <code>LocalSettings.php</code>",
        "config-help": "help",
        "config-help-tooltip": "click to expand",
        "config-nofile": "File \"$1\" could not be found. Has it been deleted?",
        "config-extension-link": "Did you know that your wiki supports [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions]?\n\nYou can browse [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions by category] or the [//www.mediawiki.org/wiki/Extension_Matrix Extension Matrix] to see the full list of extensions.",
-       "mainpagetext": "<strong>MediaWiki has been successfully installed.</strong>",
+       "mainpagetext": "<strong>MediaWiki has been installed.</strong>",
        "mainpagedocfooter": "Consult the [//meta.wikimedia.org/wiki/Help:Contents User's Guide] for information on using the wiki software.\n\n== Getting started ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki release mailing list]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]"
 }
index 71c5231..e7bed0e 100644 (file)
@@ -13,7 +13,7 @@
        "config-localsettings-upgrade": "Aptiktas failas <code>LocalSettings.php</code>. Norėdami patobulinti šią instaliaciją, prašome įvesti reikšmę <code>$wgUpgradeKey</code> į dėžutę žemiau. Jūs rasite ją <code>LocalSettings.php</code>.",
        "config-localsettings-cli-upgrade": "Aptiktas failas <code>LocalSettings.php</code>. Tam kad patobulinti šią instaliaciją, prašome paleisti <code>update.php</code>.",
        "config-localsettings-key": "Naujinimo raktas:",
-       "config-localsettings-badkey": "Raktas, kurį pateikėte, yra neteisingas.",
+       "config-localsettings-badkey": "Atnaujinimo raktas, kurį pateikėte, yra neteisingas.",
        "config-upgrade-key-missing": "Aptikta esama MediaWiki instaliacija. Tam kad atnaujinti šią instaliaciją, prašome įrašyti šią eilutę <code>LocalSettings.php</code> failo pabaigoje:\n\n$1",
        "config-localsettings-incomplete": "Esamas failas <code>LocalSettings.php</code> yra nepilnas. Nenustatytas kintamasis $1.\nPrašome pakeisti failą <code>LocalSettings.php</code> tai, kad kintamasis būtų nustatytas ir spauskite „{{int:Config-continue}}“.",
        "config-localsettings-connection-error": "Buvo susidurta su klaida, kai jungtasi prie duomenų bazės naudojantis nustatymais iš <code>LocalSettings.php</code>. Prašome pataisyti šiuos nustatymus ir bandyti dar kartą.\n\n$1",
@@ -54,6 +54,7 @@
        "config-apc": "[http://www.php.net/apc APC] yra įdiegtas",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] yra įdiegtas",
        "config-diff3-bad": "GNU diff3 nerastas.",
+       "config-using-server": "Naudojant serverio pavadinimas „<nowiki>$1</nowiki>“.",
        "config-using-uri": "Naudojamas serverio URL „<nowiki>$1$2</nowiki>“.",
        "config-db-type": "Duomenų bazės tipas:",
        "config-db-host": "Duomenų bazės serveris:",
        "config-header-oracle": "Oracle nustatymai",
        "config-header-mssql": "„Microsoft“ SQL serverio nustatymai",
        "config-invalid-db-type": "Neteisingas duomenų bazės tipas",
+       "config-missing-db-name": "Privalote įvesti „{{int:config-db-name}}“ reikšmę.",
        "config-missing-db-host": "Privalote įvesti „{{int:config-db-host}}“ reikšmę.",
        "config-missing-db-server-oracle": "Privalote įvesti „{{int:config-db-host-oracle}}“ reikšmę.",
        "config-postgres-old": "PostgreSQL $1 ar vėlesnė yra reikalinga. Jūs turite $2.",
+       "config-sqlite-cant-create-db": "Nepavyko sukurti duomenų bazės failo <code>$1</code>.",
        "config-regenerate": "Pergeneruoti LocalSettings.php →",
        "config-db-web-account-same": "Naudoti tą pačią paskyrą kaip ir įdiegimui",
        "config-db-web-create": "Sukurti paskyrą, jeigu jos nėra",
index 9366983..0931bea 100644 (file)
@@ -67,7 +67,6 @@
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] è installato",
        "config-apc": "[http://www.php.net/apc APC] è installato",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] è installato",
-       "config-no-cache": "'''Attenziò:''' [http://www.php.net/apc APC], [http://xcache.lighttpd.net/ XCache] o [http://www.iis.net/download/WinCacheForPhp WinCache] nun so' state truvate.\n'A funziona caching 'e ll'oggette non è apicciata.",
        "config-no-cache-apcu": "<strong>Attenziò:</strong> [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] o [http://www.iis.net/download/WinCacheForPhp WinCache] nun so' state truvate.\n'A funziona caching 'e ll'oggette non è apicciata.",
        "config-mod-security": "<strong>Attenziò:</strong> 'O servitore web vuosto téne [http://modsecurity.org/ mod_security]/mod_security2 appicciato. Ce stanno tante mpustaziune commune ca 'o facessero causà prubbleme a MediaWiki e ll'ati software ca permettessero ll'utente 'e pubbrecà cuntenute.\nSi putite, stutate sta funziona. Sinò, riferite 'a [http://modsecurity.org/documentation/ documentaziona ncopp' 'o mod_security] o cuntattate 'o host vuosto pe' ve dà supporto quanno se scummogliasse cocch'errore.",
        "config-diff3-bad": "GNU diff3 nun truvato.",
        "config-ns-site-name": "'O stesso ch' 'o nomme d' 'o wiki: $1",
        "config-ns-other": "Ati (specificà)",
        "config-ns-other-default": "MyWiki",
-       "config-project-namespace-help": "Secutanno l'esempio 'e Wikipedia, tante wiki teneno 'e paggene lloro ch' 'e regole spartute d' 'e paggene 'e cuntenute, dint'a nu \"'''namespace 'e pruggetto'''\". Tuttuquante 'e titule d' 'e paggene dint'a stu namespace accummenciano cu nu certo prefisso ca se putesse nzegnà ccà.\n'O solito, stu prefisso vene d' 'o nomme d' 'o wiki, ma nun adda cuntenè carattere 'e punteggiatura comme fossero \"#\" o \":\".",
+       "config-project-namespace-help": "Secutanno l'esempio 'e Wikipedia, tante wiki teneno 'e paggene lloro ch' 'e regole spartute d' 'e paggene 'e cuntenute, dint'a nu '''namespace 'e pruggetto'''. Tuttuquante 'e titule d' 'e paggene dint'a stu namespace accummenciano cu nu certo prefisso ca se putesse nzegnà ccà.\n'O solito, stu prefisso vene d' 'o nomme d' 'o wiki, ma nun adda cuntenè carattere 'e punteggiatura comme fossero \"#\" o \":\".",
        "config-ns-invalid": "'O namespace specificato \"<nowiki>$1</nowiki>\" nun è buono.\nSpecificate nu namespace 'e pruggetto differente.",
        "config-ns-conflict": "'O namespace innecato \"<nowiki>$1</nowiki>\" tràse ncunflitto cu nu namespace predefinito 'e MediaWiki.\nSpecifiate n'atu nomme divierzo 'e namespace 'e pruggetto.",
        "config-admin-box": "Cunto ammenistratore",
index aaf9fb0..479ec32 100644 (file)
@@ -452,7 +452,6 @@ class JobQueueDB extends JobQueue {
         * @see JobQueue::doAck()
         * @param Job $job
         * @throws MWException
-        * @return Job|bool
         */
        protected function doAck( Job $job ) {
                if ( !isset( $job->metadata['id'] ) ) {
@@ -476,8 +475,6 @@ class JobQueueDB extends JobQueue {
                } catch ( DBError $e ) {
                        $this->throwDBException( $e );
                }
-
-               return true;
        }
 
        /**
index c127239..bd832db 100644 (file)
@@ -49,7 +49,7 @@
 class JobQueueFederated extends JobQueue {
        /** @var HashRing */
        protected $partitionRing;
-       /** @var array (partition name => JobQueue) reverse sorted by weight */
+       /** @var JobQueue[] (partition name => JobQueue) reverse sorted by weight */
        protected $partitionQueues = [];
 
        /** @var int Maximum number of partitions to try */
@@ -311,7 +311,7 @@ class JobQueueFederated extends JobQueue {
                        throw new MWException( "The given job has no defined partition name." );
                }
 
-               return $this->partitionQueues[$job->metadata['QueuePartition']]->ack( $job );
+               $this->partitionQueues[$job->metadata['QueuePartition']]->ack( $job );
        }
 
        protected function doIsRootJobOldDuplicate( Job $job ) {
index 30907e6..4f8f6b3 100644 (file)
@@ -72,10 +72,13 @@ class EmailNotification {
        protected $editor;
 
        /**
+        * @deprecated since 1.27 use WatchedItemStore::updateNotificationTimestamp directly
+        *
         * @param User $editor The editor that triggered the update.  Their notification
         *  timestamp will not be updated(they have already seen it)
         * @param LinkTarget $linkTarget The link target of the title to update timestamps for
         * @param string $timestamp Set the update timestamp to this value
+        *
         * @return int[] Array of user IDs
         */
        public static function updateWatchlistTimestamp(
@@ -83,47 +86,16 @@ class EmailNotification {
                LinkTarget $linkTarget,
                $timestamp
        ) {
-               global $wgEnotifWatchlist, $wgShowUpdatedMarker;
-
-               if ( !$wgEnotifWatchlist && !$wgShowUpdatedMarker ) {
+               // wfDeprecated( __METHOD__, '1.27' );
+               $config = RequestContext::getMain()->getConfig();
+               if ( !$config->get( 'EnotifWatchlist' ) && !$config->get( 'ShowUpdatedMarker' ) ) {
                        return [];
                }
-
-               $dbw = wfGetDB( DB_MASTER );
-               $res = $dbw->select( [ 'watchlist' ],
-                       [ 'wl_user' ],
-                       [
-                               'wl_user != ' . intval( $editor->getID() ),
-                               'wl_namespace' => $linkTarget->getNamespace(),
-                               'wl_title' => $linkTarget->getDBkey(),
-                               'wl_notificationtimestamp IS NULL',
-                       ], __METHOD__
+               return WatchedItemStore::getDefaultInstance()->updateNotificationTimestamp(
+                       $editor,
+                       $linkTarget,
+                       $timestamp
                );
-
-               $watchers = [];
-               foreach ( $res as $row ) {
-                       $watchers[] = intval( $row->wl_user );
-               }
-
-               if ( $watchers ) {
-                       // Update wl_notificationtimestamp for all watching users except the editor
-                       $fname = __METHOD__;
-                       $dbw->onTransactionIdle(
-                               function () use ( $dbw, $timestamp, $watchers, $linkTarget, $fname ) {
-                                       $dbw->update( 'watchlist',
-                                               [ /* SET */
-                                                       'wl_notificationtimestamp' => $dbw->timestamp( $timestamp )
-                                               ], [ /* WHERE */
-                                                       'wl_user' => $watchers,
-                                                       'wl_namespace' => $linkTarget->getNamespace(),
-                                                       'wl_title' => $linkTarget->getDBkey(),
-                                               ], $fname
-                                       );
-                               }
-                       );
-               }
-
-               return $watchers;
        }
 
        /**
@@ -149,7 +121,15 @@ class EmailNotification {
                }
 
                // update wl_notificationtimestamp for watchers
-               $watchers = self::updateWatchlistTimestamp( $editor, $title, $timestamp );
+               $config = RequestContext::getMain()->getConfig();
+               $watchers = [];
+               if ( $config->get( 'EnotifWatchlist' ) || $config->get( 'ShowUpdatedMarker' ) ) {
+                       $watchers = WatchedItemStore::getDefaultInstance()->updateNotificationTimestamp(
+                               $editor,
+                               $title,
+                               $timestamp
+                       );
+               }
 
                $sendEmail = true;
                // $watchers deals with $wgEnotifWatchlist.
index d65e8be..d7ba266 100644 (file)
@@ -4636,7 +4636,7 @@ class Parser {
                        $anchor = $safeHeadline;
                        $legacyAnchor = $legacyHeadline;
                        if ( isset( $refers[$arrayKey] ) ) {
-                               // @codingStandardsIgnoreStart 
+                               // @codingStandardsIgnoreStart
                                for ( $i = 2; isset( $refers["${arrayKey}_$i"] ); ++$i );
                                // @codingStandardsIgnoreEnd
                                $anchor .= "_$i";
@@ -4645,7 +4645,7 @@ class Parser {
                                $refers[$arrayKey] = true;
                        }
                        if ( $legacyHeadline !== false && isset( $refers[$legacyArrayKey] ) ) {
-                               // @codingStandardsIgnoreStart 
+                               // @codingStandardsIgnoreStart
                                for ( $i = 2; isset( $refers["${legacyArrayKey}_$i"] ); ++$i );
                                // @codingStandardsIgnoreEnd
                                $legacyAnchor .= "_$i";
@@ -4793,7 +4793,7 @@ class Parser {
                        $sections[0] = $sections[0] . $toc . "\n";
                }
 
-               $full .= join( '', $sections );
+               $full .= implode( '', $sections );
 
                if ( $this->mForceTocPosition ) {
                        return str_replace( '<!--MWTOC-->', $toc, $full );
index 598702d..5e8fb04 100644 (file)
@@ -160,7 +160,7 @@ class SearchMssql extends SearchDatabase {
                        }
                }
 
-               $searchon = $this->db->addQuotes( join( ',', $q ) );
+               $searchon = $this->db->addQuotes( implode( ',', $q ) );
                $field = $this->getIndexField( $fulltext );
                return "$field, $searchon";
        }
index 70c771d..bbdfdc3 100644 (file)
@@ -120,7 +120,7 @@ class BotPasswordSessionProvider extends ImmutableSessionProviderWithCookie {
                if ( $missingKeys ) {
                        $this->logger->info( 'Session "{session}": Missing metadata: {missing}', [
                                'session' => $info,
-                               'missing' => join( ', ', $missingKeys ),
+                               'missing' => implode( ', ', $missingKeys ),
                        ] );
                        return false;
                }
index 21db609..0fd8fa8 100644 (file)
@@ -352,7 +352,7 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
                        $new = true;
                }
                if ( is_array( $salt ) ) {
-                       $salt = join( '|', $salt );
+                       $salt = implode( '|', $salt );
                }
                return new Token( $secret, (string)$salt, $new );
        }
index 81f8243..efa3445 100644 (file)
@@ -287,7 +287,7 @@ final class SessionManager implements SessionManagerInterface {
                // Make sure there's exactly one
                if ( count( $infos ) > 1 ) {
                        throw new \UnexpectedValueException(
-                               'Multiple empty sessions tied for top priority: ' . join( ', ', $infos )
+                               'Multiple empty sessions tied for top priority: ' . implode( ', ', $infos )
                        );
                } elseif ( count( $infos ) < 1 ) {
                        throw new \UnexpectedValueException( 'No provider could provide an empty session!' );
@@ -537,7 +537,7 @@ final class SessionManager implements SessionManagerInterface {
                \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
 
                # Watch user's userpage and talk page
-               $user->addWatch( $user->getUserPage(), \WatchedItem::IGNORE_USER_RIGHTS );
+               $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
 
                return true;
        }
@@ -677,7 +677,7 @@ final class SessionManager implements SessionManagerInterface {
 
                if ( count( $retInfos ) > 1 ) {
                        $ex = new \OverflowException(
-                               'Multiple sessions for this request tied for top priority: ' . join( ', ', $retInfos )
+                               'Multiple sessions for this request tied for top priority: ' . implode( ', ', $retInfos )
                        );
                        $ex->sessionInfos = $retInfos;
                        throw $ex;
index bc2bb31..8ce480e 100644 (file)
@@ -582,31 +582,51 @@ class SpecialPageFactory {
         * @return string HTML fragment
         */
        public static function capturePath( Title $title, IContextSource $context ) {
-               global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
-
-               // Save current globals
-               $oldTitle = $wgTitle;
-               $oldOut = $wgOut;
-               $oldRequest = $wgRequest;
-               $oldUser = $wgUser;
-               $oldLang = $wgLang;
-
-               // Set the globals to the current context
+               global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang;
+               $main = RequestContext::getMain();
+
+               // Save current globals and main context
+               $glob = [
+                       'title' => $wgTitle,
+                       'output' => $wgOut,
+                       'request' => $wgRequest,
+                       'user' => $wgUser,
+                       'language' => $wgLang,
+               ];
+               $ctx = [
+                       'title' => $main->getTitle(),
+                       'output' => $main->getOutput(),
+                       'request' => $main->getRequest(),
+                       'user' => $main->getUser(),
+                       'language' => $main->getLanguage(),
+               ];
+
+               // Override
                $wgTitle = $title;
                $wgOut = $context->getOutput();
                $wgRequest = $context->getRequest();
                $wgUser = $context->getUser();
                $wgLang = $context->getLanguage();
+               $main->setTitle( $title );
+               $main->setOutput( $context->getOutput() );
+               $main->setRequest( $context->getRequest() );
+               $main->setUser( $context->getUser() );
+               $main->setLanguage( $context->getLanguage() );
 
                // The useful part
                $ret = self::executePath( $title, $context, true );
 
-               // And restore the old globals
-               $wgTitle = $oldTitle;
-               $wgOut = $oldOut;
-               $wgRequest = $oldRequest;
-               $wgUser = $oldUser;
-               $wgLang = $oldLang;
+               // Restore old globals and context
+               $wgTitle = $glob['title'];
+               $wgOut = $glob['output'];
+               $wgRequest = $glob['request'];
+               $wgUser = $glob['user'];
+               $wgLang = $glob['language'];
+               $main->setTitle( $ctx['title'] );
+               $main->setOutput( $ctx['output'] );
+               $main->setRequest( $ctx['request'] );
+               $main->setUser( $ctx['user'] );
+               $main->setLanguage( $ctx['language'] );
 
                return $ret;
        }
index 9930655..625e4aa 100644 (file)
@@ -794,7 +794,7 @@ class SpecialBlock extends FormSpecialPage {
                        WatchAction::doWatch(
                                Title::makeTitle( NS_USER, $target ),
                                $performer,
-                               WatchedItem::IGNORE_USER_RIGHTS
+                               User::IGNORE_USER_RIGHTS
                        );
                }
 
index 72f8cca..fe1dd98 100644 (file)
@@ -581,7 +581,7 @@ class ImportReporter extends ContextSource {
         * @param array $pageInfo
         * @return void
         */
-       function reportPage( $title, $foreignTitle, $revisionCount,
+       public function reportPage( $title, $foreignTitle, $revisionCount,
                        $successCount, $pageInfo ) {
                $args = func_get_args();
                call_user_func_array( $this->mOriginalPageOutCallback, $args );
index 6b61ef9..8d45468 100644 (file)
@@ -714,7 +714,7 @@ class LoginForm extends SpecialPage {
                DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
 
                // Watch user's userpage and talk page
-               $u->addWatch( $u->getUserPage(), WatchedItem::IGNORE_USER_RIGHTS );
+               $u->addWatch( $u->getUserPage(), User::IGNORE_USER_RIGHTS );
 
                return Status::newGood( $u );
        }
index c1e538a..a874038 100644 (file)
@@ -716,7 +716,7 @@ abstract class UploadBase {
                                WatchAction::doWatch(
                                        $this->getLocalFile()->getTitle(),
                                        $user,
-                                       WatchedItem::IGNORE_USER_RIGHTS
+                                       User::IGNORE_USER_RIGHTS
                                );
                        }
                        Hooks::run( 'UploadComplete', [ &$this ] );
index d82a9e6..8ee0845 100644 (file)
@@ -145,6 +145,7 @@ class UploadFromChunks extends UploadFromFile {
                if ( !$status->isOk() ) {
                        return $status;
                }
+
                wfDebugLog( 'fileconcatenate', "Combined $i chunks in $tAmount seconds." );
 
                // File system path
index 7bc410d..68a169a 100644 (file)
@@ -62,17 +62,22 @@ class User implements IDBAccessObject {
         */
        const VERSION = 10;
 
-       /**
-        * Maximum items in $mWatchedItems
-        */
-       const MAX_WATCHED_ITEMS_CACHE = 100;
-
        /**
         * Exclude user options that are set to their default value.
         * @since 1.25
         */
        const GETOPTIONS_EXCLUDE_DEFAULTS = 1;
 
+       /**
+        * @since 1.27
+        */
+       const CHECK_USER_RIGHTS = true;
+
+       /**
+        * @since 1.27
+        */
+       const IGNORE_USER_RIGHTS = false;
+
        /**
         * Array of Strings List of member variables which are saved to the
         * shared cache (memcached). Any operation which changes the
@@ -291,9 +296,6 @@ class User implements IDBAccessObject {
        /** @var Block */
        private $mBlockedFromCreateAccount = false;
 
-       /** @var array */
-       private $mWatchedItems = [];
-
        /** @var integer User::READ_* constant bitfield used to load data */
        protected $queryFlagsUsed = self::READ_NORMAL;
 
@@ -3445,51 +3447,36 @@ class User implements IDBAccessObject {
                }
        }
 
-       /**
-        * Get a WatchedItem for this user and $title.
-        *
-        * @since 1.22 $checkRights parameter added
-        * @param Title $title
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
-        * @return WatchedItem
-        */
-       public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
-
-               if ( isset( $this->mWatchedItems[$key] ) ) {
-                       return $this->mWatchedItems[$key];
-               }
-
-               if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
-                       $this->mWatchedItems = [];
-               }
-
-               $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
-               return $this->mWatchedItems[$key];
-       }
-
        /**
         * Check the watched status of an article.
         * @since 1.22 $checkRights parameter added
         * @param Title $title Title of the article to look at
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+        * @param bool $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
         * @return bool
         */
-       public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               return $this->getWatchedItem( $title, $checkRights )->isWatched();
+       public function isWatched( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
+               if ( $title->isWatchable() && ( !$checkRights || $this->isAllowed( 'viewmywatchlist' ) ) ) {
+                       return WatchedItemStore::getDefaultInstance()->isWatched( $this, $title );
+               }
+               return false;
        }
 
        /**
         * Watch an article.
         * @since 1.22 $checkRights parameter added
         * @param Title $title Title of the article to look at
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
-        */
-       public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               $this->getWatchedItem( $title, $checkRights )->addWatch();
+        * @param bool $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
+        */
+       public function addWatch( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
+               if ( !$checkRights || $this->isAllowed( 'editmywatchlist' ) ) {
+                       WatchedItemStore::getDefaultInstance()->addWatchBatch( [
+                               [ $this, $title->getSubjectPage() ],
+                               [ $this, $title->getTalkPage() ],
+                       ]
+                       );
+               }
                $this->invalidateCache();
        }
 
@@ -3497,11 +3484,14 @@ class User implements IDBAccessObject {
         * Stop watching an article.
         * @since 1.22 $checkRights parameter added
         * @param Title $title Title of the article to look at
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+        * @param bool $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass User::CHECK_USER_RIGHTS or User::IGNORE_USER_RIGHTS.
         */
-       public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               $this->getWatchedItem( $title, $checkRights )->removeWatch();
+       public function removeWatch( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
+               if ( !$checkRights || $this->isAllowed( 'editmywatchlist' ) ) {
+                       WatchedItemStore::getDefaultInstance()->removeWatch( $this, $title->getSubjectPage() );
+                       WatchedItemStore::getDefaultInstance()->removeWatch( $this, $title->getTalkPage() );
+               }
                $this->invalidateCache();
        }
 
@@ -3569,9 +3559,8 @@ class User implements IDBAccessObject {
                        $force = 'force';
                }
 
-               $this->getWatchedItem( $title )->resetNotificationTimestamp(
-                       $force, $oldid
-               );
+               WatchedItemStore::getDefaultInstance()
+                       ->resetNotificationTimestamp( $this, $title, $force, $oldid );
        }
 
        /**
index 521e345..617e8f5 100644 (file)
@@ -69,13 +69,13 @@ class MWRestrictions {
                $invalidKeys = array_diff( $keys, $validKeys );
                if ( $invalidKeys ) {
                        throw new InvalidArgumentException(
-                               'Array contains invalid keys: ' . join( ', ', $invalidKeys )
+                               'Array contains invalid keys: ' . implode( ', ', $invalidKeys )
                        );
                }
                $missingKeys = array_diff( $neededKeys, $keys );
                if ( $missingKeys ) {
                        throw new InvalidArgumentException(
-                               'Array is missing required keys: ' . join( ', ', $missingKeys )
+                               'Array is missing required keys: ' . implode( ', ', $missingKeys )
                        );
                }
 
index b36f080..89625c0 100644 (file)
@@ -52,11 +52,11 @@ class LanguageCu extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # родительный падеж
-                                       if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вики' )
-                                               || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вики' )
+                                       if ( ( implode( '', array_slice( $ar[0], -4 ) ) == 'вики' )
+                                               || ( implode( '', array_slice( $ar[0], -4 ) ) == 'Вики' )
                                        ) {
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ї' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'їѩ';
+                                       } elseif ( implode( '', array_slice( $ar[0], -2 ) ) == 'ї' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'їѩ';
                                        }
                                        break;
                                case 'accusative': # винительный падеж
index f6d5270..05b0ebe 100644 (file)
@@ -52,12 +52,12 @@ class LanguageHy extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # սեռական հոլով
-                                       if ( join( '', array_slice( $ar[0], -1 ) ) == 'ա' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'այի';
-                                       } elseif ( join( '', array_slice( $ar[0], -1 ) ) == 'ո' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'ոյի';
-                                       } elseif ( join( '', array_slice( $ar[0], -4 ) ) == 'գիրք' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -4 ) ) . 'գրքի';
+                                       if ( implode( '', array_slice( $ar[0], -1 ) ) == 'ա' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -1 ) ) . 'այի';
+                                       } elseif ( implode( '', array_slice( $ar[0], -1 ) ) == 'ո' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -1 ) ) . 'ոյի';
+                                       } elseif ( implode( '', array_slice( $ar[0], -4 ) ) == 'գիրք' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -4 ) ) . 'գրքի';
                                        } else {
                                                $word .= 'ի';
                                        }
index 6cc23e3..72bde40 100644 (file)
@@ -51,19 +51,19 @@ class LanguageUk extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # родовий відмінок
-                                       if ( join( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ії';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) === 'ти' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'т';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) === 'ди' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'дів';
-                                       } elseif ( join( '', array_slice( $ar[0], -3 ) ) === 'ник' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
+                                       if ( implode( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'ії';
+                                       } elseif ( implode( '', array_slice( $ar[0], -2 ) ) === 'ти' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'т';
+                                       } elseif ( implode( '', array_slice( $ar[0], -2 ) ) === 'ди' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'дів';
+                                       } elseif ( implode( '', array_slice( $ar[0], -3 ) ) === 'ник' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
                                        }
                                        break;
                                case 'accusative': # знахідний відмінок
-                                       if ( join( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ію';
+                                       if ( implode( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'ію';
                                        }
                                        break;
                        }
index 7379a13..2ec6120 100644 (file)
        "wrongpasswordempty": "كلمة السر المدخلة كانت فارغة.\nمن فضلك حاول مرة أخرى.",
        "passwordtooshort": "يجب أن تتكون كلمة السر على الأقل من {{PLURAL:$1|حرف واحد|حرفين|$1 حروف|$1 حرفا|$1 حرف}}.",
        "passwordtoolong": "كلمات السر لا يجب أن تكون أطول من  {{PLURAL:$1|1 حرف|$1 حروف}}.",
+       "passwordtoopopular": "كلمات المرور الشائعة لا يمكن استخدامها. برجاء اختيار كلمة مرور أكثر فرادة.",
        "password-name-match": "يجب أن تكون كلمة المرور مختلفة عن اسم المستخدم.",
        "password-login-forbidden": "تم منع استخدام اسم المستخدم هذا وكلمة السر.",
        "mailmypassword": "أعد تعيين كلمة السر",
        "apisandbox-no-parameters": "وحدة API هذه ليس بها معاملات.",
        "apisandbox-helpurls": "وصلات المساعدة",
        "apisandbox-examples": "أمثلة",
+       "apisandbox-dynamic-parameters": "معاملات إضافية",
        "apisandbox-dynamic-parameters-add-label": "اضافة أليات:",
        "apisandbox-dynamic-parameters-add-placeholder": "اسم المعامل",
+       "apisandbox-dynamic-error-exists": "يوجد بالفعل معامل باسم \"$1\".",
        "apisandbox-deprecated-parameters": "معاملات مهملة",
        "apisandbox-submit-invalid-fields-title": "بعض الحقول غير صالحة",
        "apisandbox-results": "النتائج",
        "mediastatistics": "إحصاءات الميديا",
        "mediastatistics-summary": "إحصاءات عن أنماط الملفات المرفوعة، وتشمل أحدث نسخة من الملف فقط، حيث تستبعد النسخ القديمة أو المحذوفة من الملفات.",
        "mediastatistics-nbytes": "{{PLURAL:$1|بايت واحد|بايتان اثنان|$1 بايتات|$1 بايتاً|$1 بايت}} ($2; $3%)",
+       "mediastatistics-allbytes": "الحجم الكلي لكل الملفات: {{PLURAL:$1|$1 بايت}} ($2).",
        "mediastatistics-table-mimetype": "نوع MIME",
        "mediastatistics-table-extensions": "الامتدادات الممكنة",
        "mediastatistics-table-count": "عدد الملفات",
        "api-error-blacklisted": "اختر عنوانا مختلفا ومفهوما.",
        "sessionmanager-tie": "لا يمكن جمع أنواع استيثاق متعددة: $1.",
        "sessionprovider-generic": "جلسات $1",
+       "sessionprovider-mediawiki-session-cookiesessionprovider": "جلسات قائمة على ملفات تعريف الارتباط (كوكيز)",
        "sessionprovider-nocookies": "قد يتم تعطيل الكوكيز. تأكد من تمكين ملفات تعريف الأرتباط وأبد مرةأخرى.",
        "randomrootpage": "صفحة جذر عشوائية"
 }
index 5131276..a1167f2 100644 (file)
@@ -84,7 +84,7 @@
        "september": "سبتامبر",
        "october": "كتوبر",
        "november": "نوفامبر",
-       "december": "ديسامبر",
+       "december": "ديسمبر",
        "january-gen": "جانفي",
        "february-gen": "فيفري",
        "march-gen": "مارس",
        "unprotectthispage": "بدّل الحضية تاع هاد الباجة",
        "newpage": "باجه جديده",
        "talkpage": "قرعَج على هاد الباجة",
-       "talkpagelinktext": "مهادرة",
+       "talkpagelinktext": "تناقش",
        "specialpage": "باجة خوصوصيّة",
        "personaltools": "دوزان شخصيه",
        "articlepage": "شوف الباجة تاع المحتاوا",
        "pool-errorunknown": "خلطة ماشي معروفة",
        "pool-servererror": "السربيس تاع العدّان راه حابس ( $1 ).",
        "poolcounter-usage-error": "غلطة تاع ستُعمال: $1",
-       "aboutsite": "على{{SITENAME}}",
+       "aboutsite": "على {{SITENAME}}",
        "aboutpage": "Project:على",
        "copyright": "المحتاوا راه تحت النسخة $1 تاع الليسانس، غير يلا كان مكتوب حاجاخرة.",
        "copyrightpage": "{{ns:project}}:حقوق النسخ",
        "currentevents": "الختيّارات",
        "currentevents-url": "Project:خبورات",
        "disclaimers": "تنبيهات",
-       "disclaimerpage": "Project:التحذيرات العامه",
+       "disclaimerpage": "Project:التنبيهات العامة",
        "edithelp": "معونة",
        "helppage-top-gethelp": "معاونة",
        "mainpage": "الپاجة اللولانيّة",
        "policy-url": "Project:المقاون",
        "portal": "بورطاي المجتمع",
        "portal-url": "Project:بورطاي المجتمع",
-       "privacy": "اÙ\84سÙ\8aاسة ØªØ§Ø¹ Ø§Ù\84خصÙ\88صÙ\8aات (اÙ\84دÙ\8aÙ\86 Ø§Ù\84ضÙ\8aÙ\91Ù\82)",
-       "privacypage": "Project:خصÙ\88صÙ\8aÙ\87",
+       "privacy": "اÙ\84سÙ\8aاسة ØªØ§Ø¹ Ø§Ù\84خصÙ\88صÙ\8aØ©",
+       "privacypage": "Project:اÙ\84سÙ\8aاسة ØªØ§Ø¹ Ø§Ù\84خصÙ\88صÙ\8aÙ\91Ø©",
        "badaccess": "مشكل فل مسموحات",
        "badaccess-group0": "ماشي مقبول ليك تدير الشي الّي راك تسيّي تديرهُ.",
        "badaccess-groups": "الفعلة الّي راك سيّيت تديرها مسموحة برك لل مستعملّين {{PLURAL:$2||الّي هوما منل جماعة|الّي هوما من وحدة من هاد الجمايع}}: $1.",
        "viewsourceold": "شوف الاصل",
        "editlink": "تبديل",
        "viewsourcelink": "شوف العين",
-       "editsectionhint": "Ø¥Ù\8aدÙ\8aتÙ\8a Ø§Ù\84صÙ\86Ù\81:$1",
+       "editsectionhint": "بدÙ\91Ù\84 Ù\81 Ø§Ù\84سÙ\83سÙ\8aÙ\88Ù\86$1",
        "toc": "محتويات",
        "showtoc": "ورّي",
        "hidetoc": "خبّي",
        "site-atom-feed": "$1 تيار آتوم",
        "page-rss-feed": "تلقيمة RSS تاع \"$1\"",
        "page-atom-feed": "$1 تيار آتوم",
-       "red-link-title": "$1 (اÙ\84باجة Ù\85ا Ù\83اÙ\8aÙ\86Ø´)",
+       "red-link-title": "$1 (اÙ\84باجة Ù\85ا Ù\83اÙ\8aÙ\86Ø© Ø´Ù\8a)",
        "sort-descending": "رتّب بل نازولي",
        "sort-ascending": "رتّب بل طالوعي",
        "nstab-main": "الباجة",
        "myprivateinfoprotected": "ما عندكش السراح باش تبدّل المعلومات الشخصيّة ديالك.",
        "mypreferencesprotected": "ما عندكش السراح باش تبدّل الإختيّارات ديالك.",
        "ns-specialprotected": "الپاجات الخصيصة ما تنجمش تتبدّل.",
-       "titleprotected": "هاد العلوان راه محضي من` التبدال من عند [[User:$1|$1]].\nالسبّة الّي مدّها هيّا <em>$2</em>.",
+       "titleprotected": "[[User:$1|$1]] {{GENDER:$1|حمى|حمات}} هاذ العنوان م الخلقان.\nالسبّة تاعو هيّ <em>$2</em>.",
        "filereadonlyerror": "ماشي ممكن تبدال الفيشي \"$1\" خاطرش الزمّام \"$2\" راه مشغّلة فيه الخاصيّة \"اقرا برك\".\n\nالموسيّر الّي غلقهُ راه ماد التفسير هادا: \"$3\".",
        "invalidtitle-knownnamespace": "علوان ماشي مقبول ب وسَع تاع تسميّة \"$2\" معا الكتيبة \"$3\".",
        "invalidtitle-unknownnamespace": "علوان ماشي مقبول ب نمرو ماشي معروف تاع الوسَع تاع تسميّة \"$1\" معا الكتيبة \"$2\".",
        "minoreditletter": "ط",
        "newpageletter": "ج‌",
        "boteditletter": "ب",
-       "rc-change-size-new": "$1 {{PLURAL:$1|octet|octets}} مورا التبدال",
+       "rc-change-size-new": "$1 {{PLURAL:$1|اوكتاتة|اوكتاتات}} بعد التبدال",
        "rc-enhanced-expand": "شوف التفاصيل",
        "rc-enhanced-hide": "خبي التفاصيل",
        "recentchangeslinked": "تبديلات مربوطه",
index 3ace910..356080e 100644 (file)
        "accmailtitle": "Пароль адасланы.",
        "accmailtext": "Створаны адвольны пароль для [[User talk:$1|$1]] быў адасланы па адрасе $2. Яго можна зьмяніць на старонцы ''[[Special:ChangePassword|зьмены паролю]]'' пасьля ўваходу.",
        "newarticle": "(Новая)",
-       "newarticletext": "Вы прыйшлі па спасылцы на старонку, якая яшчэ не існуе.\nКаб стварыць яе, напішыце тэкст у полі ніжэй (глядзіце [$1 старонку дапамогі] для дадатковай інфармацыі).\nКалі Вы трапілі сюды памылкова, націсьніце '''назад''' у вашым браўзэры.",
+       "newarticletext": "Вы прыйшлі па спасылцы на старонку, якая яшчэ не існуе.\nКаб стварыць яе, напішыце тэкст у полі ніжэй (глядзіце [$1 старонку дапамогі] для дадатковай інфармацыі).\nКалі Вы трапілі сюды памылкова, націсьніце кнопку «<strong>назад</strong>» у вашым браўзэры.",
        "anontalkpagetext": "----''Гэта старонка гутарак ананімнага ўдзельніка, які яшчэ не стварыў сабе рахунак альбо не ўжывае яго. Таму мы вымушаныя ўжываць лічбавы IP-адрас дзеля ягонай ідэнтыфікацыі. Адзін IP-адрас можа выкарыстоўвацца некалькімі ўдзельнікамі. Калі Вы — ананімны ўдзельнік і лічыце, што атрымалі не прызначаныя Вам камэнтары, калі ласка, [[Special:UserLogin/signup|стварыце рахунак]] альбо [[Special:UserLogin|увайдзіце ў сыстэму]], каб у будучыні пазьбегнуць магчымай блытаніны зь іншымі ананімнымі ўдзельнікамі.''",
        "noarticletext": "Цяпер тэкст на гэтай старонцы адсутнічае.\nВы можаце [[Special:Search/{{PAGENAME}}|пашукаць гэтую назву]] сярод іншых старонак, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пашукаць у адпаведных журналах падзеяў]\nальбо [{{fullurl:{{FULLPAGENAME}}|action=edit}} стварыць гэтую старонку]</span>.",
        "noarticletext-nopermission": "Цяпер на гэтай старонцы тэкст адсутнічае.\nВы можаце [[Special:Search/{{PAGENAME}}|пашукаць назву гэтай старонкі]] на іншых старонках, альбо <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} пашукаць зьвязаныя запісы ў журналах]</span>, але ў вас няма дазволу ствараць гэтую старонку.",
        "grant-patrol": "Патруляваньне зьменаў старонак",
        "grant-protect": "Абарона і зьняцьце абароны старонак",
        "grant-rollback": "Адкат зьменаў старонак",
+       "grant-sendemail": "Адпраўка лістоў электроннай пошты іншым удзельнікам",
+       "grant-uploadeditmovefile": "Загрузка, замена і перайменаваньне файлаў",
        "newuserlogpage": "Журнал стварэньня рахункаў",
        "newuserlogpagetext": "Гэта журнал стварэньня рахункаў удзельнікаў і ўдзельніц.",
        "rightslog": "Журнал правоў удзельнікаў",
index 12ea82c..c4b6b67 100644 (file)
        "accmailtitle": "پاسورد دیم داته بوت.",
        "newarticle": "(نوکین)",
        "newarticletext": "شما یک لینک ئی پدا گیپته ئیت و بي ورّق ئی رسیته ئيت که تا انون موجود نه اینت .\nپه ای ورّق ئی جۆڑ کورتینی خاتیرا، به جهلگین چارگوش ئی تا په نیوشیتین ئا شرو بکنیت (په گیشتیرین مالوماتان [$1 کومک ئی ورّق  ] ئا بگیندیت).\nاگه نالوٹگ ایدا آته ئیت، وتی بروزیر تا «بێرگشت» ئی کیلی ئا پرینچیت.",
-       "noarticletext": "ای تاکدیم همی انون هیچ متنئ نداریت .\nشما ئه توانیت که بئ دیگه تاکدیمانئ [[Special:Search/{{PAGENAME}}|ای تاکدیمی ئنوانا بگردیت]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} مربوطین سیاه چال ئا هم بگردیت ]،\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} ای تاکدیما ایڈیٹ بکنیت]</span>.",
+       "noarticletext": "ای تاکدیم انونین وختا هیچ متنئ نداریت.\nشما ئه توانێت که بِه دیگه تاکدیمانئ تا [[Special:Search/{{PAGENAME}}|ای عنوانئ پدا بگردێت]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} مربوتين کورم-جاهاني تا هم بگردێت]،\nیا [{{fullurl:{{FULLPAGENAME}}|action=edit}} ای تاکدیما جۆڑ بکنێت]</span>.",
        "noarticletext-nopermission": "ای تاکدیم همی انون هیچ متنی نداریت.\nشما ئه توانیت که دیگه تاکدیمانئ تا [[Special:Search/{{PAGENAME}}|ای ئنوانئ پدا بگردیت ]]،\nیا <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} مرتبطین سیاه چال ئانئ پدا بگردیت ]</span> ولی شما په ای تاکدیمئ جوڑ کورتینا اجازه نداریت.",
        "missing-revision": "#$1 ئی ایڈیٹ شه  «{{FULLPAGENAME}}» ئی تاکدیما موجود نه اینت.\n\nمعمولاً بئ اثر لینک بئ تاریخچهٔ ئا اپڈیٹ نه بوته و تاکدیم پاک بوته.\nتوانیت ایدت مئلومات بئ  [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} پاک بوته ئین سیاه چال ئی] تا بگیندیت.",
        "userpage-userdoesnotexist": "«<nowiki>$1</nowiki>» ئی کار زوروکین حساب راجستر نه بوته.\nمهربانی بکنیت مطمائین بئیت که لوٹیت ای تاکدیما جوڑ یا ایڈیٹ بکنیت.",
        "recentchanges-label-bot": "ای ایڈیٹا یک ربات ئی کورته",
        "recentchanges-label-unpatrolled": "ای ایڈیٹ تا انون گشت وارته نه بوته",
        "recentchanges-label-plusminus": "تاکدیمئ حجم بئ ای اندازگ بایٹ ئا تغیر کورته",
-       "recentchanges-legend-heading": "'''اختصارئان:'''",
+       "recentchanges-legend-heading": "<strong>اختصارئان:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (همیرنگ بی [[Special:NewPages|نوکین تاکدیمانئ لڑ لیست]] ئا سیل بکنیت)",
-       "rcnotefrom": "بئ جهلگا تغیرات شه <strong>$3, $4</strong> (تا <strong>$1</strong> {{PLURAL:$5|نشان داته بوته|نشان داته انت}}).",
+       "rcnotefrom": "بِه جهلگا تغیرات شه <strong>$3, $4</strong> (تا <strong>$1</strong> {{PLURAL:$5|نشان داته بوته|نشان داته انت}}).",
        "rclistfrom": "نوکین تغیراتانئ نشان داتین شرو شه $3 $2",
        "rcshowhideminor": "$1 ئی کمین ایڈیٹان",
        "rcshowhideminor-show": "نشان داتین",
        "javascripttest-pagetext-unknownaction": "نازانتین اکشن \"$1\".",
        "javascripttest-pagetext-skins": "پوسته‌ای ئا په آزمایشانی اجرا ئا انتخاب کنیت:",
        "javascripttest-qunit-intro": "[$1 آزمایشی مشتندانا] بئ mediawiki.org تا بگیندیت.",
-       "tooltip-pt-userpage": "شمی کار زوروکئ تاکدیم",
-       "tooltip-pt-mytalk": "شمی هبر و گپئ تاکدیم",
-       "tooltip-pt-preferences": "نئ تنظیمات",
+       "tooltip-pt-userpage": "{{GENDER:|شمئ کار زُورۆکین}} تاکدیم",
+       "tooltip-pt-mytalk": "{{GENDER:|شمئ}} حبر و گپئ تاکدیم",
+       "tooltip-pt-preferences": "{{GENDER:|شمئ}} تنظیماتان",
        "tooltip-pt-watchlist": "آ دیمانی لیست که شما آوانی تغیرانا پدگیری ئا کنیت",
-       "tooltip-pt-mycontris": "شمی شراکت ئانی لیست",
+       "tooltip-pt-mycontris": "{{GENDER:|شمئ}} شراکتاني لڑ",
        "tooltip-pt-login": "توصیه ئه کنن که بئ سایٹ ئی تا داخل بئیت. اگرچه که ای کار په جبر و زور نه اینت",
        "tooltip-pt-logout": "در بوتین",
        "tooltip-pt-createaccount": "شه شما ئه لوٹن که په وت یک کار زوروکئ حساب ئی جۆڑ بکنیت و بئ سایٹ ئی تا داخل بئیت؛هرچینکه که ای کار جبری نه اینت",
        "tooltip-t-recentchangeslinked": "تاکدیمانئ آخیرین تغیران که ای دیم گۆ آوان لینک داریت",
        "tooltip-feed-rss": "آراس‌اس ئی خبرنامه په ای تاکدیما",
        "tooltip-feed-atom": "اتم ئی حبرنامه په ای دیما",
-       "tooltip-t-contributions": "ای کار زوروکئ شراکتانی لڑ لیست",
+       "tooltip-t-contributions": "{{GENDER:$1|ای کار‌ زوروکئ}} شراکتانی لڑ لیست",
        "tooltip-t-emailuser": "په ای کار زوروکا ایمیل ئی دیم داتین",
        "tooltip-t-info": "ای دیمی باره ئا گیشتیرین مئلومات",
        "tooltip-t-upload": "فایلی بُرز کورتین",
index 7824732..8185527 100644 (file)
        "grant-editmyoptions": "আপনার ব্যবহারকারী পছন্দসমূহ সম্পাদনা করুন",
        "grant-editmywatchlist": "আপনার নজরতালিকা সম্পাদনা করুন",
        "grant-editprotected": "সংরক্ষিত পাতা সম্পাদনা করুন",
+       "grant-sendemail": "অন্য ব্যবহারকারীকে ইমেইল পাঠান",
        "grant-uploadfile": "নতুন ফাইল আপলোড করুন",
        "grant-basic": "মৌলিক অধিকার",
        "grant-viewdeleted": "অপসারিত ফাইল ও পাতাগুলি দেখুন",
index a3be6ef..cdb14db 100644 (file)
        "userrights": "Benutzerrechte verwalten",
        "userrights-lookup-user": "Gruppenzugehörigkeit verwalten",
        "userrights-user-editname": "Benutzername:",
-       "editusergroup": "{{GENDER:$1|Benutzerrechte}} bearbeiten",
+       "editusergroup": "{{GENDER:$1|Benutzergruppen}} verwalten",
        "editinguser": "Ändere Benutzerrechte {{GENDER:$1|des Benutzers|der Benutzerin}} <strong>[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Benutzer-Gruppenzugehörigkeit bearbeiten",
        "saveusergroups": "{{GENDER:$1|Gruppenzugehörigkeit}} ändern",
        "right-editprotected": "Seiten bearbeiten, die als „{{int:protect-level-sysop}}“ geschützt sind",
        "right-editsemiprotected": "Seiten bearbeiten, die als „{{int:protect-level-autoconfirmed}}“ geschützt sind",
        "right-editcontentmodel": "Das Inhaltsmodell einer Seite bearbeiten",
-       "right-editinterface": "Benutzeroberfläche bearbeiten",
+       "right-editinterface": "Systemnachrichten und Benutzeroberflächen bearbeiten",
        "right-editusercssjs": "Fremde CSS- und JavaScript-Dateien bearbeiten",
        "right-editusercss": "Fremde CSS-Dateien bearbeiten",
        "right-edituserjs": "Fremde JavaScript-Dateien bearbeiten",
        "right-patrolmarks": "Kontrollmarkierungen in den letzten Änderungen sehen",
        "right-unwatchedpages": "Liste der unbeobachteten Seiten ansehen",
        "right-mergehistory": "Versionsgeschichten von Seiten vereinen",
-       "right-userrights": "Benutzerrechte bearbeiten",
-       "right-userrights-interwiki": "Benutzerrechte in anderen Wikis bearbeiten",
+       "right-userrights": "Benutzerrechte verwalten",
+       "right-userrights-interwiki": "Benutzerrechte in anderen Wikis verwalten",
        "right-siteadmin": "Datenbank sperren und entsperren",
        "right-override-export-depth": "Exportiere Seiten einschließlich verlinkter Seiten bis zu einer Tiefe von 5",
        "right-sendemail": "E-Mails an andere Benutzer senden",
        "action-autopatrol": "eigene Bearbeitungen als kontrolliert zu markieren",
        "action-unwatchedpages": "die Liste der unbeobachteten Seiten einzusehen",
        "action-mergehistory": "die Versionsgeschichten von Seiten zu vereinen",
-       "action-userrights": "Benutzerrechte zu ändern",
+       "action-userrights": "Benutzerrechte zu verwalten",
        "action-userrights-interwiki": "die Rechte von Benutzern in anderen Wikis zu ändern",
        "action-siteadmin": "die Datenbank zu sperren oder freizugeben",
        "action-sendemail": "E-Mails zu senden",
        "changecontentmodel-nodirectediting": "Das Inhaltsmodell „$1“ unterstützt keine direkten Bearbeitungen",
        "log-name-contentmodel": "Inhaltsmodell-Änderungs-Logbuch",
        "log-description-contentmodel": "Ereignisse bezüglich den Inhaltsmodellen einer Seite",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|erstellte}} die Seite $3 mit einem Nicht-Standard-Inhaltsmodell „$5“",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|änderte}} das Inhaltsmodell der Seite $3 von „$4“ nach „$5“",
        "logentry-contentmodel-change-revertlink": "zurücksetzen",
        "logentry-contentmodel-change-revert": "zurücksetzen",
index 39146a2..13fe7ce 100644 (file)
        "right-importupload": "Εισαγωγή σελίδων με ανέβασμα αρχείου",
        "right-patrol": "Σήμανση επεξεργασιών άλλων χρηστών ως ελεγμένες",
        "right-autopatrol": "Αυτόματη σημείωση των επεξεργασιών τους ως ελεγμένες",
-       "right-patrolmarks": "Î\94είÏ\84ε Ï\84ιÏ\82 Ï\83ημειÏ\8eÏ\83ειÏ\82 'Ï\85Ï\80Ï\8c Ï\80αÏ\81ακολοÏ\8dθηÏ\83η' Ï\84Ï\89ν Ï\80Ï\81οÏ\83Ï\86άτων αλλαγών",
+       "right-patrolmarks": "ΠÏ\81οβολή Ï\83ημάνÏ\83εÏ\89ν ÎµÎ»Î­Î³Ï\87οÏ\85 Ï\80Ï\81Ï\8cÏ\83Ï\86ατων αλλαγών",
        "right-unwatchedpages": "Δείτε μια λίστα σελίδων που δεν παρακολουθούνται",
        "right-mergehistory": "Συγχώνευση του ιστορικού των σελίδων",
        "right-userrights": "Τροποποίηση όλων των δικαιωμάτων χρηστών",
        "ipb_expiry_temp": "Οι κρυμμένες φραγές ονομάτων χρηστών πρέπει να είναι μόνιμες.",
        "ipb_hide_invalid": "Μη εφικτή καταστολή αυτού του λογαριασμού. Μπορεί να έχει περισσότερες από {{PLURAL:$1|μια επεξεργασία|$1 επεξεργασίες}}.",
        "ipb_already_blocked": "Η διεύθυνση IP \"$1\" είναι ήδη φραγμένη",
-       "ipb-needreblock": "$1 είναι ήδη αποκλεισμένη. Θέλετε να αλλάξετε τις ρυθμίσεις?",
+       "ipb-needreblock": "Η $1 είναι ήδη αποκλεισμένη. Θέλετε να αλλάξετε τις ρυθμίσεις;",
        "ipb-otherblocks-header": "{{PLURAL:$1|Άλλη φραγή|Άλλες φραγές}}",
        "unblock-hideuser": "Δεν μπορείτε να καταργήσετε τον αποκλεισμό αυτού του χρήστη, καθώς το όνομα χρήστη του έχει αποκρυβεί.",
        "ipb_cant_unblock": "Σφάλμα: Ο αριθμός αναγνώρισης φραγής $1 δεν βρέθηκε. Μπορεί να έχει ξεμπλοκαριστεί ήδη.",
        "pageinfo-category-pages": "Αριθμός σελίδων",
        "pageinfo-category-subcats": "Αριθμός υποκατηγοριών",
        "pageinfo-category-files": "Αριθμός αρχείων",
-       "markaspatrolleddiff": "Î\9dα Ï\83ημειÏ\89θεί 'Ï\85Ï\80Ï\8c Ï\80αÏ\81ακολοÏ\8dθηÏ\83η'",
+       "markaspatrolleddiff": "ΣήμανÏ\83η Ï\89Ï\82 ÎµÎ»ÎµÎ³Î¼Î­Î½Î¿",
        "markaspatrolledtext": "Σήμανση αυτής της σελίδας ως ελεγμένης",
        "markaspatrolledtext-file": "Επισημάνετε αυτή τη έκδοση του αρχείου ως ελεγμένη",
-       "markedaspatrolled": "ΣημειÏ\89μένο Ï\89Ï\82 'Ï\85Ï\80Ï\8c Ï\80αÏ\81ακολοÏ\8dθηÏ\83η'",
+       "markedaspatrolled": "ΣημειÏ\8eθηκε Ï\89Ï\82 ÎµÎ»ÎµÎ³Î¼Î­Î½Î¿",
        "markedaspatrolledtext": "Η επιλεγμένη αναθεώρηση της [[:$1]] έχει σημειωθεί ως ελεγμένη.",
        "rcpatroldisabled": "Η λειτουργία 'Παρακολούθηση Πρόσφατων Αλλαγών' έχει απενεργοποιηθεί.",
        "rcpatroldisabledtext": "Η λειτουργία 'Παρακολούθηση Πρόσφατων Αλλαγών' είναι αυτή τη στιγμή απενεργοποιημένη.",
index 115b66f..fea9fbd 100644 (file)
        "nocookiesfornew": "The user account was not created, as we could not confirm its source.\nEnsure you have cookies enabled, reload this page and try again.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "noname": "You have not specified a valid username.",
-       "loginsuccesstitle": "Login successful",
+       "loginsuccesstitle": "Logged in",
        "loginsuccess": "<strong>You are now logged in to {{SITENAME}} as \"$1\".</strong>",
        "nosuchuser": "There is no user by the name \"$1\".\nUsernames are case sensitive.\nCheck your spelling, or [[Special:UserLogin/signup|create a new account]].",
        "nosuchusershort": "There is no user by the name \"$1\".\nCheck your spelling.",
        "createaccount-title": "Account creation for {{SITENAME}}",
        "createaccount-text": "Someone created an account for your email address on {{SITENAME}} ($4) named \"$2\", with password \"$3\".\nYou should log in and change your password now.\n\nYou may ignore this message, if this account was created in error.",
        "login-throttled": "You have made too many recent login attempts.\nPlease wait $1 before trying again.",
-       "login-abort-generic": "Your login was unsuccessful - Aborted",
+       "login-abort-generic": "Your login failed - Aborted",
        "login-migrated-generic": "Your account has been migrated, and your username no longer exist on this wiki.",
        "loginlanguagelabel": "Language: $1",
        "loginlanguagelinks": "* {{#language:de}}|de\n* {{#language:en}}|en\n* {{#language:eo}}|eo\n* {{#language:fr}}|fr\n* {{#language:es}}|es\n* {{#language:it}}|it\n* {{#language:nl}}|nl",
        "newpassword": "New password:",
        "retypenew": "Retype new password:",
        "resetpass_submit": "Set password and log in",
-       "changepassword-success": "Your password has been changed successfully!",
+       "changepassword-success": "Your password has been changed!",
        "changepassword-throttled": "You have made too many recent login attempts.\nPlease wait $1 before trying again.",
        "botpasswords": "Bot passwords",
        "botpasswords-summary": "<em>Bot passwords</em> allow access to a user account via the API without using the account's main login credentials. The user rights available when logged in with a bot password may be restricted.\n\nIf you don't know why you might want to do this, you should probably not do it. No one should ever ask you to generate one of these and give it to them.",
        "botpasswords-insert-failed": "Failed to add bot name \"$1\". Was it already added?",
        "botpasswords-update-failed": "Failed to update bot name \"$1\". Was it deleted?",
        "botpasswords-created-title": "Bot password created",
-       "botpasswords-created-body": "The bot password \"$1\" was created successfully.",
+       "botpasswords-created-body": "The bot password \"$1\" was created.",
        "botpasswords-updated-title": "Bot password updated",
-       "botpasswords-updated-body": "The bot password \"$1\" was updated successfully.",
+       "botpasswords-updated-body": "The bot password \"$1\" was updated.",
        "botpasswords-deleted-title": "Bot password deleted",
        "botpasswords-deleted-body": "The bot password \"$1\" was deleted.",
        "botpasswords-newpassword": "The new password to log in with <strong>$1</strong> is <strong>$2</strong>. <em>Please record this for future reference.</em>",
        "resetpass-no-info": "You must be logged in to access this page directly.",
        "resetpass-submit-loggedin": "Change password",
        "resetpass-submit-cancel": "Cancel",
-       "resetpass-wrong-oldpass": "Invalid temporary or current password.\nYou may have already successfully changed your password or requested a new temporary password.",
+       "resetpass-wrong-oldpass": "Invalid temporary or current password.\nYou may have already changed your password or requested a new temporary password.",
        "resetpass-recycled": "Please reset your password to something other than your current password.",
        "resetpass-temp-emailed": "You logged in with a temporary emailed code.\nTo finish logging in, you must set a new password here:",
        "resetpass-temp-password": "Temporary password:",
        "revdelete-unsuppress": "Remove restrictions on restored revisions",
        "revdelete-log": "Reason:",
        "revdelete-submit": "Apply to selected {{PLURAL:$1|revision|revisions}}",
-       "revdelete-success": "Revision visibility successfully updated.",
+       "revdelete-success": "Revision visibility updated.",
        "revdelete-failure": "Revision visibility could not be updated:\n$1",
-       "logdelete-success": "Log visibility successfully set.",
+       "logdelete-success": "Log visibility set.",
        "logdelete-failure": "Log visibility could not be set:\n$1",
        "revdel-restore": "change visibility",
        "pagehist": "Page history",
        "userrights-unchangeable-col": "Groups you cannot change",
        "userrights-irreversible-marker": "$1*",
        "userrights-conflict": "Conflict of user rights changes! Please review and confirm your changes.",
-       "userrights-removed-self": "You successfully removed your own rights. As such, you are no longer able to access this page.",
+       "userrights-removed-self": "You removed your own rights. As such, you are no longer able to access this page.",
        "group": "Group:",
        "group-user": "Users",
        "group-autoconfirmed": "Autoconfirmed users",
        "uploadstash-summary": "This page provides access to files that are uploaded or in the process of uploading, but are not yet published to the wiki. These files are not visible to anyone but the user who uploaded them.",
        "uploadstash-clear": "Clear stashed files",
        "uploadstash-nofiles": "You have no stashed files.",
-       "uploadstash-badtoken": "Performing of that action was unsuccessful, perhaps because your editing credentials expired. Try again.",
-       "uploadstash-errclear": "Clearing the files was unsuccessful.",
+       "uploadstash-badtoken": "Performing that action failed. Perhaps because your editing credentials expired. Please try again.",
+       "uploadstash-errclear": "Clearing the files failed.",
        "uploadstash-refresh": "Refresh the list of files",
        "invalid-chunk-offset": "Invalid chunk offset",
        "img-auth-accessdenied": "Access denied",
        "tags-delete-not-allowed": "Tags defined by an extension cannot be deleted unless the extension specifically allows it.",
        "tags-delete-not-found": "The tag \"$1\" does not exist.",
        "tags-delete-too-many-uses": "The tag \"$1\" is applied to more than $2 {{PLURAL:$2|revision|revisions}}, which means it cannot be deleted.",
-       "tags-delete-warnings-after-delete": "The tag \"$1\" was deleted successfully, but the following {{PLURAL:$2|warning was|warnings were}} encountered:",
+       "tags-delete-warnings-after-delete": "The tag \"$1\" was deleted, but the following {{PLURAL:$2|warning was|warnings were}} encountered:",
        "tags-activate-title": "Activate tag",
        "tags-activate-question": "You are about to activate the tag \"$1\".",
        "tags-activate-reason": "Reason:",
        "tags-edit-reason": "Reason:",
        "tags-edit-revision-submit": "Apply changes to {{PLURAL:$1|this revision|$1 revisions}}",
        "tags-edit-logentry-submit": "Apply changes to {{PLURAL:$1|this log entry|$1 log entries}}",
-       "tags-edit-success": "The changes were successfully applied.",
+       "tags-edit-success": "The changes were applied.",
        "tags-edit-failure": "The changes could not be applied:\n$1",
        "tags-edit-nooldid-title": "Invalid target revision",
        "tags-edit-nooldid-text": "You have either not specified any target revision on which to perform this function, or the specified revision does not exist.",
index 79e1cfd..21ecee3 100644 (file)
        "changecontentmodel-nodirectediting": "El modelo de contenido $1 no admite la edición directa",
        "log-name-contentmodel": "Registro de cambios del modelo de contenido",
        "log-description-contentmodel": "Eventos relacionados con los modelos de contenido de una página",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|creó}} la página $3 usando un modelo de contenido no predeterminado \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|cambió}} el modelo de contenido de la página $3 de \"$4\" a \"$5\"",
        "logentry-contentmodel-change-revertlink": "revertir",
        "logentry-contentmodel-change-revert": "revertir",
index a6a5652..7b007e8 100644 (file)
        "changecontentmodel-nodirectediting": "نمونه محتوی $1 امکان ویرایش مستقیم را پشتیبانی نمی‌کند",
        "log-name-contentmodel": "سیاهه تغییر نمونه محتوی",
        "log-description-contentmodel": "رویدادهای مرتبط با نمونه محتوی‌های یک صفحه",
+       "logentry-contentmodel-new": "صفحهٔ $3 با استفاده از مدل‌های محتوایی غیر پیش‌فرض «$5» توسط $1 {{GENDER:$2|ساخته شد}}",
        "logentry-contentmodel-change": "نمونه محتوای صفحهٔ $3 از \"$4\" به \"$5\" توسط $1 {{GENDER:$2|تغییر داده شد}}",
        "logentry-contentmodel-change-revertlink": "واگردانی",
        "logentry-contentmodel-change-revert": "واگردانی",
index 2cac81f..805ed0e 100644 (file)
@@ -18,6 +18,7 @@
        "tog-hideminor": "Krógva minni broytingar í seinastu broytingum",
        "tog-hidepatrolled": "Krógva eftirkannaðar rættingar í seinastu broytingum",
        "tog-newpageshidepatrolled": "Goym eftirkannaðar síður frá listanum yvir nýggjar síður",
+       "tog-hidecategorization": "Fjal bólking av síðum",
        "tog-extendwatchlist": "Víðka eftirlitslistan fyri at vísa allar broytingar, ikki bara tær seinastu",
        "tog-usenewrc": "Bólka broytingar eftir síðu í seinastu broytingum og eftirlitslita",
        "tog-numberheadings": "Sjálvvirkandi talmerking av yvirskriftum",
@@ -46,6 +47,7 @@
        "tog-watchlisthideliu": "Goym broytingar sum eru gjørdar av brúkarum, sum eru loggaðir á, frá hyggjaralistanum",
        "tog-watchlisthideanons": "Krógva broytingar sum eru gjørdar av dulnevndum brúkarum frá eftirlitslistanum",
        "tog-watchlisthidepatrolled": "Fjal eftirhugdar broytingar frá eftirlitslistanum",
+       "tog-watchlisthidecategorization": "Fjal bólking av síðum",
        "tog-ccmeonemails": "Send mær avrit av teldubrøvum, sum eg sendi til aðrar brúkarar",
        "tog-diffonly": "Vís ikki innihaldið av síðuni undir broytingum",
        "tog-showhiddencats": "Vís goymdir bólkar",
        "morenotlisted": "Hesin listin er ikki liðugur.",
        "mypage": "Síða",
        "mytalk": "Kjak",
-       "anontalk": "Kjak til hesa IP-adressuna",
+       "anontalk": "Kjak",
        "navigation": "Navigatión",
        "and": "&#32;og",
        "qbfind": "Finn",
        "pool-timeout": "Støðgur, bíða verður eftir lásinum",
        "pool-queuefull": "Køin til \"hylin\" er full",
        "pool-errorunknown": "Ókend villa",
+       "pool-servererror": "Pool counter-tænastan er ikki tøk ($1).",
+       "poolcounter-usage-error": "Nýtslufeilur: $1",
        "aboutsite": "Um {{SITENAME}}",
        "aboutpage": "Project:Um",
        "copyright": "Innihaldið er tøkt undir $1, um ikki annað er viðmerkt.",
        "nstab-template": "Fyrimynd",
        "nstab-help": "Hjálp",
        "nstab-category": "Bólkur",
+       "mainpage-nstab": "Forsíða",
        "nosuchaction": "Ongin slík gerð",
        "nosuchactiontext": "Gerðin, ið tilskilað er í url, virkar ikki.\nMøguliga hevur tú stava urlin skeivt, ella fylgt einari skeivari leinkju.\nHetta kann eisini benda á ein feil í software'ini sum {{SITENAME}} brúkar.",
        "nosuchspecialpage": "Ongin slík serlig síða",
        "filerenameerror": "Kundi ikki umdoypa fílu \"$1\" til \"$2\".",
        "filedeleteerror": "Kundi ikki strika fíluna \"$1\".",
        "directorycreateerror": "Kundi ikki upprætta mappuna \"$1\".",
+       "directoryreadonlyerror": "Faldarin \"$1\" er vardur móti skriving.",
+       "directorynotreadableerror": "Faldarin \"$1\" er ikki lesbarur.",
        "filenotfound": "Kundi ikki finna fílu \"$1\".",
        "unexpected": "Óvæntað virði: \"$1\"=\"$2\".",
        "formerror": "Villa: Kundi ikki senda skránna.",
        "viewsource": "Vís keldu",
        "viewsource-title": "Sí keldu fyri $1",
        "actionthrottled": "Hendingin kvaldist",
-       "actionthrottledtext": "↓ Fyri at mótvirka spam, er tað ikki møguligt at gera hetta alt ov nógvar ferðir uppá stutta tíð, og tú ert farin yvir tað markið.\nVinarliga royn aftur um fáir minuttir.",
+       "actionthrottledtext": "Fyri at mótvirka spam, er tað ikki møguligt at gera hetta alt ov nógvar ferðir uppá stutta tíð, og tú ert farin yvir tað markið.\nVinarliga royn aftur um fáir minuttir.",
        "protectedpagetext": "Hendan síða er blivin vard fyri at steðga rættingum ella øðrum handlingum.",
-       "viewsourcetext": "Tú kanst síggja og avrita kelduna til hesa grein:",
-       "viewyourtext": "Tú kanst síggja og avrita kelduna fyri '''tínar rættingar''' til hesa síðuna:",
+       "viewsourcetext": "Tú kanst síggja og avrita kelduna til hesa grein.",
+       "viewyourtext": "Tú kanst síggja og avrita kelduna til <strong>tínar rættingar</strong> til hesa síðuna.",
        "protectedinterface": "↓ Henda síðan gevur markamóts tekst til ritbúnaðin (software), og er vard fyri at fyribyrgja misnýtslu.\nFyri at gera rættingar ella broyta týðingar á øllum wiki'um, vinarliga nýt [//translatewiki.net/ translatewiki.net], MediaWiki verkætlanina.",
-       "editinginterface": "↓ '''Ávaring:''' Tú rættar eina síðu sum verður brúkt til at geva markamóts tekst til ritbúnaðin (software).\nBroytingar á hesi síðu fara at ávirka útsjóndina á brúkara markamótinum (interface) fyri aðrar brúkarar á hesi wiki.\nFyri at gera týðingar ella broyta týðingar á øllum wiki, vinarliga nýt [//translatewiki.net/ translatewiki.net],  sum er ein MediaWiki verkætlan.",
-       "cascadeprotected": "Henda síðan er vard fyri rættingum, tí hon er í fylgjandi {{PLURAL:$1|síðu, sum er|síðum, sum eru}}\nvardar við \"arvaðari síðuverjing\"\n$2",
+       "editinginterface": "<strong>Ávaring:</strong> Tú rættar eina síðu sum verður brúkt til at geva markamóts tekst til ritbúnaðin (software).\nBroytingar á hesi síðu fara at ávirka útsjóndina á brúkara markamótinum (interface) fyri aðrar brúkarar á hesi wiki.",
+       "translateinterface": "Fyri at gera ella broyta týðingar fyri allar wikiir, vinarliga nýt [//translatewiki.net/ translatewiki.net], the MediaWiki staðsetingar verkætlan.",
+       "cascadeprotected": "Henda síðan er vard fyri rættingum, tí hon er í fylgjandi {{PLURAL:$1|síðu, sum er|síðum, sum eru}}\nvardar við \"niðurarvan\" møguleikanum tendraðum:\n$2",
        "namespaceprotected": "Tú hevur ikki loyvi til at rætta síður í $1 navnateiginum.",
        "customcssprotected": "Tú hevur ikki loyvi til at rætta hesa CSS síðuna, tí hon inniheldur persónligar innstillingar hjá øðrum brúkara.",
        "customjsprotected": "Tú hevur ikki loyvir til at rætta hesa JavaScript síðuna, tí hon inniheldur persónligar innstillingar hjá øðrum brúkara.",
        "mypreferencesprotected": "Tú hevur ikki loyvi til at rætta tínar preferensur.",
        "ns-specialprotected": "Serstakar síður kunnu ikki rættast.",
        "titleprotected": "[[User:$1|$1]] hevur vart hetta heitið frá skapan.\nGivin orsøk er <em>$2</em>.",
-       "filereadonlyerror": "Tað var ikki møguligt at broyta fíluna \"$1\" tí at fílugoymslan \"$2\" er í bara-lesa støðu.\n\nUmboðsstjórin sum stongdi hana, gav hesa frágreiðing: \"$3\".",
+       "filereadonlyerror": "Tað var ikki møguligt at broyta fíluna \"$1\" tí at fílugoymslan \"$2\" er skrivivard.\n\nSkipanaradministratorurin sum stongdi hana, gav hesa frágreiðing: \"$3\".",
        "invalidtitle-knownnamespace": "Ógyldugt heiti við navnaøki \"$2\" og teksti \"$3\"",
        "invalidtitle-unknownnamespace": "Ógyldigt heiti við ókendum navnaøkis tali $1 og teksti \"$2\"",
        "exception-nologin": "Tú ert ikki loggað/ur inn",
-       "exception-nologin-text": "Vinarliga [[Special:Userlogin|rita inn]] fyri at fáa atgongd til hesa síðu ella handling.",
+       "exception-nologin-text": "Vinarliga rita inn fyri at fáa atgongd til hesa síðu ella handling.",
        "exception-nologin-text-manual": "Vinarliga $1 fyri at fáa atgongd til hesa síðu ella handling.",
        "virus-badscanner": "Konfiguratións villa: Ókendur virus skannari: ''$1''",
        "virus-scanfailed": "↓  skanning virkaði ikki (kota $1)",
        "virus-unknownscanner": "ókent antivirus:",
        "logouttext": "'''Tú hevur nú ritað út.'''\n \nLegg til merkis, at summar síður framvegis vera vístar, sum um tú enn vart loggað/ur á, til tú hevur reinsað tín brovsara fyri \"cache\".",
+       "cannotlogoutnow-title": "Tað ber ikki til at rita út nú",
        "welcomeuser": "Vælkomin, $1!",
        "welcomecreation-msg": "Tín konta er nú stovnað.\nGloym ikki at broyta tínar [[Special:Preferences|{{SITENAME}}-innstillingar]].",
        "yourname": "Títt brúkaranavn:",
        "resetpass_submit": "Vel loyniorð og rita inn",
        "changepassword-success": "Títt loyniorð er nú broytt!",
        "changepassword-throttled": "Tú hevur roynt at rita inn ov nógvar ferðir nýliga.\nVinarliga bíða $1 áðrenn tú roynir aftur.",
+       "botpasswords-label-create": "Upprætta",
+       "botpasswords-label-update": "Dagfør",
+       "botpasswords-label-cancel": "Avbrót",
+       "botpasswords-label-delete": "Strika",
+       "botpasswords-label-resetpassword": "Nullstilla loyniorðið",
        "resetpass_forbidden": "Loyniorð kunnu ikki broytast",
        "resetpass-no-info": "Tú mást vera loggaður á fyri at fáa beinleiðis atgongd til hesa síðu.",
        "resetpass-submit-loggedin": "Broyt loyniorð",
        "sig_tip": "Tín undirskrift við tíðarstempli",
        "hr_tip": "Vatnrøtt linja (vera sparin við)",
        "summary": "Samandráttur:",
-       "subject": "Evni/heiti:",
+       "subject": "Evni:",
        "minoredit": "Hetta er smábroyting",
        "watchthis": "Hav eftirlit við hesi síðuni",
        "savearticle": "Goym síðu",
        "notextmatches": "Ongin síðutekstur samsvarar",
        "prevn": "undanfarnu {{PLURAL:$1|$1}}",
        "nextn": "næstu {{PLURAL:$1|$1}}",
+       "prev-page": "undanfarna síða",
        "next-page": "næsta síða",
        "prevn-title": "Gomul $1 {{PLURAL:$1|úrslit|úrslit}}",
        "nextn-title": "Næstu $1 {{PLURAL:$1|úrslit|úrslit}}",
        "search-redirect": "(umstilling $1)",
        "search-section": "(sektión $1)",
        "search-category": "(bólkur $1)",
+       "search-file-match": "(svarar til innihaldið av fíluni)",
        "search-suggest": "Meinti tú: $1",
+       "search-rewritten": "Vísir úrslit fyri $1. Leita í staðin eftir $2.",
        "search-interwiki-caption": "Líknandi verkætlanir",
        "search-interwiki-default": "Úrslit frá $1:",
        "search-interwiki-more": "(meira)",
        "showingresultsinrange": "Niðanfyri verða víst upp til {{PLURAL:$1|<strong>1</strong> úrslit|<strong>$1</strong> úrslit}} í økinum #<strong>$2</strong> til #<strong>$3</strong>.",
        "search-showingresults": "{{PLURAL:$4|Úrslit <strong>$1</strong> av <strong>$3</strong>|Úrslit <strong>$1 - $2</strong> av <strong>$3</strong>}}",
        "search-nonefound": "Leitingin gav onki úrslit.",
+       "search-nonefound-thiswiki": "Ongi úrslit passaðu til fyrispurningin á hesi síðu.",
        "powersearch-legend": "Víðkað leitan",
        "powersearch-ns": "Leita í navnaøkinum:",
        "powersearch-togglelabel": "Kanna eftir:",
        "preferences": "Innstillingar",
        "mypreferences": "Innstillingar",
        "prefs-edits": "Tal av rættingum:",
-       "prefsnologintext2": "Vinarliga $1 fyri at broyta tínar innstillingat.",
+       "prefsnologintext2": "Vinarliga rita inn fyri at broyta tínar innstillingar.",
        "prefs-skin": "Hamur",
        "skin-preview": "Forskoðan",
        "datedefault": "Ongi serlig ynskir",
        "prefs-personal": "Brúkaradáta",
        "prefs-rc": "Nýkomnar broytingar og stubbaskoðan",
        "prefs-watchlist": "Eftirlit",
+       "prefs-editwatchlist": "Rætta eftirlitslistan",
+       "prefs-editwatchlist-clear": "Rudda tín eftirlitslista",
        "prefs-watchlist-days": "Tal av døgum, sum skula vísast í eftirliti:",
        "prefs-watchlist-days-max": "Í mesta lagi $1 {{PLURAL:$1|dagur|dagar}}",
        "prefs-watchlist-edits": "Tal av rættingum, sum skula vísast í víðkaðum eftirliti:",
        "prefs-watchlist-token": "Lykil til eftirlitslistan:",
        "prefs-misc": "Ymiskar innstillingar",
        "prefs-resetpass": "Broyt loyniorð",
-       "prefs-changeemail": "Broyt t-post adressu",
+       "prefs-changeemail": "Broyt ella tak burtur t-post adressu",
        "prefs-setemail": "Skriva tína t-post adressu",
        "prefs-email": "T-post møguleikar",
        "prefs-rendering": "Útsjónd",
        "rows": "Røð:",
        "columns": "Teigar:",
        "searchresultshead": "Leita",
-       "stub-threshold": "Avmarkað til <a href=\"#\" class=\"stub\">stubba leinki</a> formatering (bytes):",
+       "stub-threshold": "Avmarkað til stubba leinki formatering $1:",
+       "stub-threshold-sample-link": "dømi",
        "stub-threshold-disabled": "Er gjørt óvirki",
        "recentchangesdays": "Dagar av vísa í seinastu broytingum:",
        "recentchangesdays-max": "Í mesta lagi $1 {{PLURAL:$1|dagur|dagar}}",
index d64d4db..a0ef809 100644 (file)
        "changecontentmodel-nodirectediting": "Le modèle de contenu $1 ne permet pas la modification directe",
        "log-name-contentmodel": "Journal de modification de modèle de contenu",
        "log-description-contentmodel": "Événements relatifs aux modèles de contenu d’une page",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|a créé}} la page $3 en utilisant un modèle de contenu « $5 » autre que celui par défaut",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|a modifié}} le modèle de contenu de la page $3 de « $4 » en « $5 »",
        "logentry-contentmodel-change-revertlink": "rétablir",
        "logentry-contentmodel-change-revert": "rétablir",
index c20e7e9..97548fe 100644 (file)
        "category-empty": "<em>Ora cela catègoria contint gins de pâge de fichiér multimèdiâ.</em>",
        "hidden-categories": "{{PLURAL:$1|Catègoria cachiêe|Catègories cachiêes}}",
        "hidden-category-category": "Catègories cachiêes",
-       "category-subcat-count": "Cela catègoria-que at {{PLURAL:$2|mas que cela sot-catègoria.|{{PLURAL:$1|cela sot-catègoria|celes $1 sot-catègories}}, sur na soma de $2.}}",
-       "category-subcat-count-limited": "Cela catègoria-que at {{PLURAL:$1|cela sot-catègoria|celes $1 sot-catègories}}.",
-       "category-article-count": "{{PLURAL:$2|Cela catègoria-que contint mas que cela pâge.|{{PLURAL:$1|Cela pâge est|Celes $1 pâges sont}} a cela catègoria-que, sur na soma de $2.}}",
-       "category-article-count-limited": "{{PLURAL:$1|Cela pâge figure|Celes $1 pâges figuront}} dedens la presenta catègoria.",
-       "category-file-count": "{{PLURAL:$2|Cela catègoria-que contint mas que cél fichiér.|{{PLURAL:$1|Cél fichiér est|Celos $1 fichiérs sont}} a cela catègoria-que, sur na soma de $2.}}",
-       "category-file-count-limited": "{{PLURAL:$1|Cél fichiér figure|Celos $1 fichiérs figuront}} dedens la presenta catègoria.",
+       "category-subcat-count": "Cela catègoria at {{PLURAL:$2|mas que cela sot-catègoria-que.|{{PLURAL:$1|cela sot-catègoria|celes $1 sot-catègories}}-que, sur na soma de $2.}}",
+       "category-subcat-count-limited": "Cela catègoria at {{PLURAL:$1|cela sot-catègoria|celes $1 sot-catègories}}-que.",
+       "category-article-count": "{{PLURAL:$2|Cela catègoria contint mas que cela pâge-que.|{{PLURAL:$1|Cela pâge-que est|Celes $1 pâges-que sont}} a cela catègoria, sur na soma de $2.}}",
+       "category-article-count-limited": "{{PLURAL:$1|Cela pâge-que figure|Celes $1 pâges-que figuront}} dedens la presenta catègoria.",
+       "category-file-count": "{{PLURAL:$2|Cela catègoria contint mas que cél fichiér-que.|{{PLURAL:$1|Cél fichiér-que est|Celos $1 fichiérs-que sont}} a cela catègoria, sur na soma de $2.}}",
+       "category-file-count-limited": "{{PLURAL:$1|Cél fichiér-que figure|Celos $1 fichiérs-que figuront}} dedens la presenta catègoria.",
        "listingcontinuesabbrev": "(suita)",
        "index-category": "Pâges endèxâyes",
        "noindex-category": "Pâges pas endèxâyes",
        "title-invalid-magic-tilde": "Lo titro de la pâge demandâye contint na cobla de tildes magicos pas justa (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "Lo titro de la pâge demandâye est trop long. Dêt pas dèpassar $1 octèt{{PLURAL:$1||s}} dens l’encodâjo UTF-8.",
        "title-invalid-leading-colon": "Lo titro de la pâge demandâye contint un doux-pouents pas justo u comencement.",
-       "perfcached": "Celes balyês sont en cacho et pôvont pas étre a jorn. Por lo més {{PLURAL:$1|un rèsultat est disponiblo|$1 rèsultats sont disponiblos}} dedens lo cacho.",
-       "perfcachedts": "Celes balyês sont en cacho et sont étâyes betâyes a jorn por lo dèrriér côp lo $1. Por lo més {{PLURAL:$4|un rèsultat est disponiblo|$4 rèsultats sont disponiblos}} dedens lo cacho.",
+       "perfcached": "Celes balyês-que sont en cacho et pôvont pas étre a jorn. Por lo més {{PLURAL:$1|un rèsultat est disponiblo|$1 rèsultats sont disponiblos}} dedens lo cacho.",
+       "perfcachedts": "Celes balyês-que sont en cacho et sont étâyes betâyes a jorn por lo dèrriér côp lo $1. Por lo més {{PLURAL:$4|un rèsultat est disponiblo|$4 rèsultats sont disponiblos}} dedens lo cacho.",
        "querypage-no-updates": "Ora les mêses a jorn por cela pâge sont dèsactivâyes.\nLes balyês ique seront pas betâyes a jorn.",
        "viewsource": "Vêre lo tèxto sôrsa",
        "viewsource-title": "Vêre lo tèxto sôrsa de $1",
        "protectedinterface": "Cela pâge-que balye de tèxto d’entèrface por la programeria sur cél vouiqui et est vêr protègiêe por èvitar los abus.\nPor apondre ou ben changiér de traduccions sur tôs los vouiquis, se vos plét empleyéd [//translatewiki.net/ translatewiki.net], lo projèt de localisacion de MediaWiki.",
        "editinginterface": "<strong>Atencion :</strong> vos éte aprés changiér na pâge empleyêe por fâre lo tèxto d’entèrface de la programeria.\nLos changements sè cognetront sur l’aparence de l’entèrface utilisator por los ôtros utilisators de cél vouiqui.",
        "translateinterface": "Por apondre ou ben changiér des traduccions sur tôs los vouiquis, se vos plét empleyéd [//translatewiki.net/ translatewiki.net], lo projèt de localisacion de MediaWiki.",
-       "cascadeprotected": "Cela pâge-que est protègiêe contre los changements perce qu’el est transcllua per {{PLURAL:$1|cela pâge qu’est étâye protègiêe|celes pâges que sont étâyes protègiêes}} avouéc lo chouèx « protèccion en cascâda » activâ :\n$2",
+       "cascadeprotected": "Cela pâge est protègiêe contre los changements perce qu’el est transcllua per {{PLURAL:$1|cela pâge-que qu’est étâye protègiêe|celes pâges-que que sont étâyes protègiêes}} avouéc lo chouèx « protèccion en cascâda » activâ :\n$2",
        "namespaceprotected": "Vos éd pas la pèrmission de changiér les pâges de l’èspâço de noms « <strong>$1</strong> ».",
        "customcssprotected": "Vos éd pas la pèrmission de changiér cela pâge CSS perce que contint la configuracion a sè d’un ôtr’utilisator.",
        "customjsprotected": "Vos éd pas la pèrmission de changiér cela pâge JavaScript perce que contint la configuracion a sè d’un ôtr’utilisator.",
        "mailerror": "Fôta pendent l’èxpèdicion du mèssâjo : $1",
        "acct_creation_throttle_hit": "Des vesitors de cél vouiqui-que qu’emplèyont voutron adrèce IP ant fêt $1 comptio{{PLURAL:$1||s}} pendent lo jorn passâ, cen qu’est lo més ôtorisâ dens ceti temps.\nDu côp los vesitors qu’emplèyont cel’adrèce IP pôvont fâre gins de comptio por lo moment.",
        "emailauthenticated": "Voutron adrèce èlèctronica est étâye confirmâye lo $2 a $3.",
-       "emailnotauthenticated": "Voutron adrèce èlèctronica est p’oncor confirmâye.\nNion mèssâjo serat mandâ por châcuna de celes fonccionalitâts.",
+       "emailnotauthenticated": "Voutron adrèce èlèctronica est p’oncor confirmâye.\nNion mèssâjo serat mandâ por châcuna de celes fonccionalitâts-que.",
        "noemailprefs": "Spècifiâd un’adrèce èlèctronica dens voutres prèferences por empleyér celes fonccionalitâts.",
        "emailconfirmlink": "Confirmâd voutron adrèce èlèctronica",
        "invalidemailaddress": "Cel’adrèce èlèctronica pôt pas étre accèptâye perce que semble avêr un format pas justo.\nSe vos plét, buchiéd un’adrèce ben formatâye ou ben lèssiéd cél champ vouedo.",
        "createaccount-text": "Yon at fêt un comptio por voutron adrèce èlèctronica dessus {{SITENAME}} ($4) apelâ « $2 », avouéc lo contresegno « $3 ».\nVos vos devriâd branchiér et pués changiér dês ora voutron contresegno.\n\nIgnorâd cél mèssâjo-que se cél compto est étâ fêt per fôta.",
        "login-throttled": "Dês pou vos éd èprovâ un mouél de branchements.\nSe vos plét, atende-vos $1 devant que tornar èprovar.",
        "login-abort-generic": "Voutron branchement at pas reussi - Anulâ",
-       "login-migrated-generic": "Voutron comptio est étâ migrâ, et pués voutron nom d’utilisator ègziste pas més dessus cél vouiqui.",
+       "login-migrated-generic": "Voutron comptio est étâ migrâ, et pués voutron nom d’utilisator ègziste pas més sur cél vouiqui.",
        "loginlanguagelabel": "Lengoua : $1",
        "suspicious-userlogout": "Voutra demanda de dèbranchement est étâye refusâye perce que semble qu’est étâye mandâye per un navegator câsso ou ben la mêsa en cacho d’un proxi.",
        "createacct-another-realname-tip": "Lo veré nom est u chouèx.\nSe vos dècidâd de lo balyér, serat empleyê por atribuar a l’utilisator ses ôvres.",
        "changeemail-throttled": "Vos éd èprovâ un mouél de branchements.\nSe vos plét, atende-vos $1 devant que tornar èprovar.",
        "changeemail-nochange": "Se vos plét, buchiéd na novèl’adrèce èlèctronica difèrenta.",
        "resettokens": "Rebetar a zérô los jetons",
-       "resettokens-text": "Ique, vos pouede rebetar a zérô los jetons que pèrmètont d’arrevar a quârques balyês privâyes associyêes a voutron comptio.\n\nVos o devriâd fâre se vos los éd partagiês per accident avouéc yon ou ben se voutron comptio est étâ compromètu.",
+       "resettokens-text": "Ique, vos pouede rebetar a zérô los jetons que pèrmètont d’arrevar a quârques balyês privâyes associyêes a voutron comptio.\n\nVos o devriâd fâre se vos los éd partagiês per accident avouéc yon ou ben se voutron comptio est étâ comprometu.",
        "resettokens-no-tokens": "Y at gins de jeton a rebetar a zérô.",
        "resettokens-tokens": "Jetons :",
        "resettokens-token-label": "$1 (valor d’ora : $2)",
        "loginreqlink": "branchiér",
        "loginreqpagetext": "Se vos plét, vos vos dête $1 por povêr vêre les ôtres pâges.",
        "accmailtitle": "Contresegno mandâ",
-       "accmailtext": "Un contresegno fêt a l’hasârd por [[User talk:$1|$1]] est étâ mandâ a $2. Pôt étre changiê sur la pâge de <em>[[Special:ChangePassword|changement de contresegno]]</em> aprés branchement.",
+       "accmailtext": "Un contresegno fêt a l’hasârd por [[User talk:$1|$1]] est étâ mandâ a $2. Pôt étre changiê dessus la pâge de <em>[[Special:ChangePassword|changement de contresegno]]</em> aprés branchement.",
        "newarticle": "(Novél)",
-       "newarticletext": "Vos éd siuvu un lim de vers na pâge qu’ègziste p’oncor.\nPor fâre cela pâge, buchiéd voutron tèxto dedens la bouèta ce-desot (vêde la [$1 pâge d’éde] por més d’enformacions).\nSe vos éte arrevâ{{GENDER:||ye}} ique per fôta, cllicâd sur lo boton <strong>Devant</strong> de voutron navegator.",
+       "newarticletext": "Vos éd siuvu un lim de vers na pâge qu’ègziste p’oncor.\nPor fâre cela pâge, buchiéd voutron tèxto dedens la bouèta ce-desot (vêde la [$1 pâge d’éde] por més d’enformacions).\nSe vos éte arrevâ{{GENDER:||ye}} ique per fôta, cllicâd dessus lo boton <strong>Devant</strong> de voutron navegator.",
        "anontalkpagetext": "----\n<em>O est la pâge de discussion d’un utilisator anonimo qu’at p’oncor fêt un comptio ou ben que nen emplèye pas.</em>\nPor cen, nos devens empleyér son adrèce IP numerica por o identifiar.\nUn’adrèce IP d’ense pôt étre partagiêe per un mouél d’utilisators.\nSe vos éte {{GENDER:|un utilisator|un’utilisatrice}} anonim{{GENDER:|o|a}} et pués se vos constatâd que des comentèros que vos regârdont pas vos sont étâs adrèciês, se vos plét [[Special:UserLogin/signup|féte un comptio]] ou ben [[Special:UserLogin|branchiéd-vos]] por èvitar tota confusion que vint avouéc d’ôtros utilisators anonimos.",
        "noarticletext": "Ora y at gins de tèxto dedens cela pâge.\nVos pouede [[Special:Search/{{PAGENAME}}|fâre na rechèrche sur cél titro]] dedens les ôtres pâges,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechèrchiér dedens los jornâls liyês]\nou ben [{{fullurl:{{FULLPAGENAME}}|action=edit}} fâre cela pâge]</span>.",
        "noarticletext-nopermission": "Ora y at gins de tèxto dedens cela pâge.\nVos pouede [[Special:Search/{{PAGENAME}}|fâre na rechèrche sur cél titro]] dedens les ôtres pâges ou ben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} rechèrchiér dedens los jornâls liyês]</span>, mas vos éd pas la pèrmission de fâre cela pâge.",
-       "missing-revision": "La vèrsion n° $1 de la pâge apelâye « {{FULLPAGENAME}} » ègziste pas.\n\nEn g·ènèrâl cen arreve en siuvent un lim dèpassâ d’un historico de vers na pâge qu’est étâye suprimâye.\nVos pouede trovar més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
+       "missing-revision": "La vèrsion n° $1 de la pâge apelâye « {{FULLPAGENAME}} » ègziste pas.\n\nEn g·ènèrâl cen arreve en siuvent un lim dèpassâ d’un historico de vers na pâge qu’est étâye suprimâye.\nVos pouede trovar més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
        "userpage-userdoesnotexist": "Lo comptio utilisator « $1 » est pas encartâ.\nSe vos plét, controlâd se vos voléd fâre ou ben changiér cela pâge.",
        "userpage-userdoesnotexist-view": "Lo comptio utilisator « $1 » est pas encartâ.",
        "blocked-notice-logextract": "Ora {{GENDER:$1|cél utilisator|cel’utilisatrice}} est blocâ{{GENDER:$1||ye}}.\nLa dèrriére entrâ du jornâl des blocâjos est balyêe ce-desot coment rèference :",
        "sectioneditnotsupported-title": "Changement de sèccion pas recognu",
        "sectioneditnotsupported-text": "Lo changement d’una sèccion est pas recognu dens cela pâge.",
        "permissionserrors": "Fôta de pèrmission",
-       "permissionserrorstext": "Vos éd pas la pèrmission de fâre l’accion demandâye por {{PLURAL:$1|cela rêson|celes rêsons}} :",
-       "permissionserrorstext-withaction": "Vos éd pas la pèrmission de $2 por {{PLURAL:$1|cela rêson|celes rêsons}} :",
+       "permissionserrorstext": "Vos éd pas la pèrmission de fâre l’accion demandâye por {{PLURAL:$1|cela rêson|celes rêsons}}-que :",
+       "permissionserrorstext-withaction": "Vos éd pas la pèrmission de $2 por {{PLURAL:$1|cela rêson|celes rêsons}}-que :",
        "contentmodelediterror": "Vos pouede pas changiér cela vèrsion perce que son modèlo de contegnu est <code>$1</code>, cen que sè difèrence du modèlo de contegnu d’ora de la pâge <code>$2</code>.",
        "recreate-moveddeleted-warn": "<strong>Atencion : vos éte aprés refâre na pâge qu’est étâye suprimâye dês devant.</strong>\n\nDemandâd-vos se fôt franc continuar son changement.\nLo jornâl de les suprèssions et des dèplacements de cela pâge est balyê ce-desot por comoditât :",
        "moveddeleted-notice": "Cela pâge est étâye suprimâye.\nLo jornâl de les suprèssions et des dèplacements de cela pâge est balyê ce-desot coment rèference.",
        "defaultmessagetext": "Mèssâjo per dèfôt",
        "content-failed-to-parse": "Falyita de l’analise du contegnu de $2 por lo modèlo $1 : $3",
        "invalid-content-data": "Balyês du contegnu pas justes",
-       "content-not-allowed-here": "Lo contegnu « $1 » est pas ôtorisâ sur la pâge [[$2]]",
+       "content-not-allowed-here": "Lo contegnu « $1 » est pas ôtorisâ dessus la pâge [[$2]]",
        "editwarning-warning": "Quitar cela pâge vos farat pèrdre tôs los changements que vos éd fêts.\nSe vos éte branchiê{{GENDER:||e}}, vos pouede dèsactivar cela semonce dedens la sèccion « {{int:prefs-editing}} » de voutres prèferences.",
        "editpage-notsupportedcontentformat-title": "Format de contegnu pas recognu",
        "editpage-notsupportedcontentformat-text": "Lo format de contegnu $1 est pas recognu per lo modèlo de contegnu $2.",
        "rev-deleted-user": "(nom d’utilisator enlevâ)",
        "rev-deleted-event": "(dètalys du jornâl enlevâs)",
        "rev-deleted-user-contribs": "[nom d’utilisator ou ben adrèce IP enlevâ(ye) - changement cachiê sur les contribucions]",
-       "rev-deleted-text-permission": "Cela vèrsion de la pâge est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
-       "rev-suppressed-text-permission": "Cela vèrsion de la pâge est étâye <strong>rèprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].",
-       "rev-deleted-text-unhide": "Cela vèrsion de la pâge est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].\nVos pouede adés [$1 vêre cela vèrsion] se vos o voléd.",
-       "rev-suppressed-text-unhide": "Cela vèrsion de la pâge est étâye <strong>rèprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].\nVos pouede adés [$1 vêre cela vèrsion] se vos o voléd.",
-       "rev-deleted-text-view": "Cela vèrsion de la pâge est étâye <strong>suprimâye</strong>.\nVos la pouede vêre ; y pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
-       "rev-suppressed-text-view": "Cela vèrsion de la pâge est étâye <strong>rèprimâye</strong>.\nVos la pouede vêre ; y pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].",
-       "rev-deleted-no-diff": "Vos pouede pas vêre cela dif perce que yona de les vèrsions est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
+       "rev-deleted-text-permission": "Cela vèrsion de la pâge est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
+       "rev-suppressed-text-permission": "Cela vèrsion de la pâge est étâye <strong>rèprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].",
+       "rev-deleted-text-unhide": "Cela vèrsion de la pâge est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].\nVos pouede adés [$1 vêre cela vèrsion] se vos o voléd.",
+       "rev-suppressed-text-unhide": "Cela vèrsion de la pâge est étâye <strong>rèprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].\nVos pouede adés [$1 vêre cela vèrsion] se vos o voléd.",
+       "rev-deleted-text-view": "Cela vèrsion de la pâge est étâye <strong>suprimâye</strong>.\nVos la pouede vêre ; y pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
+       "rev-suppressed-text-view": "Cela vèrsion de la pâge est étâye <strong>rèprimâye</strong>.\nVos la pouede vêre ; y pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].",
+       "rev-deleted-no-diff": "Vos pouede pas vêre cela dif perce que yona de les vèrsions est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
        "rev-suppressed-no-diff": "Vos pouede pas vêre cela dif perce que yona de les vèrsions est étâye <strong>suprimâye</strong>.",
-       "rev-deleted-unhide-diff": "Yona de les vèrsions de cela dif est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].\nVos pouede adés [$1 vêre cela dif] se vos o voléd.",
-       "rev-suppressed-unhide-diff": "Yona de les vèrsions de cela dif est étâye <strong>rèprimâye</strong>.\nY pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].\nVos pouede adés [$1 vêre cela dif] se vos o voléd.",
-       "rev-deleted-diff-view": "Yona de les vèrsions de cela dif est étâye <strong>suprimâye</strong>.\nVos pouede vêre cela dif ; y pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
-       "rev-suppressed-diff-view": "Yona de les vèrsions de cela dif est étâye <strong>rèprimâye</strong>.\nVos pouede vêre cela dif ; y pôt avêr més de dètalys sur lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].",
+       "rev-deleted-unhide-diff": "Yona de les vèrsions de cela dif est étâye <strong>suprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].\nVos pouede adés [$1 vêre cela dif] se vos o voléd.",
+       "rev-suppressed-unhide-diff": "Yona de les vèrsions de cela dif est étâye <strong>rèprimâye</strong>.\nY pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].\nVos pouede adés [$1 vêre cela dif] se vos o voléd.",
+       "rev-deleted-diff-view": "Yona de les vèrsions de cela dif est étâye <strong>suprimâye</strong>.\nVos pouede vêre cela dif ; y pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
+       "rev-suppressed-diff-view": "Yona de les vèrsions de cela dif est étâye <strong>rèprimâye</strong>.\nVos pouede vêre cela dif ; y pôt avêr més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} jornâl de les rèprèssions].",
        "rev-delundel": "changiér la visibilitât",
        "rev-showdeleted": "montrar",
        "revisiondelete": "Suprimar ou ben refâre de vèrsions",
        "logdelete-text": "Los èvènements du jornâl suprimâs continueront a aparêtre dedens los jornâls, mas na partia de lor contegnu serat inaccèssibla u publico.",
        "revdelete-text-others": "Los ôtros administrators porront adés arrevar u contegnu cachiê et lo refâre, a muens que des rèstriccions de més seyont dèfenies.",
        "revdelete-confirm": "Se vos plét, confirmâd qu’o est franc cen que vos voléd fâre, que vos en compregnéd les consèquences, et pués que vos o féte en acôrd avouéc les [[{{MediaWiki:Policy-url}}|règlles]].",
-       "revdelete-suppress-text": "La rèprèssion dêt étre empleyêe <strong>ren que</strong> dens celos câs :\n* Enformacions que pôvont étre difamatouères\n* Enformacions a sè que vant pas avouéc\n*: <em>adrèce, numerô de tèlèfono, numerô d’identificacion nacionâl, et tot cen que vat avouéc</em>",
+       "revdelete-suppress-text": "La rèprèssion dêt étre empleyêe <strong>ren que</strong> dens celos câs-que :\n* Enformacions que pôvont étre difamatouères\n* Enformacions a sè que vant pas avouéc\n*: <em>adrèce, numerô de tèlèfono, numerô d’identificacion nacionâl, et tot cen que vat avouéc</em>",
        "revdelete-legend": "Dèfenir de rèstriccions de visibilitât",
        "revdelete-hide-text": "Tèxto de la vèrsion",
        "revdelete-hide-image": "Cachiér lo contegnu du fichiér",
        "revdelete-modify-missing": "Fôta en changient la piéce avouéc l’ID $1 : el est manquenta dedens la bâsa de balyês !",
        "revdelete-no-change": "<strong>Atencion :</strong> la piéce datâye du $1 a $2 at ja la configuracion de visibilitât demandâye.",
        "revdelete-concurrent-change": "Fôta en changient la piéce datâye du $1 a $2 : son statut semble étre étâ changiê per un ôtro justo que vos èprovâvâd d’o changiér.\nSe vos plét, controlâd los jornâls.",
-       "revdelete-only-restricted": "Fôta en cachient la piéce datâye du $1 a $2 : vos pouede pas rèprimar de piéces de la viua ux administrators sen chouèsir avouéc des ôtros chouèx de visibilitât.",
+       "revdelete-only-restricted": "Fôta en cachient la piéce datâye du $1 a $2 : vos pouede pas rèprimar de piéces de la viua ux administrators sen chouèsir avouéc dôtros chouèx de visibilitât.",
        "revdelete-reason-dropdown": "*Rêsons corentes de suprèssion\n** Violacion du drêt d’ôtor\n** Comentèros enformacions a sè que vant pas avouéc\n** Nom d’utilisator que vat pas avouéc\n** Enformacions que pôvont étre difamatouères",
        "revdelete-otherreason": "Ôtra rêson ou ben rêson de més :",
        "revdelete-reasonotherlist": "Ôtra rêson",
        "mergehistory-from": "Pâge d’origina :",
        "mergehistory-into": "Pâge de dèstinacion :",
        "mergehistory-list": "Historico des changements que pôvont étre fusionâs",
-       "mergehistory-merge": "Celes vèrsions de [[:$1]] pôvont étre fusionâyes dedens [[:$2]].\nEmpleyéd la colona de botons de chouèx por fusionar mas que les vèrsions fêtes dês lo comencement tant qu’a la dâta spècifiâye.\nNotâd que l’usâjo des lims de navegacion rebeterat a zérô cela colona.",
+       "mergehistory-merge": "Celes vèrsions-que de [[:$1]] pôvont étre fusionâyes dedens [[:$2]].\nEmpleyéd la colona de botons de chouèx por fusionar mas que les vèrsions fêtes dês lo comencement tant qu’a la dâta spècifiâye.\nNotâd que l’usâjo des lims de navegacion rebeterat a zérô cela colona.",
        "mergehistory-go": "Montrar los changements que pôvont étre fusionâs",
        "mergehistory-submit": "Fusionar les vèrsions",
        "mergehistory-empty": "Niona vèrsion pôt étre fusionâye.",
        "diff-multi-sameuser": "({{PLURAL:$1|Na vèrsion entèrmèdièra per lo mém’utilisator pas montrâye|$1 vèrsions entèrmèdières per lo mém’utilisator pas montrâyes}})",
        "diff-multi-otherusers": "({{PLURAL:$1|Na vèrsion entèrmèdièra|$1 vèrsions entèrmèdières}} per {{PLURAL:$2|un ôtr’utilisator|$2 utilisators}} pas montrâye{{PLURAL:$1||s}})",
        "diff-multi-manyusers": "({{PLURAL:$1|Na vèrsion entèrmèdièra|$1 vèrsions entèrmèdières}} per més {{PLURAL:$2|d’un utilisator|de $2 utilisators}} {{PLURAL:$1|est pas montrâye|sont pas montrâyes}})",
-       "difference-missing-revision": "{{PLURAL:$2|Na vèrsion|$2 vèrsions}} de cela difèrence ($1) {{PLURAL:$2|est pas étâye trovâye|sont pas étâyes trovâyes}}.\n\nEn g·ènèrâl cen arreve en siuvent un lim dèpassâ d’una dif de vers na pâge qu’est étâye suprimâye.\nVos pouede trovar més de dètalys sur lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
+       "difference-missing-revision": "{{PLURAL:$2|Na vèrsion|$2 vèrsions}} de cela difèrence ($1) {{PLURAL:$2|est pas étâye trovâye|sont pas étâyes trovâyes}}.\n\nEn g·ènèrâl cen arreve en siuvent un lim dèpassâ d’una dif de vers na pâge qu’est étâye suprimâye.\nVos pouede trovar més de dètalys dessus lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornâl de les suprèssions].",
        "searchresults": "Rèsultats de la rechèrche",
        "searchresults-title": "Rèsultats de la rechèrche por « $1 »",
        "titlematches": "Corrèspondances dedens los titros de les pâges",
        "shown-title": "Montrar $1 rèsultat{{PLURAL:$1||s}} per pâge",
        "viewprevnext": "Vêre ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "<strong>Y at na pâge apelâye « [[:$1]] » sur cél vouiqui.</strong> {{PLURAL:$2|0=|Vêde avouéc los ôtros rèsultats de voutra rechèrche.}}",
-       "searchmenu-new": "<strong>Fâre la pâge « [[:$1|$1]] » sur cél vouiqui !</strong> {{PLURAL:$2|0=|Vêde avouéc la pâge trovâye avouéc voutra rechèrche.|Vêde avouéc los rèsultats de voutra rechèrche.}}",
+       "searchmenu-new": "<strong>Fâre la pâge « [[:$1|$1]] » sur cél vouiqui !</strong> {{PLURAL:$2|0=|Vêde asse-ben la pâge trovâye avouéc voutra rechèrche.|Vêde avouéc los rèsultats de voutra rechèrche.}}",
        "searchprofile-articles": "Pâges de contegnu",
        "searchprofile-images": "Multimèdiâ",
        "searchprofile-everything": "Tot",
        "yourvariant": "Vèrsion de la lengoua du contegnu :",
        "prefs-help-variant": "Voutra vèrsion voutron ortografia prèferâye por fâre vêre les pâges de contegnu de cél vouiqui.",
        "yournick": "Signatura novèla :",
-       "prefs-help-signature": "Los comentèros sur les pâges de discussion dêvont étre signês avouéc « <nowiki>~~~~</nowiki> » que serat convèrti per voutra signatura et un horodatâjo.",
+       "prefs-help-signature": "Los comentèros dessus les pâges de discussion dêvont étre signês avouéc « <nowiki>~~~~</nowiki> » que serat convèrti per voutra signatura et un horodatâjo.",
        "badsig": "Signatura bruta pas justa.\nControlâd les balises HTML.",
        "badsiglength": "Voutra signatura est trop longe.\nDêt pas dèpassar $1 caractèro{{PLURAL:$1||s}}.",
        "yourgender": "Coment vos prèferâd étre dècrit ?",
        "email": "Mèssageria èlèctronica",
        "prefs-help-realname": "Lo veré nom est u chouèx.\nS’il est balyê, serat empleyê por vos atribuar voutres ôvres.",
        "prefs-help-email": "L’adrèce èlèctronica est u chouèx, mas el est nècèssèra por rebetar a zérô voutron contresegno, se vos vegnévâd a l’oubliar.",
-       "prefs-help-email-others": "Vos porriâd avouéc chouèsir de lèssiér los ôtros lor veriér vers vos per mèssageria èlèctronica avouéc un lim sur voutra pâge utilisator ou ben de discussion sen que seye nècèssèro de rèvèlar voutron adrèce èlèctronica.",
+       "prefs-help-email-others": "Vos porriâd asse-ben chouèsir de lèssiér los ôtros lor veriér vers vos per mèssageria èlèctronica avouéc un lim sur voutra pâge utilisator ou ben de discussion sen que seye nècèssèro de rèvèlar voutron adrèce èlèctronica.",
        "prefs-help-email-required": "Un’adrèce èlèctronica est nècèssèra.",
        "prefs-info": "Enformacions de bâsa",
        "prefs-i18n": "Entèrnacionalisacion",
        "right-purge": "Purgiér lo cacho du seto d’una pâge sen confirmacion",
        "right-autoconfirmed": "Pas étre afèctâ per les limitacions de dèbit liyêes a les adrèces IP",
        "right-bot": "Étre trètâ coment un mècanismo ôtomatisâ",
-       "right-nominornewtalk": "Pas dècllenchiér la notificacion de mèssâjo novél quand fant un petiôt changement sur la pâge de discussion d’un utilisator",
+       "right-nominornewtalk": "Pas dècllenchiér la notificacion de mèssâjo novél quand fant un petiôt changement dessus la pâge de discussion d’un utilisator",
        "right-apihighlimits": "Empleyér de limites ples hôtes dedens les demandes API",
        "right-writeapi": "Empleyér l’API d’ècritura",
        "right-delete": "Suprimar de pâges",
        "upload_directory_read_only": "Lo rèpèrtouèro de tèlèchargement ($1) est pas accèssiblo en ècritura dês lo sèrvior Vouèbe.",
        "uploaderror": "Fôta pendent lo tèlèchargement",
        "upload-recreate-warning": "<strong>Atencion : un fichiér avouéc cél nom est étâ suprimâ ou ben dèplaciê.</strong>\n\nLo jornâl de les suprèssions et des dèplacements de cela pâge est balyê ique por comoditât :",
-       "uploadtext": "Empleyéd lo formulèro ce-desot por tèlèchargiér de fichiérs.\nPor vêre ou ben rechèrchiér de fichiérs tèlèchargiês dês devant, vêde la [[Special:FileList|lista des fichiérs tèlèchargiês]]. Los (re-)tèlèchargements sont asse-ben encartâs sur lo [[Special:Log/upload|jornâl des tèlèchargements]], et les suprèssions sur lo [[Special:Log/delete|jornâl de les suprèssions]].\n\nPor entrebetar un fichiér dedens na pâge, empleyéd un lim de yona de celes fôrmes :\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Fichiér.jpg]]</nowiki></code></strong> por empleyér la vèrsion en plêna largior du fichiér\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Fichiér.png|200px|thumb|left|tèxto dèscriptif]]</nowiki></code></strong> por empleyér na miniatura de 200 pixèls de lârjo dedens na bouèt’a gôche avouéc « tèxto dèscriptif » coment dèscripcion\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Fichiér.ogg]]</nowiki></code></strong> por liyér tot drêt vers lo fichiér sen lo fâre vêre",
+       "uploadtext": "Empleyéd lo formulèro ce-desot por tèlèchargiér de fichiérs.\nPor vêre ou ben rechèrchiér de fichiérs tèlèchargiês dês devant, vêde la [[Special:FileList|lista des fichiérs tèlèchargiês]]. Los (re-)tèlèchargements sont asse-ben encartâs dessus lo [[Special:Log/upload|jornâl des tèlèchargements]], et les suprèssions dessus lo [[Special:Log/delete|jornâl de les suprèssions]].\n\nPor entrebetar un fichiér dedens na pâge, empleyéd un lim de yona de celes fôrmes-que :\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Fichiér.jpg]]</nowiki></code></strong> por empleyér la vèrsion en plêna largior du fichiér\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Fichiér.png|200px|thumb|left|tèxto dèscriptif]]</nowiki></code></strong> por empleyér na miniatura de 200 pixèls de lârjo dedens na bouèt’a gôche avouéc « tèxto dèscriptif » coment dèscripcion\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Fichiér.ogg]]</nowiki></code></strong> por liyér tot drêt vers lo fichiér sen lo fâre vêre",
        "upload-permitted": "Tipo{{PLURAL:$2||s}} de fichiérs ôtorisâ{{PLURAL:$2||s}} : $1.",
        "upload-preferred": "Tipo{{PLURAL:$2||s}} de fichiérs prèferâ{{PLURAL:$2||s}} : $1.",
        "upload-prohibited": "Tipo{{PLURAL:$2||s}} de fichiérs dèfendu{{PLURAL:$2||s}} : $1.",
        "emptyfile": "Lo fichiér que vos éd tèlèchargiê semble étre vouedo.\nCen pôt étre diu a na fôta dedens lo nom du fichiér.\nSe vos plét, controlâd que vos voléd franc tèlèchargiér cél fichiér.",
        "windows-nonascii-filename": "Cél vouiqui recognêt pas los noms de fichiérs avouéc des caractèros spèciâls.",
        "fileexists": "Un fichiér avouéc cél nom ègziste ja, se vos plét controlâd <strong>[[:$1]]</strong> se {{GENDER:|vos}} éte pas de sûr de lo volêr changiér.\n[[$1|thumb]]",
-       "filepageexists": "La pâge de dèscripcion por cél fichiér est ja étâye fêta ique <strong>[[:$1]]</strong>, mas nion fichiér avouéc cél nom ègziste ora.\nLo rèsumâ que vos voléd buchiér aparêtrat pas sur la pâge de dèscripcion.\nPor o fâre, vos la devréd changiér a la man.\n[[$1|thumb]]",
+       "filepageexists": "La pâge de dèscripcion por cél fichiér est ja étâye fêta ique <strong>[[:$1]]</strong>, mas nion fichiér avouéc cél nom ègziste ora.\nLo rèsumâ que vos voléd buchiér aparêtrat pas dessus la pâge de dèscripcion.\nPor o fâre, vos la devréd changiér a la man.\n[[$1|thumb]]",
        "fileexists-extension": "Un fichiér avouéc un nom d’ense ègziste ja : [[$2|thumb]]\n* Nom du fichiér a tèlèchargiér : <strong>[[:$1]]</strong>\n* Nom du fichiér ègzistent : <strong>[[:$2]]</strong>\nPôt-étre vos voléd empleyér un nom ples prôpro ?",
        "fileexists-thumbnail-yes": "Lo fichiér semble étre un’émâge en talye rèduita <em>(miniatura)</em>.\n[[$1|thumb]]\nSe vos plét, controlâd lo fichiér <strong>[[:$1]]</strong>.\nSe lo fichiér controlâ est la mém’émâge avouéc la talye originâla, y at pas fôta de tèlèchargiér na miniatura de més.",
        "file-thumbnail-no": "Lo nom du fichiér comence per <strong>$1</strong>.\nSemble étre un’émâge en talye rèduita <em>(miniatura)</em>.\nSe vos éd cel’émâge en hôta rèsolucion, tèlèchargiéd-la, ôtrament changiéd son nom, se vos plét.",
        "php-uploaddisabledtext": "Los tèlèchargements de fichiérs sont dèsactivâs dedens PHP.\nSe vos plét, controlâd la configuracion de « file_uploads ».",
        "uploadscripted": "Cél fichiér contint de code HTML ou ben un scripte que porrêt étre entèrprètâ a tôrt per un navegator Vouèbe.",
        "upload-scripted-pi-callback": "Y at pas moyen de tèlèchargiér un fichiér que contint d’enstruccions de trètament de fôlye de stilo XML.",
-       "uploaded-script-svg": "Piéce ècrivâbla « $1 » trovâye dedens lo fichiér SVG tèlèchargiê.",
-       "uploaded-hostile-svg": "CSS pas de sûr trovâ dens la piéce de stilo d’un fichiér SVG tèlèchargiê.",
-       "uploaded-event-handler-on-svg": "La dèfinicion d’atributs de maneyor d’èvènement <code>$1=\"$2\"</code> est pas ôtorisâ dedens los fichiérs SVG.",
-       "uploaded-href-attribute-svg": "Los atributs href dedens los fichiérs SVG sont ôtorisâs ren que por s’en rèferar a de cibes http:// ou ben https://, <code>&lt;$1 $2=\"$3\"&gt;</code> trovâ.",
-       "uploaded-href-unsafe-target-svg": "href de vers des balyês pas de sûr trovâ dedens lo fichiér SVG tèlèchargiê : URI ciba <code>&lt;$1 $2=\"$3\"&gt;</code>.",
-       "uploaded-animate-svg": "Balisa « animate » trovâye que porrêt changiér lo href en empleyent l’atribut « from » <code>&lt;$1 $2=\"$3\"&gt;</code> dedens lo fichiér SVG tèlèchargiê.",
-       "uploaded-setting-event-handler-svg": "La dèfinicion d’atributs de maneyor d’èvènement est blocâye, <code>&lt;$1 $2=\"$3\"&gt;</code> trovâ dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-script-svg": "Na piéce ècrivâbla « $1 » est étâye trovâye dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-hostile-svg": "CSS pas de sûr est étâ trovâ dens la piéce de stilo d’un fichiér SVG tèlèchargiê.",
+       "uploaded-event-handler-on-svg": "La dèfinicion d’atributs de maneyor d’èvènement <code>$1=\"$2\"</code> est pas ôtorisâye dedens los fichiérs SVG.",
+       "uploaded-href-attribute-svg": "Los atributs href dedens los fichiérs SVG sont ôtorisâs ren que por s’en rèferar a de cibes http:// ou ben https://, <code>&lt;$1 $2=\"$3\"&gt;</code> est étâ trovâ.",
+       "uploaded-href-unsafe-target-svg": "href de vers des balyês pas de sûr est étâ trovâ dedens lo fichiér SVG tèlèchargiê : URI ciba <code>&lt;$1 $2=\"$3\"&gt;</code>.",
+       "uploaded-animate-svg": "La balisa « animate » est étâye trovâye que porrêt changiér lo href en empleyent l’atribut « from » <code>&lt;$1 $2=\"$3\"&gt;</code> dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-setting-event-handler-svg": "La dèfinicion d’atributs de maneyor d’èvènement est dèfendua, <code>&lt;$1 $2=\"$3\"&gt;</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
        "uploaded-setting-href-svg": "L’usâjo de la balisa « set » por apondre un atribut « href » a la piéce parenta est dèfendu.",
+       "uploaded-wrong-setting-svg": "L’usâjo de la balisa « set » por apondre na ciba distanta/balyês/scripte a un atribut quint que seye est dèfendu. <code>&lt;set to=\"$1\"&gt;</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-setting-handler-svg": "Los SVG que dèfenéssont l’atribut « handler » avouéc distant/balyês/scripte sont dèfendus. <code>$1=\"$2\"</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-remote-url-svg": "Los SVG que dèfenéssont un atribut de stilo quint que seye avouéc un’URL distanta sont dèfendus. <code>$1=\"$2\"</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-image-filter-svg": "Un filtro d’émâge avouéc URL est étâ trovâ : <code>&lt;$1 $2=\"$3\"&gt;</code> dedens lo fichiér SVG tèlèchargiê.",
+       "uploadscriptednamespace": "Cél fichiér SVG contint un èspâço de noms « $1 » pas ôtorisâ.",
+       "uploadinvalidxml": "Lo XML dedens lo fichiér tèlèchargiê at pas possu étre analisâ.",
        "uploadvirus": "Cél fichiér contint un virus !\nDètalys : $1",
-       "uploadjava": "O est un fichiér ZIP que contint un fichiér Java « .class ».\nLo tèlèchargement de fichiérs Java est pas ôtorisâ, pôvont èvitar des rèstriccions de sècuritât.",
+       "uploadjava": "O est un fichiér ZIP que contint un fichiér Java « .class ».\nLo tèlèchargement de fichiérs Java est pas ôtorisâ perce que pôvont èvitar de rèstriccions de sècuritât.",
        "upload-source": "Fichiér sôrsa",
        "sourcefilename": "Nom du fichiér sôrsa :",
        "sourceurl": "URL sôrsa :",
        "upload-maxfilesize": "Talye maximon du fichiér : $1",
        "upload-description": "Dèscripcion du fichiér",
        "upload-options": "Chouèx de tèlèchargement",
-       "watchthisupload": "Siuvre ceti fichiér",
+       "watchthisupload": "Siuvre cél fichiér",
        "filewasdeleted": "Un fichiér avouéc cél nom est ja étâ tèlèchargiê et pués suprimâ.\nVos devriâd controlar lo $1 devant que lo tornar tèlèchargiér.",
-       "filename-bad-prefix": "Lo nom du fichiér que vos tèlèchargiéd comence per '''« $1 »''' qu’est en g·ènèral un nom pas dèscriptif balyê ôtomaticament per los aparèlys-fotô numericos.\nSe vos plét, chouèsésséd un nom ples dèscriptif por voutron fichiér.",
+       "filename-thumb-name": "Cen ressemble a un titro de miniatura. Se vos plét, tèlèchargiéd gins de miniatura ja presenta sur lo mémo vouiqui. Ôtrament, se vos plét corregiéd lo nom du fichiér por que seye ples significatif et pués qu’il èye pas lo prèfixo de miniatura.",
+       "filename-bad-prefix": "Lo nom du fichiér que vos tèlèchargiéd comence per <strong>« $1 »</strong> qu’est en g·ènèrâl un nom pas dèscriptif balyê ôtomaticament per los aparèlys-fotô numericos.\nSe vos plét, chouèsésséd-nen un nom ples dèscriptif.",
        "filename-prefix-blacklist": " #<!-- lèssiéd ceta legne justo d’ense --> <pre>\n# La sintaxa est ceta :\n#  * Tot tèxto que siut un « # » tant qu’a la fin de la legne est un comentèro.\n#  * Tota legne pas voueda est un prèfixo tipico de nom de fichiér balyê ôtomaticament per los aparèlys-fotô numericos :\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # quârques enfatâblos\nIMG # g·ènèrico\nJD # Jenoptik\nMGP # Pentax\nPICT # de totes sôrtes\n #</pre> <!-- lèssiéd ceta legne justo d’ense -->",
        "upload-proto-error": "Protocolo fôx",
        "upload-proto-error-text": "Lo tèlèchargement a distance at fôta d’URLs que començont per <code>http://</code> ou ben <code>ftp://</code>.",
        "upload-misc-error-text": "Na fôta encognua est arrevâye pendent lo tèlèchargement.\nSe vos plét, controlâd que l’URL est justa et accèssibla et pués tornâd èprovar.\nSe lo problèmo continue, veriéd-vos vers un [[Special:ListUsers/sysop|administrator]].",
        "upload-too-many-redirects": "L’URL contint trop de redirèccions",
        "upload-http-error": "Na fôta HTTP est arrevâye : $1",
-       "upload-copy-upload-invalid-domain": "Los tèlèchargements de copies sont pas disponiblos dês ceti domêno.",
+       "upload-copy-upload-invalid-domain": "La copia des tèlèchargements est pas disponibla dês cél domêno.",
+       "upload-foreign-cant-upload": "Cél vouiqui est pas configurâ por tèlèchargiér de fichiérs vers lo dèpôt de fichiérs de defôr demandâ.",
+       "upload-dialog-title": "Tèlèchargiér un fichiér",
+       "upload-dialog-button-cancel": "Anular",
+       "upload-dialog-button-done": "Fêt",
+       "upload-dialog-button-save": "Encartar",
+       "upload-dialog-button-upload": "Tèlèchargiér",
+       "upload-form-label-infoform-title": "Dètalys",
+       "upload-form-label-infoform-name": "Nom",
+       "upload-form-label-infoform-name-tooltip": "Un titro dèscriptif sen pariér por lo fichiér, que sèrvirat coment nom de fichiér. Vos pouede empleyér de lengâjo corent avouéc des èspâços. Pas entrebetar l’èxtension du fichiér.",
+       "upload-form-label-infoform-description": "Dèscripcion",
+       "upload-form-label-infoform-description-tooltip": "Dècrire vito tot cen qu’y at de particuliér por cel’ôvra.\nPor na fotô, mencionar les chouses principâles que sont semondues, l’ocasion ou ben l’endrêt.",
+       "upload-form-label-usage-title": "Usâjo",
+       "upload-form-label-usage-filename": "Nom du fichiér",
+       "foreign-structured-upload-form-label-own-work": "Su l’ôtor de cel’ôvra",
+       "foreign-structured-upload-form-label-infoform-categories": "Catègories",
+       "foreign-structured-upload-form-label-infoform-date": "Dâta",
+       "foreign-structured-upload-form-label-own-work-message-local": "Confirmo que tèlèchârjo cél fichiér d’aprés les condicions d’usâjo et les politiques de licence de {{SITENAME}}.",
+       "foreign-structured-upload-form-label-not-own-work-message-local": "Se vos pouede pas tèlèchargiér cél fichiér d’aprés les politiques de {{SITENAME}}, se vos plét cllôde cela bouèta de dialogo et pués èprovâd un’ôtra mètoda.",
+       "foreign-structured-upload-form-label-not-own-work-local-local": "Vos pouede asse-ben èprovar la [[Special:Upload|pâge de tèlèchargement per dèfôt]].",
+       "foreign-structured-upload-form-label-own-work-message-default": "Compregno que tèlèchârjo cél fichiér vers un dèpôt partagiê. Confirmo qu’o fé d’aprés les condicions d’usâjo et les politiques de licence de ceti.",
+       "foreign-structured-upload-form-label-not-own-work-message-default": "Se vos pouede pas tèlèchargiér cél fichiér d’aprés les politiques du dèpôt partagiê, se vos plét cllôde cela bouèta de dialogo et pués èprovâd un’ôtra mètoda.",
+       "foreign-structured-upload-form-label-not-own-work-local-default": "Vos pouede asse-ben èprovar d’empleyér la [[Special:Upload|pâge de tèlèchargement de {{SITENAME}}]], se cél fichiér y pôt étre tèlèchargiê d’aprés lors politiques.",
+       "foreign-structured-upload-form-label-own-work-message-shared": "Cèrtifio étre lo dètentior des drêts d’ôtor sur cél fichiér, et j’accèpto de publeyér cél fichiér dessus Wikimedia Commons en lo betent irrèvocâblament desot licence [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Atribucion - Partâjo dens les Mémes Condicions 4.0] et pués j’accèpto les [https://wikimediafoundation.org/wiki/Terms_of_Use condicions d’usâjo].",
+       "foreign-structured-upload-form-label-not-own-work-message-shared": "Se vos éte pas lo dètentior des drêts d’ôtor sur cél fichiér ou ben que vos lo voléd publeyér desot na licence difèrenta, vos pouede empleyér l’[https://commons.wikimedia.org/wiki/Special:UploadWizard assistent de tèlèchargement de Commons].",
+       "foreign-structured-upload-form-label-not-own-work-local-shared": "Vos pouede asse-ben èprovar d’empleyér la [[Special:Upload|pâge de tèlèchargement de {{SITENAME}}]], se cél fichiér y pôt étre tèlèchargiê d’aprés lors politiques.",
        "backend-fail-stream": "Y at pas moyen de tramandar lo fichiér « $1 ».",
        "backend-fail-backup": "Y at pas moyen d’encartar lo fichiér « $1 ».",
        "backend-fail-notexists": "Lo fichiér $1 ègziste pas.",
        "backend-fail-copy": "Y at pas moyen de copiyér lo fichiér « $1 » vers « $2 ».",
        "backend-fail-move": "Y at pas moyen de dèplaciér lo fichiér « $1 » vers « $2 ».",
        "backend-fail-opentemp": "Y at pas moyen d’uvrir lo fichiér temporèro.",
-       "backend-fail-writetemp": "Y at pas moyen d’ècrire dedens lo fichiér temporèro.",
+       "backend-fail-writetemp": "Y at pas moyen d’ècrire sur lo fichiér temporèro.",
        "backend-fail-closetemp": "Y at pas moyen de cllôre lo fichiér temporèro.",
        "backend-fail-read": "Y at pas moyen de liére lo fichiér « $1 ».",
        "backend-fail-create": "Y at pas moyen d’ècrire lo fichiér « $1 ».",
        "backend-fail-maxsize": "Y at pas moyen d’ècrire lo fichiér « $1 » perce qu’il est ples grôs {{PLURAL:$2|qu’un octèt|que $2 octèts}}.",
-       "backend-fail-readonly": "Ora lo sistèmo de stocâjo « $1 » est justo en lèctura. La rêson balyêe est : « ''$2'' »",
+       "backend-fail-readonly": "Ora lo sistèmo de stocâjo « $1 » est mas qu’en lèctura. La rêson balyêe est : <em>$2</em>",
        "backend-fail-synced": "Lo fichiér « $1 » est dens un ètat dèsordonâ dedens los sistèmos de stocâjo de dedens",
        "backend-fail-connect": "Y at pas moyen de sè branchiér u sistèmo de stocâjo « $1 ».",
        "backend-fail-internal": "Na fôta encognua est arrevâye dedens lo sistèmo de stocâjo « $1 ».",
        "backend-fail-contenttype": "Y at pas moyen de dètèrmenar lo tipo de contegnu du fichiér a stocar dedens « $1 ».",
        "backend-fail-batchsize": "Lo sistèmo de stocâjo at balyê na pârt de $1 {{PLURAL:$1|opèracion|opèracions}} de fichiér ; la limita est $2 {{PLURAL:$2|opèracion|opèracions}}.",
-       "backend-fail-usable": "Y at pas moyen de liére d’ècrire lo fichiér « $1 » a côsa de pèrmissions ensufisentes ou ben de rèpèrtouèros / conteniors manquents.",
-       "filejournal-fail-dbconnect": "Y at pas moyen de sè branchiér a la bâsa de balyês du jornal por lo sistèmo de stocâjo « $1 ».",
-       "filejournal-fail-dbquery": "Y at pas moyen de betar a jorn la bâsa de balyês du jornal por lo sistèmo de stocâjo « $1 ».",
-       "lockmanager-notlocked": "Y at pas moyen de dèvèrrolyér « $1 » ; il est pas vèrrolyê.",
+       "backend-fail-usable": "Y at pas moyen de liére d’ècrire lo fichiér « $1 » a côsa de drêts ensufisents ou ben de rèpèrtouèros conteniors manquents.",
+       "filejournal-fail-dbconnect": "Y at pas moyen de sè branchiér a la bâsa de balyês du jornâl por lo sistèmo de stocâjo « $1 ».",
+       "filejournal-fail-dbquery": "Y at pas moyen de betar a jorn la bâsa de balyês du jornâl por lo sistèmo de stocâjo « $1 ».",
+       "lockmanager-notlocked": "Y at pas moyen de dècotar « $1 » ; o est pas cotâ.",
        "lockmanager-fail-closelock": "Y at pas moyen de cllôre lo fichiér de vèrroly por « $1 ».",
        "lockmanager-fail-deletelock": "Y at pas moyen de suprimar lo fichiér de vèrroly por « $1 ».",
        "lockmanager-fail-acquirelock": "Y at pas moyen d’avêr lo vèrroly por « $1 ».",
        "lockmanager-fail-releaselock": "Y at pas moyen de relâchiér lo vèrroly por « $1 ».",
        "lockmanager-fail-db-bucket": "Y at pas moyen de sè veriér vers prod de bâses de balyês de vèrroly dedens la sèlye $1.",
        "lockmanager-fail-db-release": "Y at pas moyen de relâchiér los vèrrolys sur la bâsa de balyês $1.",
-       "lockmanager-fail-svr-acquire": "Y at pas moyen d’avêr des vèrrolys sur lo sèrvior $1.",
+       "lockmanager-fail-svr-acquire": "Y at pas moyen d’avêr de vèrrolys sur lo sèrvior $1.",
        "lockmanager-fail-svr-release": "Y at pas moyen de relâchiér los vèrrolys sur lo sèrvior $1.",
        "zip-file-open-error": "Na fôta est arrevâye pendent l’uvèrtura du fichiér por los contrôlos ZIP.",
        "zip-wrong-format": "Lo fichiér spècifiâ est pas un fichiér ZIP.",
        "zip-bad": "Lo fichiér est un fichiér ZIP corrompu ou ben ôtrament iliésiblo.\nPôt pas étre controlâ coment fôt por la sècuritât.",
-       "zip-unsupported": "Lo fichiér est un fichiér ZIP qu’emplèye des fonccionalitâts ZIP pas recognues per MediaWiki.\nPôt pas étre controlâ coment fôt por la sècuritât.",
+       "zip-unsupported": "Lo fichiér est un fichiér ZIP qu’emplèye de fonccionalitâts ZIP pas recognues per MediaWiki.\nPôt pas étre controlâ coment fôt por la sècuritât.",
        "uploadstash": "Cacho de tèlèchargement",
-       "uploadstash-summary": "Ceta pâge balye accès ux fichiérs que sont tèlèchargiês ou ben en côrs de tèlèchargement, mas sont p’oncor publeyês dedens lo vouiqui. Celos fichiérs sont p’oncor visiblos, solament por l’utilisator que los at tèlèchargiês.",
-       "uploadstash-clear": "Èfaciér los fichiérs en cacho",
+       "uploadstash-summary": "Cela pâge balye accès ux fichiérs que sont tèlèchargiês ou ben en cors de tèlèchargement, mas sont p’oncor publeyês dedens lo vouiqui. Celos fichiérs sont p’oncor visiblos, solament por l’utilisator que los at tèlèchargiês.",
+       "uploadstash-clear": "Vouedar los fichiérs en cacho",
        "uploadstash-nofiles": "Vos éd gins de fichiér en cacho.",
        "uploadstash-badtoken": "L’ègzécucion de cel’accion at pas reussi, pôt-étre perce que voutros identifients de changement ant èxpirâ. Tornâd èprovar.",
        "uploadstash-errclear": "L’èfacement des fichiérs at pas reussi.",
        "uploadstash-refresh": "Rafrèchir la lista des fichiérs",
        "invalid-chunk-offset": "Dèplacement de bocon pas justo",
        "img-auth-accessdenied": "Accès refusâ",
-       "img-auth-nopathinfo": "PATH_INFO manquenta.\nVoutron sèrvior est pas configurâ por passar cel’enformacion.\nPôt étre bâsâye sur CGI et vêr pas recognetre « img_auth ».\nVêde https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
+       "img-auth-nopathinfo": "PATH_INFO manquent.\nVoutron sèrvior est pas configurâ por passar cel’enformacion.\nPôt-étre que fonccione en CGI et recognêt vêr pas img_auth.\nVêde https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Lo chemin demandâ est pas lo rèpèrtouèro de tèlèchargement configurâ.",
        "img-auth-badtitle": "Y at pas moyen de construire un titro justo dês « $1 ».",
        "img-auth-nologinnWL": "Vos éte pas branchiê et pués « $1 » est pas dedens la lista blanche.",
        "img-auth-nofile": "Lo fichiér « $1 » ègziste pas.",
-       "img-auth-isdir": "Vos èprovâd d’arrevar u rèpèrtouèro « $1 ».\nSolament l’accès ux fichiérs est pèrmês.",
+       "img-auth-isdir": "Vos èprovâd d’arrevar u rèpèrtouèro « $1 ».\nSolament l’accès ux fichiérs est pèrmetu.",
        "img-auth-streaming": "Lèctura en continu de « $1 ».",
-       "img-auth-public": "La fonccion de img_auth.php est de sortir des fichiérs d’un vouiqui privâ.\nCeti vouiqui est configurâ coment un vouiqui publico.\nPor na sècuritât pèrfèta, img_auth.php est dèsactivâ.",
-       "img-auth-noread": "L’utilisator at pas accès a la lèctura de « $1 ».",
+       "img-auth-public": "La fonccion d’img_auth.php est de sortir de fichiérs d’un vouiqui privâ.\nCél vouiqui est configurâ coment un vouiqui publico.\nPor na sècuritât parfèta, img_auth.php est dèsactivâ.",
+       "img-auth-noread": "L’utilisator at pas accès en lèctura de « $1 ».",
        "http-invalid-url": "URL pas justa : $1",
        "http-invalid-scheme": "Les URLs avouéc lo plan « $1 » sont pas recognues.",
        "http-request-error": "La demanda HTTP at pas reussi a côsa d’una fôta encognua.",
        "upload-curl-error6": "Y at pas moyen d’avengiér l’URL",
        "upload-curl-error6-text": "L’URL balyêe pôt pas étre avengiêe.\nSe vos plét, tornâd controlar que l’URL est justa et pués que lo seto est en legne.",
        "upload-curl-error28": "Dèlê dèpassâ pendent lo tèlèchargement",
-       "upload-curl-error28-text": "Lo seto at tardâ bien a rèpondre.\nSe vos plét, controlâd que lo seto est en legne, atende un pou et pués tornâd èprovar.\nVos pouede asse-ben èprovar a un’hora de muendra afluence.",
+       "upload-curl-error28-text": "Lo seto at tardâ ben a rèpondre.\nSe vos plét, controlâd que lo seto est en legne, atende-vos un petiôt moment et pués tornâd èprovar.\nVos pouede asse-ben èprovar a un’hora de muendra borrâ.",
        "license": "Licence :",
        "license-header": "Licence",
        "nolicense": "Pas yona chouèsia",
+       "licenses-edit": "Changiér los chouèx de licence",
        "license-nopreview": "(Apèrçu pas disponiblo)",
-       "upload_source_url": " (un’URL justa et accèssibla publicament)",
-       "upload_source_file": " (un fichiér sur voutron ordenator)",
-       "listfiles-summary": "Ceta pâge spèciâla montre tôs los fichiérs tèlèchargiês.\nQuand el est filtrâye per utilisator, solament los fichiérs que la vèrsion la ples novèla est étâye tèlèchargiêe per cél utilisator sont montrâs.",
-       "listfiles_search_for": "Rechèrchiér un nom de fichiér mèdia :",
+       "upload_source_url": "(lo fichiér que vos éd chouèsi dês un’URL justa et accèssibla publicament)",
+       "upload_source_file": "(lo fichiér que vos éd chouèsi dês voutron ordenator)",
+       "listfiles-delete": "suprimar",
+       "listfiles-summary": "Cela pâge spèciâla montre tôs los fichiérs tèlèchargiês.",
+       "listfiles_search_for": "Rechèrchiér un nom de fichiér multimèdiâ :",
+       "listfiles-userdoesnotexist": "Lo comptio utilisator « $1 » est pas encartâ.",
        "imgfile": "fichiér",
        "listfiles": "Lista de fichiérs",
-       "listfiles_thumb": "Figura",
+       "listfiles_thumb": "Miniatura",
        "listfiles_date": "Dâta",
        "listfiles_name": "Nom",
        "listfiles_user": "Utilisator",
        "listfiles_size": "Talye",
        "listfiles_description": "Dèscripcion",
        "listfiles_count": "Vèrsions",
+       "listfiles-show-all": "Entrebetar les vielyes vèrsions de les émâges",
+       "listfiles-latestversion": "Vèrsion d’ora",
+       "listfiles-latestversion-yes": "Ouè",
+       "listfiles-latestversion-no": "Nan",
        "file-anchor-link": "Fichiér",
        "filehist": "Historico du fichiér",
        "filehist-help": "Cllicar dessus na dâta et hora por vêre lo fichiér coment il ére a cél moment.",
        "filehist-datetime": "Dâta et hora",
        "filehist-thumb": "Miniatura",
        "filehist-thumbtext": "Miniatura por la vèrsion du $1",
-       "filehist-nothumb": "Niona figura",
+       "filehist-nothumb": "Niona miniatura",
        "filehist-user": "Utilisator",
        "filehist-dimensions": "Dimensions",
        "filehist-filesize": "Talye du fichiér",
        "filehist-comment": "Comentèro",
        "imagelinks": "Usâjo du fichiér",
-       "linkstoimage": "{{PLURAL:$1|Cela pâge-que emplèye|Celes $1 pâges-que emplèyont}} ceti fichiér :",
-       "linkstoimage-more": "Més {{PLURAL:$1|d’una pâge emplèye|de $1 pâges emplèyont}} ceti fichiér.\nCeta lista montre ren que {{PLURAL:$1|la premiére pâge qu’emplèye|les $1 premiéres pâges qu’emplèyont}} ceti fichiér.\nNa [[Special:WhatLinksHere/$2|lista complèta]] est disponibla.",
-       "nolinkstoimage": "Niona pâge emplèye ceti fichiér.",
-       "morelinkstoimage": "Vêde [[Special:WhatLinksHere/$1|més de lims]] de vers ceti fichiér.",
+       "linkstoimage": "{{PLURAL:$1|Cela pâge-que emplèye|Celes $1 pâges-que emplèyont}} cél fichiér :",
+       "linkstoimage-more": "Més {{PLURAL:$1|d’una pâge emplèye|de $1 pâges emplèyont}} cél fichiér.\nCela lista-que montre mas que {{PLURAL:$1|la premiére pâge qu’emplèye|les $1 premiéres pâges qu’emplèyont}} cél fichiér.\nNa [[Special:WhatLinksHere/$2|lista complèta]] est disponibla.",
+       "nolinkstoimage": "Niona pâge emplèye cél fichiér.",
+       "morelinkstoimage": "Vêde [[Special:WhatLinksHere/$1|més de lims]] de vers cél fichiér.",
        "linkstoimage-redirect": "$1 (redirèccion de fichiér) $2",
        "duplicatesoffile": "{{PLURAL:$1|Cél fichiér-que est un doblo|Celos $1 fichiérs-que sont des doblos}} de ceti ([[Special:FileDuplicateSearch/$2|més de dètalys]]) :",
-       "sharedupload": "Ceti fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.",
-       "sharedupload-desc-there": "Ceti fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nSe vos plét, vêde la sina [$2 pâge de dèscripcion] por més d’enformacions.",
+       "sharedupload": "Cél fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.",
+       "sharedupload-desc-there": "Cél fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nSe vos plét, vêde sa [$2 pâge de dèscripcion] por més d’enformacions.",
        "sharedupload-desc-here": "Cél fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nLa dèscripcion dessus sa [$2 pâge de dèscripcion] est montrâye ce-desot.",
-       "sharedupload-desc-edit": "Ceti fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nPôt-étre vos voléd changiér la dèscripcion sur la sina [$2 pâge de dèscripcion].",
-       "sharedupload-desc-create": "Ceti fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nPôt-étre vos voléd changiér la dèscripcion sur la sina [$2 pâge de dèscripcion].",
+       "sharedupload-desc-edit": "Cél fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nPôt-étre vos voléd changiér la dèscripcion dessus sa [$2 pâge de dèscripcion].",
+       "sharedupload-desc-create": "Cél fichiér vint de $1 et pôt étre empleyê per d’ôtros projèts.\nPôt-étre vos voléd changiér la dèscripcion dessus sa [$2 pâge de dèscripcion].",
        "filepage-nofile": "Nion fichiér de cél nom ègziste.",
        "filepage-nofile-link": "Nion fichiér de cél nom ègziste, mas vos en pouede [$1 tèlèchargiér yon].",
-       "uploadnewversion-linktext": "Tèlèchargiér na novèla vèrsion de ceti fichiér",
+       "uploadnewversion-linktext": "Tèlèchargiér na novèla vèrsion de cél fichiér",
        "shared-repo-from": "de : $1",
        "shared-repo": "un dèpôt partagiê",
        "filepage.css": "/* Lo code CSS betâ ique est encllu dens la pâge de dèscripcion du fichiér, et pués dens los vouiquis cliants ètrangiérs. */",
-       "upload-disallowed-here": "Vos pouede pas ècllafar ceti fichiér.",
+       "upload-disallowed-here": "Vos pouede pas ècllafar cél fichiér.",
        "filerevert": "Rèvocar $1",
        "filerevert-legend": "Rèvocar lo fichiér",
-       "filerevert-intro": "Vos éte prèst a rèvocar lo fichiér '''[[Media:$1|$1]]''' a la [$4 vèrsion du $2 a $3].",
+       "filerevert-intro": "Vos éte prèst a rèvocar lo fichiér <strong>[[Media:$1|$1]]</strong> a la [$4 vèrsion du $2 a $3].",
        "filerevert-comment": "Rêson :",
        "filerevert-defaultcomment": "Rèvocâ a la vèrsion du $1 a $2 ($3)",
        "filerevert-submit": "Rèvocar",
-       "filerevert-success": "'''[[Media:$1|$1]]''' est étâ rèvocâ a la [$4 vèrsion du $2 a $3].",
+       "filerevert-success": "<strong>[[Media:$1|$1]]</strong> est étâ rèvocâ a la [$4 vèrsion du $2 a $3].",
        "filerevert-badversion": "Y at gins de vèrsion locâla devant de cél fichiér avouéc l’horodatâjo balyê.",
        "filedelete": "Suprimar $1",
        "filedelete-legend": "Suprimar lo fichiér",
-       "filedelete-intro": "Vos éte prèst a suprimar lo fichiér '''[[Media:$1|$1]]''' et pués tot lo sin historico.",
-       "filedelete-intro-old": "Vos éte aprés suprimar la vèrsion de '''[[Media:$1|$1]]''' du [$4 $2 a $3].",
+       "filedelete-intro": "Vos éte prèst a suprimar lo fichiér <strong>[[Media:$1|$1]]</strong> et pués tot son historico.",
+       "filedelete-intro-old": "Vos éte aprés suprimar la vèrsion de <strong>[[Media:$1|$1]]</strong> du [$4 $2 a $3].",
        "filedelete-comment": "Rêson :",
        "filedelete-submit": "Suprimar",
-       "filedelete-success": "'''$1''' est étâ suprimâ.",
-       "filedelete-success-old": "La vèrsion de '''[[Media:$1|$1]]''' du $2 a $3 est étâye suprimâye.",
-       "filedelete-nofile": "'''$1''' ègziste pas.",
-       "filedelete-nofile-old": "Ègziste gins de vèrsion arch·ivâye de '''$1''' avouéc los atributs spècifiâs.",
-       "filedelete-otherreason": "Ôtra rêson / rêson de ples :",
+       "filedelete-success": "<strong>$1</strong> est étâ suprimâ.",
+       "filedelete-success-old": "La vèrsion de <strong>[[Media:$1|$1]]</strong> du $2 a $3 est étâye suprimâye.",
+       "filedelete-nofile": "<strong>$1</strong> ègziste pas.",
+       "filedelete-nofile-old": "Ègziste gins de vèrsion arch·ivâye de <strong>$1</strong> avouéc los atributs spècifiâs.",
+       "filedelete-otherreason": "Ôtra rêson ou ben rêson de més :",
        "filedelete-reason-otherlist": "Ôtra rêson",
-       "filedelete-reason-dropdown": "*Rêsons corentes de suprèssion\n** Violacion du drêt d’ôtor\n** Fichiér en doblo",
+       "filedelete-reason-dropdown": "*Rêsons comenes de suprèssion\n** Violacion du drêt d’ôtor\n** Fichiér en doblo",
        "filedelete-edit-reasonlist": "Changiér les rêsons de suprèssion",
        "filedelete-maintenance": "La suprèssion et la rèstoracion de fichiérs est dèsactivâye por un moment pendent la mantegnence.",
        "filedelete-maintenance-title": "Y at pas moyen de suprimar lo fichiér",
index eb82d6f..21ec0d4 100644 (file)
@@ -11,7 +11,8 @@
                        "Supriya kankumbikar",
                        "Vaishali Parab",
                        "The Discoverer",
-                       "Cliffa fernandes"
+                       "Cliffa fernandes",
+                       "Rxy"
                ]
        },
        "tog-hideminor": "हालींच बदल केल्ल्यांतले बारीक संपादन लिपय",
@@ -24,7 +25,7 @@
        "tog-enotifwatchlistpages": "म्हज्या सादुरवळेरेंतलें पान वा फायल बदल्ली जाल्यार म्हाका इमेल करात",
        "tog-shownumberswatching": "ध्यान दवरपी वांगड्यांची संख्या दाखय",
        "tog-oldsig": "सद्याची निशाणी",
-       "tog-uselivepreview": "लायव à¤ªà¥\81रà¥\8dवनियाळाà¤\9aà¥\8b à¤\89पà¥\87à¤\97 à¤\95र",
+       "tog-uselivepreview": "लायव à¤ªà¥\81रà¥\8dवनियाळाà¤\9aà¥\8b à¤µà¤¾à¤ªर",
        "tog-watchlisthideown": "सादुरवळेरीतलें म्हजे संपादन लिपय",
        "tog-watchlisthidebots": "ध्यानसुचीतले रोबोट संपादन लिपय",
        "tog-watchlisthideminor": "सादुरवळेरीतले ल्हान संपादन लिपय",
        "and": "&#32;आनीक",
        "qbfind": "सोदात",
        "qbbrowse": "ब्राउज",
-       "qbedit": "सà¤\82पादन",
+       "qbedit": "बदल",
        "qbpageoptions": "हें पान",
        "qbmyoptions": "म्हजी पानां",
        "faq": "परत परत विचारिल्ले प्रस्न",
        "print": "छाप",
        "view": "पळय",
        "view-foreign": " $1 चेर पळयात",
-       "edit": "सà¤\82पादन",
+       "edit": "बदल",
        "edit-local": "थळाव्या संपादनाचें वर्णन",
        "create": "निर्माण कर",
        "create-local": "थळावे वर्णन जोडात",
        "newpage": "नवें पान",
        "talkpage": "ह्या पानाचेर चर्चा करात",
        "talkpagelinktext": "चर्चा",
-       "specialpage": "à¤\96ाशà¥\87लà¥\87à¤\82 पान",
+       "specialpage": "विशà¥\87श पान",
        "personaltools": "खाजगी साधनां",
        "articlepage": "मजकूर पान पळयात",
        "talk": "भासाभास",
        "redirectedfrom": "($1 सून पुनर्निर्देशित)",
        "redirectpagesub": "पान परतून निर्देशीत करचें",
        "redirectto": "हांगां पुनर्निर्देशित:",
-       "lastmodifiedat": " ह्या पानांत निमाणो बदल,$1 वेर $2 वेळार केल्लो",
+       "lastmodifiedat": "ह्या पानांत निमाणो बदल,$1 वेर $2 वेळार केल्लो",
        "protectedpage": "राखून दवरिल्लें पान",
        "jumpto": "हुपून वचात:",
        "jumptonavigation": "दिशा-नियंत्रण",
        "ok": "बरें",
        "retrievedfrom": "\"$1\" चे कडल्यान परतून मेळयलें",
        "youhavenewmessagesmulti": "$1 चेर तुका नवो संदेश आसा",
-       "editsection": "सà¤\82पादन",
-       "editold": "सà¤\82पादन",
+       "editsection": "बदल",
+       "editold": "बदल",
        "viewsourceold": "उगम पळेयात",
        "editlink": "बदल",
        "viewsourcelink": "उगम पळयात",
        "nstab-main": "पान",
        "nstab-user": "वापरपी पान",
        "nstab-media": "माध्यमाचें पान",
-       "nstab-special": "à¤\96ाशà¥\87लà¥\87à¤\82 पान",
+       "nstab-special": "विशà¥\87श पान",
        "nstab-project": "प्रकल्पाचें पान",
        "nstab-image": "फायल",
        "nstab-mediawiki": "संदेश",
        "nstab-help": "आदाराचें पान",
        "nstab-category": "वर्ग",
        "nosuchaction": "असले तरेचे कार्य ना",
-       "nosuchspecialpage": "à¤\85सलà¥\87 à¤\95ाà¤\82यà¤\9a à¤\96ाशà¥\87लà¥\87à¤\82 पान ना",
+       "nosuchspecialpage": "à¤\85सलà¥\87 à¤\95ाà¤\82यà¤\9a à¤µà¤¿à¤¶à¥\87श पान ना",
        "error": "चूक",
        "databaseerror": "डॅटाबॅज त्रुटी",
        "databaseerror-textcl": "डॅटाबेज विरोध त्रुटी आयिल्ली आसा",
        "image_tip": "अंत: स्थापीत फायल",
        "media_tip": "फायलीची जोडणी",
        "sig_tip": "वेळ-छाप सयत तुमची निशाणी",
-       "hr_tip": "à¤\86डवà¥\80 à¤µà¤³ (à¤\89णà¥\8b à¤\89पà¥\87à¤\97 à¤\95रचो)",
+       "hr_tip": "à¤\86डवà¥\80 à¤µà¤³ (à¤\89णà¥\8b à¤µà¤¾à¤ªरचो)",
        "summary": "आपरोस:",
        "subject": "विशय/माथाळो",
        "minoredit": "हें दाकटें संपादन",
        "prefs-watchlist": "सादुरवळेरी",
        "youremail": "इमेल",
        "yourrealname": "खरें नांवः",
-       "right-writeapi": "बरà¥\8bवपाà¤\9aà¥\87 API à¤\9aà¥\8b à¤\89पà¥\87à¤\97 à¤\95रात",
+       "right-writeapi": "बरà¥\8bवपाà¤\9aà¥\87 API à¤µà¤¾à¤ªरात",
        "newuserlogpage": "वापरपी रोचनेचे वळेरी",
        "action-edit": "हें पान संपादीत कर",
        "nchanges": "$1 {{PLURAL:$1|बदल|बदल}}",
        "statistics": "संख्याशास्त्र",
        "statistics-pages": "पान:",
        "statistics-files": "फायल अपलोड करात",
-       "brokenredirects-edit": "सà¤\82पादन",
+       "brokenredirects-edit": "बदल",
        "brokenredirects-delete": "काडून उडयात",
        "nbytes": "$1 {{PLURAL:$1|बाय्ट}}",
        "nmembers": "$1 {{PLURAL:$1|वांगडी}}",
        "changecontentmodel-reason-label": "कारण:",
        "protectlogpage": "सुरक्षितेचें सोत्र",
        "protectedarticle": "राखिल्ले\"[[$1]]\"",
-       "restriction-edit": "सà¤\82पादन",
+       "restriction-edit": "बदल",
        "restriction-move": "दुसरेकडे व्हरात",
        "restriction-create": "निर्माण कर",
        "undeletelink": "पळेयात/परत हाडात",
        "tooltip-t-contributions": "ह्या वापरप्याची योगदानाची वळेरी",
        "tooltip-t-emailuser": "ह्या उपेगकर्त्याक इ-मेल धाडात",
        "tooltip-t-upload": "फायली अपलोड करात",
-       "tooltip-t-specialpages": "सà¤\97ळà¥\8dया à¤\96ाशà¥\87लà¥\8dया पानांची वळेरी",
+       "tooltip-t-specialpages": "सà¤\97ळà¥\8dया à¤µà¤¿à¤¶à¥\87श पानांची वळेरी",
        "tooltip-t-print": "ह्या पानाची छापपायोग्य आवृत्ती",
        "tooltip-t-permalink": "ह्या पानाच्या ह्या पुनर्नियाळाकडे सदांकाळ जोडणी",
        "tooltip-ca-nstab-main": "मजकूर पान पळेयात",
        "watchlisttools-view": "प्रस्तूत बदल पळयात.",
        "watchlisttools-edit": "सादुरवळेरी पळय आनी संपादीत करात",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|उलयात]])",
-       "specialpages": "à¤\96ाशà¥\87लà¥\80à¤\82 पानां",
+       "specialpages": "विशà¥\87श पानां",
        "tag-filter": "[[Special:Tags|कुर्वेचीट]] गाळणो:",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|कुरवेचीट|कुरवेचीटी}}]]: $2)",
        "htmlform-title-not-exists": "$1 अस्तित्वांत ना.",
index 28125ae..e135d4b 100644 (file)
        "newpage": "Novem pan",
        "talkpage": "Hea panachem bhasabhas kor",
        "talkpagelinktext": "Bhasabhas",
-       "specialpage": "Khaxhel pan",
+       "specialpage": "Vixex pan",
        "personaltools": "Khasgi avtam",
        "articlepage": "Vixoi sombondhi pan poloi",
        "talk": "Bhasabhas",
        "nstab-main": "Pan",
        "nstab-user": "Vapuddpeachem pan",
        "nstab-media": "Madheomachem pan",
-       "nstab-special": "Khaxelem pan",
+       "nstab-special": "Vixex pan",
        "nstab-project": "Prokolpache pan",
        "nstab-image": "Fail",
        "nstab-mediawiki": "Sondex",
        "nstab-category": "Vorg",
        "mainpage-nstab": "Mukhel pan",
        "nosuchaction": "Oslem torechem karya nam",
-       "nosuchspecialpage": "Oslem kaich khaxellem pan na",
+       "nosuchspecialpage": "Oslem kaich vixex pan na",
        "error": "Chuk",
        "databaseerror": "Totv-kox chuk",
        "databaseerror-textcl": "Totv-kox (database) sodtana chuk ghodli",
        "template-semiprotected": "(ordhem rakhun dovorlelem)",
        "hiddencategories": "Hem pan {{PLURAL:$1|1 lipoilelea vorgacho vangddi|$1 lipoileleam vorgancho vangddi}}:",
        "permissionserrorstext-withaction": "$2, hem korpak tuka porvangi na, {{PLURAL:$1|hea karnnak lagon|hea karnnank lagun}}:",
-       "recreate-moveddeleted-warn": "<strong>Xittkavnni: Tum ek pan porot rochtai jem fattim kadun udoilelem.<strong>\n\nPanacho sudar korop sarkem zalear dhean di.\nPan vogllavpachem ani sotr halovpachem, sovloti khatir hangasor dilelem asa:",
+       "recreate-moveddeleted-warn": "<strong>Xittkavnni: Tum ek pan porot rochtai jem fattim kadun udoilelem.<strong>\n\nPanacho sudar korop sarkem zalear dhean di.\nPan kadoupachem ani halovpachem sotr, sovloti khatir hangasor dilelem asa:",
        "moveddeleted-notice": "Hem pan kadun udoilelem asa.\nPanachea kadun udounechi ani hallovnechi sotr sondorba khatir sokoil dilea.",
        "content-model-wikitext": "wikimozkur",
        "content-model-text": "Sado mozkur",
        "prefs-help-email": "Email potto sokticho na, pun tum gupitutor visroxi zalear gupitutor punorsthapon korunk email pottechi goroz podta.",
        "prefs-help-email-others": "Tujean dusreank tujea vapurpeacho panar vo bhasabhasache panar aslele eke email zodde vorvim tuje xim sompork korunk diunk zata.\nDusre tuje xim sompork kortat tednam tuzo email potto tankam kollchenam.",
        "group-all": "(soglle)",
-       "right-writeapi": "Borovpeache API-cho upeog",
+       "right-writeapi": "Borovpeache API-cho vapor",
        "newuserlogpage": "Vapurpi rochnnechem sotr",
        "action-edit": "hem pan sudar",
        "nchanges": "$1 {{PLURAL:$1|bodlop|bodlopam}}",
        "delete-legend": "Kadun udoi",
        "actioncomplete": "Karvai sompurnn",
        "actionfailed": "Karvai oiesiesvi",
-       "dellogpage": "Vogllaoneche sotr",
+       "dellogpage": "Kadun udouneche sotr",
        "deleteotherreason": "Dusrem/aniki karon:",
        "rollbacklink": "kovoll",
        "rollbacklinkcount": "$1 {{PLURAL:$1|bodol|bodlopam}} kovoll",
        "tooltip-t-contributions": "{{GENDER:$1|Hea vapuddpeachea}} yogdanachi suchi",
        "tooltip-t-emailuser": "{{GENDER:$1|Hea vapuddpeak}} email patthoi",
        "tooltip-t-upload": "Faili upload kor",
-       "tooltip-t-specialpages": "Sogllea khaxelim pananchi volleri",
+       "tooltip-t-specialpages": "Sogllea vixex pananchi volleri",
        "tooltip-t-print": "Hea panachem chap'pakyogya avrutti",
        "tooltip-t-permalink": "Hea panache hea uzollnnek togpi zoddni",
        "tooltip-ca-nstab-main": "Mozkur pan polloi",
        "watchlisttools-raw": "Sadurvollerichi mull-an bodol kor",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|uloi]])",
        "duplicate-defaultsort": "'''Chotrai:''' Falta anukraman mukhel ''$2'' rodd korta adhlem falta anukraman mukhel ''$1'', haka.",
-       "specialpages": "Khaxelim Panam",
+       "specialpages": "Vixex panam",
        "external_image_whitelist": " #Hi voll asa toxich dovor<pre>\n#Khala sodpache sache (''regular expressions'') ghal (fokot // modem voita poi tem bhag)\n#Hanche borobor bhaile zodlele murt comparar kel'le zatele\n#Mell khatat tim murt koxeo distele, na zalear fokot mortek ek zodd distele\n#Jeo voll #-an suru zatele tem vivek mhunn manlele zatele\n#Hanga vhodle and dhakte okxora modem forok podona\n\n#Soglle sodpache sache hea volla voir ghal. Hi voll asa toxich dovor</pre>",
        "tag-filter": "[[Special:Tags|Kurvechit]] challni:",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Kurvechit|Kurvechiti}}]]: $2)",
index 713aa03..4e6e453 100644 (file)
        "changecontentmodel-nodirectediting": "מודל התוכן $1 אינו תומך בעריכה ישירה",
        "log-name-contentmodel": "יומן שינויי מודל תוכן",
        "log-description-contentmodel": "אירועים שקשורים למודל תוכן של דפים",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|יצר|יצרה}} את הדף $3 תוך שימוש במודל התוכן \"$5\" השונה ממודל ברירת המחדל",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|שינה|שינתה}} את מודל התוכן של הדף $3 מ\"$4\" ל\"$5\"",
        "logentry-contentmodel-change-revertlink": "שחזור",
        "logentry-contentmodel-change-revert": "שחזור",
index a1e3d76..be3b009 100644 (file)
        "tog-watchdefault": "Tambahkan halaman yang saya sunting ke daftar pantauan",
        "tog-watchmoves": "Tambahkan halaman yang saya pindahkan ke daftar pantauan",
        "tog-watchdeletion": "Tambahkan halaman yang saya hapus ke daftar pantauan",
-       "tog-watchrollback": "Tambahkan laman yang pernah saya kembalikan ke dalam daftar pantauan saya",
+       "tog-watchrollback": "Tambahkan halaman yang pernah saya kembalikan ke dalam daftar pantauan saya",
        "tog-minordefault": "Tandai semua suntingan sebagai suntingan kecil secara baku",
        "tog-previewontop": "Perlihatkan pratayang sebelum kotak sunting dan tidak sesudahnya",
        "tog-previewonfirst": "Perlihatkan pratayang pada suntingan pertama",
-       "tog-enotifwatchlistpages": "Kirimkan saya surel jika suatu halaman yang saya pantau berubah",
+       "tog-enotifwatchlistpages": "Kirimkan saya surel jika suatu halaman atau berkas yang saya pantau berubah",
        "tog-enotifusertalkpages": "Kirimkan saya surel jika halaman pembicaraan saya berubah",
        "tog-enotifminoredits": "Kirimkan saya surel juga pada perubahan kecil",
        "tog-enotifrevealaddr": "Tampilkan alamat surel saya pada surel notifikasi",
        "prefs-user-pages": "Halaman pengguna",
        "prefs-personal": "Profil",
        "prefs-rc": "Perubahan terbaru",
-       "prefs-watchlist": "Pemantauan",
+       "prefs-watchlist": "Daftar pantauan",
        "prefs-editwatchlist": "Sunting daftar pantauan",
-       "prefs-editwatchlist-label": "Sunting entri di daftar pantuan:",
+       "prefs-editwatchlist-label": "Sunting entri di daftar pantauan Anda:",
        "prefs-editwatchlist-edit": "Lihat dan hapus judul di daftar pantauan Anda",
        "prefs-editwatchlist-raw": "Sunting daftar pantauan mentah",
        "prefs-editwatchlist-clear": "Kosongkan daftar pantauan",
        "prefs-watchlist-days": "Jumlah hari maksimum yang ditampilkan di daftar pantauan:",
        "prefs-watchlist-days-max": "Maksimum $1 {{PLURAL:$1|hari}}",
-       "prefs-watchlist-edits": "Jumlah suntingan maksimum yang ditampilkan di daftar pantauan yang lebih lengkap:",
+       "prefs-watchlist-edits": "Jumlah suntingan maksimum yang ditampilkan di daftar pantauan yang dikembangkan:",
        "prefs-watchlist-edits-max": "Nilai maksimum: 1000",
-       "prefs-watchlist-token": "Token pantauan:",
+       "prefs-watchlist-token": "Token daftar pantauan:",
        "prefs-misc": "Lain-lain",
        "prefs-resetpass": "Ganti kata sandi",
        "prefs-changeemail": "Ubah atau hapus alamat surel",
        "recentchangesdays-max": "(maksimum $1 {{PLURAL:$1|hari|hari}})",
        "recentchangescount": "Standar jumlah suntingan yang ditampilkan:",
        "prefs-help-recentchangescount": "Opsi ini berlaku untuk perubahan terbaru, versi terdahulu halaman, dan log.",
-       "prefs-help-watchlist-token2": "Ini adalah kunci rahasia (token) ke web feed dari daftar pantauan Anda.\nSiapa saja yang tahu akan dapat melihat daftar pantauan Anda, jadi jangan dibagikan.\n[[Special:ResetTokens|Klik di sini jika Anda perlu menyetel ulang]].",
+       "prefs-help-watchlist-token2": "Ini adalah kunci rahasia (token) ke umpan web dari daftar pantauan Anda.\nSiapa saja yang tahu akan dapat melihat daftar pantauan Anda, jadi jangan dibagikan. Jika diperlukan\n[[Special:ResetTokens|Anda dapat mengatur ulang kunci tersebut]].",
        "savedprefs": "Preferensi Anda telah disimpan",
        "savedrights": "Hak pengguna {{GENDER:$1|$1}} telah disimpan.",
        "timezonelegend": "Zona waktu:",
        "right-edituserjs": "Menyunting berkas JS pengguna lain",
        "right-editmyusercss": "Sunting berkas CSS pengguna Anda",
        "right-editmyuserjs": "Sunting berkas JavaScript pengguna Anda",
-       "right-viewmywatchlist": "Lihat daftar pantau Anda",
+       "right-viewmywatchlist": "Lihat daftar pantauan Anda",
        "right-editmywatchlist": "Sunting daftar pantau Anda. Masih ada cara menambahkan halaman tanpa harus memiliki hak ini.",
        "right-viewmyprivateinfo": "Lihat data pribadi Anda (alamat surel, nama asli, dll.)",
        "right-editmyprivateinfo": "Sunting data pribadi Anda (alamat surel, nama asli, dll.)",
        "grant-uploadfile": "Mengunggah berkas baru",
        "grant-basic": "Akses dasar",
        "grant-viewdeleted": "Melihat halaman dan berkas yang dihapus",
-       "grant-viewmywatchlist": "Melihat daftar pantauan Anda",
+       "grant-viewmywatchlist": "Lihat daftar pantauan Anda",
        "newuserlogpage": "Log pengguna baru",
        "newuserlogpagetext": "Di bawah ini adalah log pendaftaran pengguna baru",
        "rightslog": "Log perubahan hak akses",
        "action-userrights-interwiki": "menyunting hak akses dari pengguna di wiki lain",
        "action-siteadmin": "mengunci atau membuka kunci basis data",
        "action-sendemail": "kirim surel",
-       "action-editmywatchlist": "sunting daftar pantau Anda",
+       "action-editmywatchlist": "sunting daftar pantauan Anda",
        "action-viewmywatchlist": "lihat daftar pantau Anda",
        "action-viewmyprivateinfo": "lihat informasi pribadi Anda",
        "action-editmyprivateinfo": "sunting informasi pribadi Anda",
        "recentchangeslinked-feed": "Perubahan terkait",
        "recentchangeslinked-toolbox": "Perubahan terkait",
        "recentchangeslinked-title": "Perubahan yang terkait dengan \"$1\"",
-       "recentchangeslinked-summary": "Ini adalah daftar perubahan pada halaman yang terkait ke halaman yang spesifik (atau bagian dari kategori yang spesifik).\nHalaman pada [[Special:Watchlist|daftar pantauan Anda]] terlihat <strong>dicetak tebal</strong>.",
+       "recentchangeslinked-summary": "Ini adalah daftar perubahan pada halaman yang terkait ke halaman tertentu (atau bagian dari kategori tertentu).\nHalaman pada [[Special:Watchlist|daftar pantauan Anda]] terlihat <strong>dicetak tebal</strong>.",
        "recentchangeslinked-page": "Nama halaman:",
        "recentchangeslinked-to": "Perlihatkan perubahan dari halaman-halaman yang terhubung dengan halaman yang disajikan",
        "recentchanges-page-added-to-category": "[[:$1]] ditambahkan pada kategori",
        "backend-fail-read": "Tidak dapat membaca berkas $1.",
        "backend-fail-create": "Tidak dapat membuat berkas $1.",
        "backend-fail-maxsize": "Tidak dapat membuat berkas $1 karena ukurannya lebih besar dari {{PLURAL:$2||}}$2 bita.",
-       "backend-fail-readonly": "Backend penyimpanan \"$1\" ini saat ini hanya bisa dibaca. Alasan yang diberikan adalah: \"''$2''\"",
+       "backend-fail-readonly": "Penyimpanan latar belakang \"$1\" ini saat ini hanya dapat dibaca. Alasan yang diberikan adalah: <em>$2</em>",
        "backend-fail-synced": "Berkas \"$1\" dalam keadaan yang tidak konsisten dalam backends penyimpanan internal",
        "backend-fail-connect": "Tidak dapat menyambung ke penyimpanan backend \"$1\".",
        "backend-fail-internal": "Kesalahan yang tidak dikenal terjadi di backend penyimpanan \"$1\".",
        "apisandbox": "Bak pasir API",
        "apisandbox-jsonly": "JavaScript dibutuhkan untuk menggunakan kotak pasir API.",
        "apisandbox-api-disabled": "API dinonaktifkan pada situs ini.",
-       "apisandbox-intro": "Gunakan halaman ini untuk bereksperimen dengan '''API layanan web MediaWiki'''.\nLihat [//www.mediawiki.org/wiki/API:Main_page dokumentasi API] untuk perincian lanjut penggunaan API. Contoh: [//www.mediawiki.org/wiki/API#A_simple_example dapatkan konten Halaman Utama]. Pilih sebuah tindakan untuk melihat contoh lain.\n\nPerhatikan bahwa, meskipun ini adalah bak pasir, tindakan yang Anda lakukan pada halaman ini dapat mengubah wiki.",
+       "apisandbox-intro": "Gunakan halaman ini untuk bereksperimen dengan '''API layanan web MediaWiki'''.\nLihat [//www.mediawiki.org/wiki/API:Main_page dokumentasi API] untuk perincian lanjut penggunaan API. Contoh: [//www.mediawiki.org/wiki/API#A_simple_example dapatkan konten Halaman Utama]. Pilih sebuah tindakan untuk melihat contoh lain.\n\nPerhatikan bahwa, meskipun ini adalah bak pasir, tindakan yang Anda lakukan pada halaman ini mungkin dapat mengubah wiki.",
        "apisandbox-fullscreen": "Kembangkan panel",
        "apisandbox-fullscreen-tooltip": "Kembangkan panel kotak pasir untuk mengisi jendela peramban.",
        "apisandbox-unfullscreen": "Tampilkan halaman",
        "mywatchlist": "Daftar pantauan",
        "watchlistfor2": "Untuk $1 $2",
        "nowatchlist": "Daftar pantauan Anda kosong.",
-       "watchlistanontext": "Silahkan login untuk melihat atau mengedit item pada daftarjaga anda",
+       "watchlistanontext": "Silakan masuk log untuk melihat atau mengedit butir dalam daftar pantauan Anda",
        "watchnologin": "Belum masuk log",
        "addwatch": "Tambahkan ke daftar pantauan",
        "addedwatchtext": "\"[[:$1]]\" dan diskusinya telah ditambahkan ke [[Special:Watchlist|watchlist]] Anda.\nPerubahan-perubahan berikutnya pada halaman tersebut dan halaman pembicaraan terkaitnya akan tercantum di sini.",
        "delete-toobig": "Halaman ini memiliki sejarah penyuntingan yang panjang, melebihi {{PLURAL:$1|revisi|revisi}}.\nPenghapusan halaman dengan sejarah penyuntingan yang panjang tidak diperbolehkan untuk mencegah kerusakan di {{SITENAME}}.",
        "delete-warning-toobig": "Halaman ini memiliki sejarah penyuntingan yang panjang, melebihi {{PLURAL:$1|revisi|revisi}}.\nMenghapus halaman ini dapat menyebabkan masalah dalam operasional basis data {{SITENAME}}.",
        "deleteprotected": "Anda tidak dapat menghapus laman ini karena telah dilindungi.",
-       "deleting-backlinks-warning": "'''Peringatan:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Halaman lain]] mengarah atau memiliki transklusi ke halaman yang akan Anda hapus.",
+       "deleting-backlinks-warning": "<strong>Peringatan:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Halaman lain]] mengarah atau memiliki transklusi ke halaman yang akan Anda hapus.",
        "rollback": "Kembalikan suntingan",
        "rollbacklink": "kembalikan",
        "rollbacklinkcount": "kembalikan $1 {{PLURAL:$1|suntingan}}",
        "api-error-badaccess-groups": "Anda tidak diizinkan mengunggah berkas ke wiki ini.",
        "api-error-badtoken": "Kesalahan internal: token buruk.",
        "api-error-copyuploaddisabled": "Mengunggah melalui URL dilarang pada peladen ini.",
-       "api-error-duplicate": "Sudah ada {{PLURAL:$1|berkas lain}} dengan konten yang sama di situs ini.",
-       "api-error-duplicate-archive": "Ada {{PLURAL:$1|berkas}} lain di situs dengan konten yang sama, namun {{PLURAL:$1|berkas|berkas-berkas}} itu telah dihapus.",
+       "api-error-duplicate": "Sudah ada {{PLURAL:$1|berkas lain|berkas lain}} dengan isi yang sama di situs ini.",
+       "api-error-duplicate-archive": "Ada {{PLURAL:$1|berkas lain|berkas lain}} di situs dengan konten yang sama, namun {{PLURAL:$1|berkas|berkas-berkas}} itu telah dihapus.",
        "api-error-empty-file": "Berkas yang Anda kirim kosong.",
        "api-error-emptypage": "Pembuatan halaman baru yang kosong tidak diizinkan.",
        "api-error-fetchfileerror": "Kesalahan internal: terjadi kesalahan saat memperoleh berkas ini.",
        "expand_templates_generate_xml": "Tampilkan pohon parser XML",
        "expand_templates_generate_rawhtml": "Tampilkan HTML mentah",
        "expand_templates_preview": "Pratayang",
-       "pagelanguage": "Pemilih bahasa halaman",
+       "pagelanguage": "Ubah bahasa halaman",
        "pagelang-name": "Halaman",
        "pagelang-language": "Bahasa",
        "pagelang-use-default": "Gunakan bahasa baku",
        "pagelang-select-lang": "Pilih bahasa",
        "right-pagelang": "Ubah bahasa halaman",
        "action-pagelang": "mengubah bahasa halaman",
-       "log-name-pagelang": "Ubah bahasa log",
+       "log-name-pagelang": "Log perubahan bahasa",
        "log-description-pagelang": "Ini adalah log perubahan dalam bahasa halaman.",
-       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|mengubah}} bahasa halaman $3 dari $4 menjadi $5.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|mengubah}} bahasa $3 dari $4 menjadi $5.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (aktif)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 (<strong>nonaktif</strong>)",
        "mediastatistics": "Statistik media",
index 7ee9692..2241d06 100644 (file)
        "tooltip-pt-login": "Укхаза хьай цIи аьле чувала/яла йиша я, амма чуцаваьлача/ялача хIама а дац",
        "tooltip-pt-logout": "Аравала/яла",
        "tooltip-ca-talk": "ОагIувна чулоацаме дувцам",
-       "tooltip-ca-edit": "Ð\95Ñ\80 Ð¾Ð°Ð³IÑ\83в Ñ\85Ñ\83вÑ\86а Ð¹Ð¸Ñ\88йолаÑ\88 Ñ\8f. Ð\94еÑ\85аÑ\80 Ð´Ð°, IалаÑ\88 ÐµÐ»Ð°Ñ\8cÑ\85, Ñ\85Ñ\8cалÑ\85е Ð±IаÑ\80гÑ\82аÑ\81Ñ\81ама Ð¾Ð°Ð³IÑ\83в Ñ\82Iа Ð±IаÑ\80гÑ\82аÑ\81Ñ\81а.",
+       "tooltip-ca-edit": "Ð¥Ñ\83вÑ\86а ÐµÑ\80 Ð¾Ð°Ð³IÑ\83в",
        "tooltip-ca-addsection": "Керда декъам хьаде",
        "tooltip-ca-viewsource": "Ер оагIув хувцамах лораяь я, амма шун цунна гIувамага хьажа бокъо я.",
        "tooltip-ca-history": "Укх оагIувни хувцама таптар",
index dc488a3..990669d 100644 (file)
        "changecontentmodel-nodirectediting": "Il modello di contenuto $1 non supporta la modifica diretta",
        "log-name-contentmodel": "Modifiche del modello contenuti",
        "log-description-contentmodel": "Eventi relativi al modello di contenuto di una pagina",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|ha creato}} la pagina $3 utilizzando un modello di contenuto non predefinito \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|ha modificato}} il modello di contenuto della pagina $3 da \"$4\" a \"$5\"",
        "logentry-contentmodel-change-revertlink": "ripristina",
        "logentry-contentmodel-change-revert": "ripristina",
        "tags-edit-chosen-placeholder": "Seleziona alcune etichette",
        "tags-edit-chosen-no-results": "Nessun tag corrispondente trovato",
        "tags-edit-reason": "Motivo:",
-       "tags-edit-revision-submit": "Applica le modifiche a {{PLURAL:$1|questa revisione|$1 revisioni}}",
+       "tags-edit-revision-submit": "Applica le modifiche a {{PLURAL:$1|questa versione|$1 versioni}}",
        "tags-edit-logentry-submit": "Applica le modifiche a {{PLURAL:$1|questa voce di registro|$1 voci di registro}}",
        "tags-edit-success": "Le modifiche sono state applicate correttamente.",
        "tags-edit-failure": "Non è stato possibile effettuare le seguenti modifiche:\n$1",
index de6aa98..0d9010e 100644 (file)
        "summary-preview": "Prospectus summarii:",
        "subject-preview": "Prospectus rei/tituli:",
        "blockedtitle": "Usor obstructus est",
-       "blockedtext": "Nomen tuum vel iste locus IP obstructus est a magistratu $1.\nRatio: :''$2''\n\n* Initium obstructionis: $8\n* Finis obstructionis: $6\n* Obstructio pertinet ad: $7\n\nTibi licet ad $1 vel [[{{MediaWiki:Grouppage-sysop}}|magistratum alium]] nuntium mittere, ut obstructio tua disceptetur.\n\nNota bene te litteras electronicas mittere non posse, nisi inscriptio electronica in [[Special:Preferences|modis tuis deligendis]] data confirmata est neu ab ea utenda non arceris!\n\nLocus IP tuus temporarius $3 est, haec obstructio sub numero #$5 relata est.\nQuaesumus haec omnia supra dicta cuipiam consultationi subiungas.",
-       "autoblockedtext": "Locus IP tuus automatice obstruitur, quia alius quidam, qui a magistratu $1 obstructus est, eo usus erat.\nRatio:\n\n:''$2''\n\n* Initium obstructionis: $8\n* Finis obstructionis: $6\n* Obstructio pertinet ad: $7\n\nTibi licet ad $1 vel [[{{MediaWiki:Grouppage-sysop}}|magistratum alium]] nuntium mittere, ut obstructio tua disceptetur.\n\nNota bene te litteras electronicas mittere non posse, nisi inscriptio electronica in [[Special:Preferences|modis tuis deligendis]] data confirmata est neu ab ea utenda non arceris!\n\nLocus IP tuus temporarius $3 est, haec obstructio sub numero #$5 relata est.\nQuaesumus haec omnia supra dicta cuipiam consultationi subiungas.",
+       "blockedtext": "<strong>Nomen tuum vel iste locus IP obstructus est</strong> a magistratu $1.\nRatio: <em>$2</em>\n\n* Initium obstructionis: $8\n* Finis obstructionis: $6\n* Obstructio pertinet ad: $7\n\nTibi licet ad $1 vel [[{{MediaWiki:Grouppage-sysop}}|magistratum]] alium nuntium mittere, ut obstructio tua disceptetur.\n\nNota bene te litteras electronicas mittere non posse, nisi inscriptio electronica in [[Special:Preferences|modis tuis deligendis]] data confirmata est neu ab ea utenda non arceris!\n\nLocus IP tuus temporarius $3 est, haec obstructio sub numero #$5 relata est.\nQuaesumus haec omnia supra dicta cuipiam consultationi subiungas.",
+       "autoblockedtext": "Locus IP tuus automatice obstruitur, quia alius quidam, qui a magistratu $1 obstructus est, eo usus erat.\nRatio:\n\n:''$2''\n\n* Initium obstructionis: $8\n* Finis obstructionis: $6\n* Obstructio pertinet ad: $7\n\nTibi licet ad $1 vel [[{{MediaWiki:Grouppage-sysop}}|magistratum]] alium nuntium mittere, ut obstructio tua disceptetur.\n\nNota bene te litteras electronicas mittere non posse, nisi inscriptio electronica in [[Special:Preferences|modis tuis deligendis]] data confirmata est neu ab ea utenda non arceris!\n\nLocus IP tuus temporarius $3 est, haec obstructio sub numero #$5 relata est.\nQuaesumus haec omnia supra dicta cuipiam consultationi subiungas.",
        "blockednoreason": "nulla causa data",
        "whitelistedittext": "Necesse est tibi $1 priusquam paginas recenseas.",
        "confirmedittext": "Inscriptio tua electronica adfirmanda est priusquam paginas recenseas.\nQuaesumus eam in [[Special:Preferences|modis tuis seligendis]] notifices et confirmes.",
index 3e6c7c1..4b89335 100644 (file)
        "blocked-mailpassword": "Jūsų IP adresas yra užblokuotas nuo redagavimo, taigi neleidžiama naudoti slaptažodžio priminimo funkcijos, kad apsisaugotume nuo piktnaudžiavimo.",
        "eauthentsent": "Patvirtinimo laiškas buvo nusiųstas į paskirtąjį el. pašto adresą.\nPrieš išsiunčiant kitą laišką į jūsų dėžutę, jūs turite vykdyti nurodymus laiške, kad patvirtintumėte, kad dėžutė tikrai yra jūsų.",
        "throttled-mailpassword": "Slaptažodžio priminimas jau buvo išsiųstas, per {{PLURAL:$1|$1 paskutinę valandą|$1 paskutines valandas|$1 paskutinių valandų}}.\n\nNorint apsisaugoti nuo piktnaudžiavimo, slaptažodžio priminimas gali būti išsiųstas tik kas {{PLURAL:$1|$1 valandą|$1 valandas|$1 valandų}}.",
-       "mailerror": "Klaida siunčiant paštą: $1",
+       "mailerror": "Klaida siunčiant laišką: $1",
        "acct_creation_throttle_hit": "Šio projekto lankytojai, naudojantys jūsų IP adresą, sukūrė {{PLURAL:$1|$1 paskyrą|$1 paskyras|$1 paskyrų}} per paskutiniąją dieną, o tai yra didžiausias leidžiamas kiekis per šį laiko tarpą.\nTodėl šiuo metu lankytojai, naudojantys šį IP adresą, daugiau negali kurti paskyrų.",
        "emailauthenticated": "Jūsų el. pašto adresas buvo patvirtintas $2 d. $3.",
        "emailnotauthenticated": "Jūsų el. pašto adresas dar nėra patvirtintas. Jokie laiškai\nnebus siunčiami nei vienai žemiau išvardintai paslaugai.",
        "mergehistory-empty": "Versijos negali būti sujungtos",
        "mergehistory-done": "$3 $1 {{PLURAL:$3|versija|versijos|versijų}} sėkmingai {{PLURAL:$3|sujungta|sujungtos|sujungta}} su [[:$2]].",
        "mergehistory-fail": "Nepavyksta atlikti istorijų sujungimo, prašome patikrinti puslapio ir laiko parametrus.",
+       "mergehistory-fail-invalid-dest": "Paskirties puslapis yra neteisingas.",
        "mergehistory-fail-toobig": "Nepavyksta sulieti istorijos, nes būtina pernešti daugiau, nei leidžia $1 riba, {{PLURAL:$1|versijos|versijų}}.",
        "mergehistory-no-source": "Šaltinio puslapis $1 neegzistuoja.",
        "mergehistory-no-destination": "Rezultato puslapis $1 neegzistuoja.",
        "apisandbox": "API smėlio dėžės",
        "apisandbox-api-disabled": "API yra išjungtas šioje svetainėje.",
        "apisandbox-intro": "Naudokite šį puslapį norėdami eksperimentuoti su '''MediaWiki API \"„.\n\tIeškokite [//www.mediawiki.org/wiki/API:Main_page API dokumentacijoje] Išsamesnės informacijos apie API naudojimo.",
+       "apisandbox-fullscreen": "Išplėsti skydelį",
+       "apisandbox-unfullscreen": "Rodyti puslapį",
        "apisandbox-submit": "Pateikti prašymą",
        "apisandbox-reset": "Išvalyti",
        "apisandbox-retry": "Bandykite dar kartą",
        "apisandbox-no-parameters": "Šis API modulis neturi parametrų.",
+       "apisandbox-helpurls": "Pagalbinės nuorodos",
        "apisandbox-examples": "Pavyzdžiai",
        "apisandbox-dynamic-parameters": "Papildomi parametrai",
        "apisandbox-dynamic-parameters-add-label": "Pridėti parametrą:",
        "apisandbox-dynamic-parameters-add-placeholder": "Parametro pavadinimas",
+       "apisandbox-dynamic-error-exists": "Parametras, pavadinimu „$1“ jau yra.",
        "apisandbox-deprecated-parameters": "Nebenaudojami parametrai",
        "apisandbox-submit-invalid-fields-title": "Kai kurie laukai yra neteisingi",
        "apisandbox-results": "Rezultatai",
        "apisandbox-request-url-label": "Prašyti URL:",
        "apisandbox-request-time": "Užklausos laikas: $1",
+       "apisandbox-alert-field": "Šio lauko reikšmė yra neteisinga.",
        "booksources": "Knygų šaltiniai",
        "booksources-search-legend": "Knygų šaltinių paieška",
        "booksources-search": "Ieškoti",
        "expand_templates_preview_fail_html": "<em>Nes {{SITENAME}} turi įgalinta gryną HTML ir įvyko sesijos duomenų praradimas, peržiūra yra paslėpta kaip atsargos priemonė prieš JavaScript atakas.</em>\n\n<strong>Jei tai teisėtas peržiūros bandymas, prašome bandyti dar kartą.</strong>\nJei tai vistiek neveikia, pabandykite [[Special:UserLogout|atsijungti]] ir vėl prisijungti.",
        "expand_templates_preview_fail_html_anon": "<em>Nes {{SITENAME}} turi įgalinta gryną HTML ir jūs esate neprisijungęs, peržiūra paslėpta kaip atsargumo priemonė prieš JavaScript atakas.</em>\n\n<strong>Jei tai teisėtas peržiūros bandymas prašome [[Special:UserLogin|prisijungti]] ir bandyti vėl.</strong>",
        "expand_templates_input_missing": "Turite pateikti bent truputį įvesties teksto.",
-       "pagelanguage": "Puslapio kalbos pasirinkimas",
+       "pagelanguage": "Keisti puslapio kalbą",
        "pagelang-name": "Puslapis",
        "pagelang-language": "Kalba",
        "pagelang-use-default": "Naudoti numatytąją kalbą",
index 4d3fe0b..7437611 100644 (file)
        "userrights": "Dalībnieku tiesību pārvaldība",
        "userrights-lookup-user": "Pārvaldīt dalībnieka grupas",
        "userrights-user-editname": "Ievadi lietotājvārdu:",
-       "editusergroup": "Izmainīt dalībnieka grupas",
+       "editusergroup": "Izmainīt {{GENDER:$1|dalībnieka|dalībnieces}} grupas",
        "editinguser": "Izmainīt lietotāja '''[[User:$1|$1]]''' ([[User talk:$1|{{int:talkpagelinktext}}]]{{int:pipe-separator}}[[Special:Contributions/$1|{{int:contribslink}}]]) statusu",
        "userrights-editusergroup": "Izmainīt lietotāja grupas",
-       "saveusergroups": "Saglabāt dalībnieka grupas",
+       "saveusergroups": "Saglabāt {{GENDER:$1|dalībnieka|dalībnieces}} grupas",
        "userrights-groupsmember": "Šobrīd ietilpst grupās:",
        "userrights-groupsmember-auto": "Netiešs dalībnieks:",
        "userrights-groups-help": "Tu vari izmainīt kādās grupās šis lietotājs ir:\n* Ieķeksēts lauciņš norāda, ka lietotājs ir attiecīgajā grupā.\n* Neieķeksēts lauciņš norāda, ka lietotājs nav attiecīgajā grupā.\n* * norāda, ka šo grupu tu nevarēsi noņemt, pēc tam, kad to būsi pielicis, vai otrādāk (tu nevarēsi atcelt savas izmaiņas).",
        "recentchanges-label-bot": "Šis ir bota veikts labojums",
        "recentchanges-label-unpatrolled": "Šis labojums vēl nav pārbaudīts",
        "recentchanges-label-plusminus": "Par tik baitiem tika izmainīts lapas izmērs",
-       "recentchanges-legend-heading": "'''Apzīmējumi:'''",
+       "recentchanges-legend-heading": "<strong>Apzīmējumi:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (skatīt arī [[Special:NewPages|jaunās lapas]])",
        "recentchanges-submit": "Rādīt",
        "rcnotefrom": "Šobrīd redzamas izmaiņas kopš '''$2''' (parādītas ne vairāk par '''$1''').",
        "apisandbox": "API smilškaste",
        "apisandbox-api-disabled": "API ir atspējots šajā tīmekļa vietnē.",
        "apisandbox-reset": "Notīrīt",
-       "apisandbox-examples": "Piemērs",
-       "apisandbox-results": "Rezultāts",
+       "apisandbox-examples": "Piemēri",
+       "apisandbox-results": "Rezultāti",
        "apisandbox-request-url-label": "Pieprasījuma URL:",
        "apisandbox-request-time": "Pieprasījuma izpildes laiks: $1",
        "booksources": "Grāmatu avoti",
        "movenotallowedfile": "Tev nav atļaujas pārvietot failus.",
        "cant-move-user-page": "Tev nav atļaujas pārvietot lietotāju lapas (neskaitot apakšlapas).",
        "cant-move-to-user-page": "Tev nav atļaujas pārvietot lapu uz lietotāja lapu (neskaitot lietotāja lapas apakšlapu).",
-       "newtitle": "Uz šādu lapu",
+       "newtitle": "Jaunais nosaukums:",
        "move-watch": "Uzraudzīt šo lapu",
        "movepagebtn": "Pārvietot lapu",
        "pagemovedsub": "Pārvietošana notikusi veiksmīgi",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|versijas|versija|versijas}} no $2",
        "javascripttest": "JavaScript testēšana",
        "javascripttest-pagetext-unknownaction": "Nezināma darbība \"$1\".",
-       "tooltip-pt-userpage": "Tava lietotāja lapa",
+       "tooltip-pt-userpage": "Tava {{GENDER:|dalībnieka|dalībnieces}} lapa",
        "tooltip-pt-anonuserpage": "Manas IP adreses lietotāja lapa",
-       "tooltip-pt-mytalk": "Tava diskusiju lapa",
+       "tooltip-pt-mytalk": "{{GENDER:|Tava}} diskusiju lapa",
        "tooltip-pt-anontalk": "Diskusija par labojumiem, kas izdarīti no šīs IP adreses",
-       "tooltip-pt-preferences": "Tavas izvēles",
+       "tooltip-pt-preferences": "{{GENDER:|Tavas}} izvēles",
        "tooltip-pt-watchlist": "Tevis uzraudzītās lapas",
        "tooltip-pt-mycontris": "{{GENDER:|Tavs}} devums",
        "tooltip-pt-anoncontribs": "Labojumi, kas veikti no šīs IP adreses",
index 811a65a..affe36a 100644 (file)
@@ -15,6 +15,7 @@
        "tog-hideminor": "Hanitsika ny fiovana madinika ao amin'ny fiovana farany",
        "tog-hidepatrolled": "Hanitrika ny fiovana voaara-maso ao amin'ny fiovana farany",
        "tog-newpageshidepatrolled": "Hanitsika ny pejy voaara-maso ao amin'ny pejy vaovao",
+       "tog-hidecategorization": "Hanafina ny fansokajiana pejy",
        "tog-extendwatchlist": "Hanitatra ny lisitra fanaraham-pejy mba haneho ny fanovana rehetra fa tsy ny vaovao indrindra fotsiny",
        "tog-usenewrc": "Hampivondrona ny fiovana araky ny pejy ao amin'ny fiovana farany ary ao amin'ny lisitry ny pejy arahana",
        "tog-numberheadings": "Asio laharany ny lohateny",
        "tog-watchlisthidebots": "Asitriho amin'ny lisitro ny fanovàna nataon'ny rôbô",
        "tog-watchlisthideminor": "Tsy aseho ny fisoloina kely anatin'ny pejy fanaraha-maso",
        "tog-watchlisthideliu": "Asitriho amin'ny lisitro ny fanovàna nataon'ny mpikambana hafa",
+       "tog-watchlistreloadautomatically": "Hanavao ny lisitry ny pejy arahana rehefa misy sivana niova (mila JavaScript)",
        "tog-watchlisthideanons": "Asitriho amin'ny lisitro ny fanovana nataon'ny IP",
        "tog-watchlisthidepatrolled": "Asitriho amin'ny lisitro ny fanovàna efa nojerena",
+       "tog-watchlisthidecategorization": "Hanafina ny fanasokajiana pejy",
        "tog-ccmeonemails": "Andefaso tahaka ny imailaka alefako amin'ny mpikambana hafa",
        "tog-diffonly": "Aza ampiseho ny voatonin'ny pejy eo amban'ny diff",
        "tog-showhiddencats": "Asehoy ny sokajy misitrika",
        "october-date": "$1 Oktobra",
        "november-date": "$1 Novambra",
        "december-date": "$1 Desambra",
+       "period-am": "Mrn",
+       "period-pm": "Hrv",
        "pagecategories": "{{PLURAL:$1|Sokajy|Sokajy}}",
        "category_header": "Ireo lahatsoratra ao amin'ny sokajy \"$1\"",
        "subcategories": "Zana-tsokajy",
        "morenotlisted": "Tsy feno ity lisitra ity.",
        "mypage": "Pejy",
        "mytalk": "Dinika",
-       "anontalk": "Resaka ho an'io adiresy IP io",
+       "anontalk": "Pejin-dresaka",
        "navigation": "Fikarohana",
        "and": "&#32;sy",
        "qbfind": "Tadiavina",
        "nstab-template": "Endrika",
        "nstab-help": "Fanoroana",
        "nstab-category": "Sokajy",
+       "mainpage-nstab": "Fandraisana",
        "nosuchaction": "Asa tsy fantatra",
        "nosuchactiontext": "Ny asa voafaritra tao amin'ny URL dia tsy fantatr'ity wiki ity",
        "nosuchspecialpage": "Tsy misy io pejy manokana io",
        "databaseerror-query": "Hataka: $1",
        "databaseerror-function": "Lefa: $1",
        "databaseerror-error": "Hadisoana: $1",
+       "transaction-duration-limit-exceeded": "Mba tsy hisian'ny fihalavan'ny fotoam-pandikana be loatra, dia nofoanana ity asa ity satria nihoatra ny fetra $2 {{PLURAL:$2}}segondra ny fotoana nalain'ny asa fanoratana ($1 s). Raha manova zavatra mibolongana be indray mandeha ianao dia zarazarao ho kelikely ny zavatra ataonao.",
        "laggedslavemode": "Fampitandremana: Mety ho tsy nisy fanovana vao haingana angamba io pejy io",
        "readonly": "Mihidy ny banky angona",
        "enterlockreason": "Manomeza antony hanidiana ny pejy, ahitana ny fotoana tokony hamahana izay fihidiana izay",
        "virus-scanfailed": "Tsy mety alefa ny fitadiavana (kaody $1)",
        "virus-unknownscanner": "Tsy fantatra io Antivirus io :",
        "logouttext": "'''Efa tafavoaka amin'izay ianao.'''\n\nFantaro fa mety mbola misy ireo pejy milaza anao fa mbola tafiditra raha tsy namafa ny pejy voatakona (cache) ianao.",
+       "cannotlogoutnow-title": "Tsy afaka mivoaka amin'izao fotoana izao",
+       "cannotlogoutnow-text": "Tsy afaka mivoaka rehetra mampiasa $1.",
        "welcomeuser": "Tonga soa, $1",
        "welcomecreation-msg": "Noforonina ny aontinao.\nAza adin ny manova ny [[Special:Preferences|safidinao ro amin'i{{SITENAME}}]].",
        "yourname": "Solonanarana",
        "remembermypassword": "{{PLURAL:}}Tadidio ny tenimiafiko (mandritry ny $1 andro fara-fahabetsany)",
        "userlogin-remembermypassword": "Tadidio aho",
        "userlogin-signwithsecure": "Fidirana amin'ny alalan'ny fanohizana azo antoka",
+       "cannotloginnow-title": "Tsy afaka miditra izao",
+       "cannotloginnow-text": "Tsy afaka miditra rehefa mampiasa $1.",
        "yourdomainname": "faritra (domaine) misy anao",
        "password-change-forbidden": "Tsy afaka manova ny tenimiafina ianao eto amin'ity wiki ity.",
        "externaldberror": "Nisy tsy fetezana angamba teo amin'ny fanamarinana anao tamin'ny sehatra ivelan'ity wiki ity, na tsy manana alalana hanova ny kaontinao ivelany ianao.",
        "createacct-benefit-body2": "pejy{{PLURAL:$1}}",
        "createacct-benefit-body3": "mpandray anjara vao haingana{{PLURAL:$1}}",
        "badretype": "Tsy mitovy ny tenimiafina nampidirinao.",
+       "usernameinprogress": "Efa am-panatanterahana ny famoronan-kaonty amin'ity anaram-pikambana ity.\nMiandrasa azafady.",
        "userexists": "Efa miasa io anaram-pikambana natsofokao io.\nAnarana hafa safidiana.",
        "loginerror": "Tsy fetezana teo amin'ny fidirana",
        "createacct-error": "Hadisoana tam-pamoronana ny kaonty",
        "resetpass_submit": "Ovay ny tenimiafina ary midira",
        "changepassword-success": "Voaova soa aman-tsara ny tenimiafinao!",
        "changepassword-throttled": "Betsaka loatra ny andram-pidirana nataonao.\nAndraso $1 aloha ny mamerina.",
+       "botpasswords": "Tenimiafin-drôbô",
+       "botpasswords-disabled": "Tsy ampiasaina ny tenimiafin-drôbô.",
+       "botpasswords-existing": "Tenimiafin-drôbô efa misy",
+       "botpasswords-label-appid": "Anarana rôbô:",
+       "botpasswords-label-create": "Foronina",
+       "botpasswords-label-update": "Vaozina",
+       "botpasswords-label-cancel": "Avela",
+       "botpasswords-label-delete": "Fafàna",
+       "botpasswords-label-resetpassword": "Hamerina ny tenimiafina",
+       "botpasswords-label-grants": "Zo mihatra:",
+       "botpasswords-label-grants-column": "Nomena",
+       "botpasswords-bad-appid": "Tsy azo raisina ny anarana rôbô \"$1\".",
+       "botpasswords-insert-failed": "Tsy afaka nanampy ny anarana rôbô \"$1\". Tsy efa nampiana ve ilay izy?",
        "resetpass_forbidden": "Tsy afaka ovaina ny tenimiafina",
        "resetpass-no-info": "Tsy maintsy tafiditra ao amin'ny kaontinao ianao vao afaka mijery ity pejy ity.",
        "resetpass-submit-loggedin": "Ovay ny tenimiafina",
        "recentchanges-label-bot": "Nataon'ny rôbô ity fanovana ity.",
        "recentchanges-label-unpatrolled": "Ity fanovana ity dia mbola tsy voamarina",
        "recentchanges-label-plusminus": "IO ny isan'ny oktety niova tamin'ilay pejy",
-       "recentchanges-legend-heading": "'''Maribolana:'''",
+       "recentchanges-legend-heading": "<strong>Maribolana:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (jereo koa ny [[Special:NewPage|lisitry ny pejy vaovao]])",
        "rcnotefrom": "Eo ambany dia ahitana ireo fiovana{{PLURAL:$5}} hatry ny <strong>$3, $4</strong> (naseho hatramin'ny <strong>$1</strong>).",
        "rclistfrom": "Asehoy izay vao niova manomboka ny $3 $2",
        "contributions": "Fandraisan'anjaran'ny mpikambana{{GENDER:$1}}",
        "contributions-title": "Fandraisan'anjaran'i $1",
        "mycontris": "Fandraisan'anjara",
+       "anoncontribs": "Fandraisan'anjara",
        "contribsub2": "Ho an'i {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Tsy misy fanovana mifanaraka amin'ireo critères ireo.",
        "uctop": "(ankehitriny)",
        "javascripttest": "Fanandramana JavaScript",
        "javascripttest-pagetext-skins": "Mifidia skin hanaovana ny fanandramana:",
        "javascripttest-qunit-intro": "Jereo ny [$1 fanoroana mikasika ny andrana] eo amin'i mediawiki.org.",
-       "tooltip-pt-userpage": "Ny pejinao",
+       "tooltip-pt-userpage": "Ny pejim-pikambanao",
        "tooltip-pt-anonuserpage": "Ny pejim-bikamban'ny IP andraisanao anjara",
        "tooltip-pt-mytalk": "Pejin-dresakao",
        "tooltip-pt-anontalk": "Ny pejin-dresaka ho an'ny fandraisan' anjara tamin'ny alànan'ity IP ity",
-       "tooltip-pt-preferences": "Ny safidinao",
+       "tooltip-pt-preferences": "Ny safidinao{{GENDER:|}}",
        "tooltip-pt-watchlist": "Ny lisitra ny pejy arahanao-maso",
        "tooltip-pt-mycontris": "Lisitra ny fandraisan'anjaranao",
        "tooltip-pt-login": "Tsara aminao no miditra na misoratra anarana, fa tsy voatery ianao.",
        "tooltip-t-recentchangeslinked": "Lisitry ny fanovàna faran'ny pejy manana rohy amin'ity zavatra ity",
        "tooltip-feed-rss": "Topaka RSS ho an'ity pejy ity",
        "tooltip-feed-atom": "Topaka atom ho an'ity pejy ity",
-       "tooltip-t-contributions": "Hijery ny lisitry ny fandraisan'anjara n'io mpikambana io",
+       "tooltip-t-contributions": "Lisitry ny fandraisan'anjara n'io mpikambana io{{GENDER:$1|}}",
        "tooltip-t-emailuser": "Handefa imailaka any amin'io mpikambana io",
        "tooltip-t-upload": "Handefa sary na rakitra",
        "tooltip-t-specialpages": "Listry ny pejy manokana rehetra",
index 1e14fc4..cd21621 100644 (file)
        "copyrightwarning2": "{{SITENAME}} တွင် ရေးသားမှုအားလုံးသည် အခြားပုံပိုးသူများ၏ တည်းဖြတ်၊ ပြောင်းလဲ၊ ဖယ်ရှားခံရနိုင်သည်ကို သတိပြုပါ။\nအကယ်၍ သင့်ရေးသားချက်များကို အညှာအတာမရှိ တည်းဖြတ်ခံရခြင်း၊ စိတ်တိုင်းကျ ဖြန့်ဝေခံရခြင်းတို့ကို အလိုမရှိပါက ဤနေရာတွင် မတင်ပါနှင့်။<br />\nသင်သည် ဤဆောင်းပါးကို သင်ကိုယ်တိုင်ရေးသားခြင်း၊ သို့မဟုတ် အများပြည်သူဆိုင်ရာဒိုမိန်းများ၊ ယင်းကဲ့သို့ လွတ်လပ်သည့် ရင်းမြစ်မှ ကူးယူထားခြင်း ဖြစ်ကြောင်းလည်း ဝန်ခံ ကတိပြုပါသည် (အသေးစိတ်ကို $1 တွင်ကြည့်ပါ)။\n<strong>မူပိုင်ခွင့်ရှိသော စာ၊ပုံများကို ခွင့်ပြုချက်မရှိဘဲ မတင်ပါနှင့်။</strong>",
        "templatesused": "{{PLURAL:$1|တမ်းပလိတ်|တမ်းပလိတ်}} ခုကို ဤစာမျက်နှာကို သုံးထားသည် -",
        "templatesusedpreview": "{{PLURAL:$1|တမ်းပလိတ်|တမ်းပလိတ်}} ခုကို ဤနမူနာတွင် သုံးထားသည် -",
+       "templatesusedsection": "ဤအပိုင်းတွင် အသုံးပြုထားသော {{PLURAL:$1|တမ်းပလိတ်|တမ်းပလိတ်များ}}:",
        "template-protected": "(ကာကွယ်ထားသည်)",
        "template-semiprotected": "(တစ်စိတ်တစ်ပိုင်း ကာကွယ်ထားသည်)",
        "hiddencategories": "ဤစာမျက်နှာသည် {{PLURAL:$1|ဝှက်ထားသော ကဏ္ဍတစ်ခု|ဝှက်ထားသော ကဏ္ဍ $1 ခု}} ၏ အဖွဲ့ဝင် ဖြစ်သည်။",
        "nocreate-loggedin": "သင်သည် စာမျက်နှာအသစ် ဖန်တီးခွင့်မရှိပါ။",
        "sectioneditnotsupported-title": "ခေါင်းစဉ်ခွဲအလိုက် တည်းဖြတ်ခြင်းကို မထောက်ပံ့ထားပါ",
+       "sectioneditnotsupported-text": "အပိုင်းလိုက်တည်းဖြတ်ခြင်းကို ဤစာမျက်နှာတွင် မရနိုင်ပါ။",
        "permissionserrors": "ခွင့်ပြုချက်အမှား",
        "permissionserrorstext": "အောက်ပါ {{PLURAL:$1|အကြောင်းပြချက်|အကြောင်းပြချက်များ}}ကြောင့် ထိုအရာအတွက် ခွင့်ပြုချက်မရှိပါ -",
        "permissionserrorstext-withaction": "အောက်ပါ အကြောင်းပြချက် {{PLURAL:$1|ခု|ခု}} ကြောင့် $2 အတွက် ခွင့်ပြုချက်မရှိပါ -",
        "edit-gone-missing": "စာမျက်နှာကို အပ်ဒိတ်မလုပ်နိုင်ပါ။\nအဖျက်ခံလိုက်ရပုံပေါ်သည်။",
        "edit-conflict": "အငြင်းပွားမှုကို တည်းဖြတ်ရန်။",
        "edit-no-change": "စာသားကို အပြောင်းအလဲ မလုပ်ခဲ့သောကြောင့် တည်းဖြတ်မှုကို လျစ်လျူရှုလိုက်သည်။",
+       "postedit-confirmation-created": "စာမျက်နှာကို ဖန်တီးပြီးပြီ။",
+       "postedit-confirmation-restored": "စာမျက်နှာကို ပြန်လည်ထိန်းသိမ်းပြီးပြီ။",
+       "postedit-confirmation-saved": "သင့်တည်းဖြတ်မှုကို သိမ်းဆည်းပြီးပြီ။",
        "edit-already-exists": "စာမျက်နှာအသစ်တစ်ခု မဖန်တီးနိုင်ပါ။\nယင်းစာမျက်နှာ တည်ရှိပြီး ဖြစ်သည်။",
        "duplicate-args-category": "တမ်းပလိတ်တွင်းရှိ arguments ထပ်နေသော စာမျက်နှာများ",
        "post-expand-template-inclusion-warning": "'''သတိပေးချက် -''' တမ်းပလိတ်အရွယ်အစား ကြီးလွန်းနေသည်။\nအချို့တမ်းပလိတ်တို့ ပါဝင်မည်မဟုတ်။",
        "histlast": "အသစ်ဆုံး",
        "historyempty": "(ဘာမှမရှိ)",
        "history-feed-title": "မူရာဇဝင်မှတ်တမ်း",
+       "history-feed-description": "ဝီကီပေါ်ရှိ ဤစာမျက်နှာ၏ တည်းဖြတ်မှုရာဇဝင်",
        "history-feed-item-nocomment": "$2 က $1",
        "rev-deleted-comment": "(တည်းဖြတ်မှုအတိုချုပ် ဖယ်ရှားပြီး)",
        "rev-deleted-user": "(အသုံးပြုသူအမည် ဖယ်ရှားပြီး)",
+       "rev-deleted-event": "(အသေးစိတ် မှတ်တမ်း ဖယ်ရှားပြီးပြီ)",
+       "rev-deleted-text-permission": "ဤစာမျက်နှာ ရာဇဝင်များသည် <strong>ဖျက်ထားပြီး</strong>ဖြစ်သည်။\nအသေးစိတ်များကို [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ဖျက်ထားသည့် မှတ်တမ်း]တွင် တွေ့ရှိနိုင်ပါသည်။",
        "rev-delundel": "အမြင်ပုံစံ ပြောင်းလဲရန်",
        "rev-showdeleted": "ပြ",
        "revisiondelete": "မူများကို ဖျက်ရန်/မဖျက်တော့ရန်",
        "revertmerge": "ပြန်ခွဲထုတ်ရန်",
        "history-title": "\"$1\"၏ တည်းဖြတ်မှု ရာဇဝင်",
        "difference-title": "\"$1\" ၏ တည်းဖြတ်မှု မူကွဲများ",
+       "difference-title-multipage": "စာမျက်နှာ \"$1\" နှင့် \"$2\" အကြား ကွဲပြားမှု",
        "difference-multipage": "(စာမျက်နှာများကြားမှ ကွဲပြားချက်များ)",
        "lineno": "စာကြောင်း $1 -",
        "compareselectedversions": "ရွေးချယ်ထားသော မူများကို နှိုင်းယှဉ်ရန်",
        "showhideselectedversions": "ရွေးချယ်ထားသော မူများကို ပြရန်/ဝှက်ရန်",
        "editundo": "နောက်ပြန် ပြန်ပြင်ရန်",
+       "diff-empty": "(ကွဲပြားမှု မရှိ)",
        "searchresults": "ရှာဖွေမှု ရလဒ်များ",
        "searchresults-title": "\"$1\" အတွက် ရှာတွေ့သည့် ရလဒ်များ",
        "titlematches": "စာမျက်နှာခေါင်းစဉ်ကိုက်ညီသည်",
        "search-result-category-size": "{{PLURAL:$1|အသင်းဝင်တစ်ခု|အသင်းဝင် $1 ခု}} ({{PLURAL:$2|ကဏ္ဍခွဲတစ်ခု|ကဏ္ဍခွဲ $2 ခု}}, {{PLURAL:$3|ဖိုင်တစ်ခု|ဖိုင် $3 ခု}})",
        "search-redirect": "($1 သို့ ပြန်ညွှန်းသည်)",
        "search-section": "(အပိုင်း $1)",
+       "search-category": "(ကဏ္ဍ $1)",
        "search-suggest": "$1 ဟု ဆိုလိုပါသလား။",
        "search-interwiki-caption": "ညီအစ်မ ပရောဂျက်များ",
        "search-interwiki-default": "$1 မှ ရလဒ်များ -",
        "right-userrights": "အသုံးပြုသူ၏အခွင့်အရေးများအားလုံးကို တည်းဖြတ်ရန်",
        "right-userrights-interwiki": "အခြားဝီကီများမှ အသုံးပြုသူများ၏ အသုံးပြုသူအခွင့်အရေးများကို တည်းဖြတ်ရန်",
        "right-sendemail": "အခြားအသုံးပြုသူများကို အီးမေးပို့ရန်",
+       "grant-editmywatchlist": "သင့် စောင့်ကြည့်စာရင်းကို တည်းဖြတ်ရန်",
        "newuserlogpage": "အသုံးပြုသူအသစ်ရောက်လာခြင်း မှတ်တမ်း",
        "newuserlogpagetext": "ဤသည်မှာ အသုံးပြုသူအသစ် ဖတ်တီးမှု မှတ်တမ်း ဖြစ်သည်။",
        "rightslog": "အသုံးပြုသူ၏ အခွင့်အရေးများ မှတ်တမ်း",
        "undelete-show-file-submit": "မှန်",
        "namespace": "အမည်ညွှန်း -",
        "invert": "ရွေးချယ်ထားခြင်းကို ပြောင်းပြန်လှန်ရန်",
+       "tooltip-invert": "ဤအကွက်ကို အမှန်ခြစ်၍ ရွေးချယ်ထားသော အမည်ညွှန်း (နှင့် ဆက်စပ်အမည်ညွှန်း)တွင် ပြောင်းလဲမှုများကို ဝှက်ပါ။",
        "namespace_association": "ဆက်စပ်နေသော အမည်ညွှန်း",
        "blanknamespace": "(ပင်မ)",
        "contributions": "{{GENDER:$1|အသုံးပြုသူ}}၏ ဆောင်ရွက်ချက်များ",
        "svg-long-desc": "SVG ဖိုင်, $1 × $2 pixels ကို အကြံပြုသည်, ဖိုင်အရွယ်အစား - $3",
        "show-big-image": "မူရင်းဖိုင်",
        "show-big-image-preview": "ဤနမူနာ၏ အရွယ်အစား - $1။",
+       "show-big-image-other": "အခြား {{PLURAL:$2|ပုံရိပ်ပြတ်သားမှု|ပုံရိပ်ပြတ်သားမှု}}: $1။",
        "newimages": "ပုံအသစ်များပြခန်း",
        "newimages-legend": "စိစစ်မှု",
        "newimages-label": "ဖိုင်အမည် (သို့ ယင်း၏အစိတ်အပိုင်း) -",
        "exif-software": "အသုံးပြုထားသော ဆော့ဝဲ",
        "exif-artist": "ဖန်တီးသူ",
        "exif-copyright": "မူပိုင်ခွင့်ပိုင်ရှင်",
+       "exif-exifversion": "Exif ဗားရှင်း",
+       "exif-colorspace": "အရောင်နေရာ",
        "exif-pixelydimension": "ပုံအကျယ်",
        "exif-pixelxdimension": "ပုံအမြင့်",
        "exif-usercomment": "အသုံးပြုသူ မှတ်ချက်များ",
index 8f2799e..cc7d313 100644 (file)
        "newarticle": "(Nuovo)",
        "newarticletext": "Site ghiuto/a addò nu link 'e na paggena ca nun esiste ancora.\nP' 'a crià sta paggena, accummenciate a scrivere dint'a cascia cà abbascio (vedite 'a [$1 paggena d'aiuto] pe liegge cchiù nfurmazziune).\nSi site venuto/a ccà pe' sbaglio, vedite 'e sprémmere 'o buttòne '''Arreto''' d' 'o navigatóre.",
        "anontalkpagetext": "----\n''Chest'è 'a paggena 'e discussione 'e n'utente anonimo, ca nun ave criàt' 'ancora n'utenza o ca nun sta ausanno. Pe' l'identificà avite 'e truvà 'o nummero d' 'o ndirizzo IP d' 'o sujo. L'indirizze IP se ponno spartì però sempe ausanno cunte differente. Si site n'utente anonimo e penzate ca 'e cummente ccà dint'a sta paggena nun parlano 'e vuje, allora [[Special:UserLogin/signup|criate n'utenza nnova]] o [[Special:UserLogin|trasite cu chella ca tenite già]] pe' nun sta' mmescato mmiez'a l'ati utente anonime n futuro.''",
-       "noarticletext": "Mo' mo' 'a paggena richiesta è abbacante. Se pò [[Special:Search/{{PAGENAME}}|ascià stu titolo]] dint'a l'ati paggene d' 'o sito, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ascià dint'e riggistre azzeccate] o pure [{{fullurl:{{FULLPAGENAME}}|action=edit}} cagnà 'a paggena mo']</span>.",
+       "noarticletext": "Mo' mo' 'a paggena richiesta è abbacante. Se pò [[Special:Search/{{PAGENAME}}|ascià stu titolo]] dint'a l'ati paggene d' 'o sito, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ascià dint'e riggistre azzeccate] o pure [{{fullurl:{{FULLPAGENAME}}|action=edit}} crià 'a paggena mo']</span>.",
        "noarticletext-nopermission": "Mo' mo' 'a paggena richiesta è abbacante. Se pò [[Special:Search/{{PAGENAME}}|ascià stu titolo]] dint'a l'ati paggene d' 'o sito, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ascià dint'e riggistre azzeccate]</span>, però nun tenite 'o permesso 'a crià sta paggena.",
        "missing-revision": "'A verziona #$1 d' 'a paggena \"{{FULLPAGENAME}}\" nun esiste.\n\nChest'è causato quanno se và dint'a nu link a na paggena ch'è stata scancellata.\n'E dettaglie se ponno truvà dint'a [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 'o riggistro 'e scancellamiente].",
        "userpage-userdoesnotexist": "'O cunto utente \"<nowiki>$1</nowiki>\" nun è riggistrato. Cuntrolla ca si buò overo crià o cagnà sta paggena.",
        "recentchanges-label-bot": "Cagnamiento affettuato 'a nu bot",
        "recentchanges-label-unpatrolled": "Chista modifica nun è stata 'ncora verificata",
        "recentchanges-label-plusminus": "'A grannezza d' 'a paggena s'è cagnata pe' bbia 'e stu nummero 'e bytes",
-       "recentchanges-legend-heading": "'''Liggenda:'''",
+       "recentchanges-legend-heading": "<strong>Liggenda:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (vide [[Special:NewPages|'e paggene nove]])",
        "recentchanges-submit": "Faje vedé",
        "rcnotefrom": "Ccà abbascio {{PLURAL:$5|è alencato 'o cagnamiento appurtato|song' alincate 'e cagnamiente appurtate}} 'a <strong>$3, $4</strong> (mmustate nfin'a <strong>$1</strong>).",
        "backend-fail-read": "Nun se può lieggere 'o file \"$1\".",
        "backend-fail-create": "Nun se può scrivere 'o file \"$1\"",
        "backend-fail-maxsize": "Nun se può scrivere 'o file \"$1\" pecché chist'è cchiù gruosso 'e {{PLURAL:$2|nu byte|$2 byte}}",
-       "backend-fail-readonly": "L'archivio 'e rezza \"$1\" è mò mò 'n sola-lettura. 'O mutivo è: \"$2\"",
+       "backend-fail-readonly": "L'archivio 'e rezza \"$1\" è mò mò 'n sola-lettura. 'O mutivo è: <em>$2</em>",
        "backend-fail-synced": "'O file \"$1\" è int' 'a nu stato ncunzistente dint'a l'archivie nterne.",
        "backend-fail-connect": "Nun se può cunnettà â memoria 'e rezza \"$1\".",
        "backend-fail-internal": "N'errore scanusciuto s'è verificato int'a l'archivie 'e rezza \"$1\".",
        "delete-toobig": "Sta paggena tene na storia 'e cagnamiente troppo longa, ncopp'a $1 {{PLURAL:$1|verzione|verziune}}.\n'O scancellamiento 'e chiste paggene è stato ristretto pe nce 'e putè astipà si ce sta cocche probblema dint' 'o database 'e {{SITENAME}}.",
        "delete-warning-toobig": "Sta paggena tene na cronologgia troppo longa, ncopp'a $1 {{PLURAL:$1|verzione|verziune}}.\nScancellannole se putesse crià troppo burdello ncopp' 'e operaziune 'e database dint'a {{SITENAME}};\niate cuoncio cuoncio.",
        "deleteprotected": "Nun putite scancellà sta paggena pecché è stata prutetta.",
-       "deleting-backlinks-warning": "'''Attenzione:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|ati paggene]] cunteneno cullegamiente o paggene appennute â n'ata paggena ca state pe' scancellà.",
+       "deleting-backlinks-warning": "<strong>Attenzione:</strong>\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|ati paggene]] cunteneno cullegamiente o paggene appennute â n'ata paggena ca state pe' scancellà.",
        "rollback": "Ausa na revizione 'e primma",
        "rollbacklink": "a vascio",
        "rollbacklinkcount": "annulla {{PLURAL:$1|nu cagnamiento|$1 cagnamiente}}",
        "tags-edit-revision-legend": "Azzecca o leva tags 'a {{PLURAL:$1|sta verziona|'e tutte sti $1 verziune}}",
        "tags-edit-logentry-legend": "Azzecca o leva tags 'a {{PLURAL:$1|sta verziona|'e tutte sti $1 verziune}}",
        "tags-edit-existing-tags": "Tag 'e mo:",
-       "tags-edit-existing-tags-none": "''Nisciuno''",
+       "tags-edit-existing-tags-none": "<em>Nisciuno</em>",
        "tags-edit-new-tags": "Nnove tag:",
        "tags-edit-add": "Azzecca sti tag:",
        "tags-edit-remove": "Lèva sti tag:",
index d91ed95..8fb4001 100644 (file)
        "listgrouprights-namespaceprotection-header": "Ograniczenia przestrzeni nazw",
        "listgrouprights-namespaceprotection-namespace": "Przestrzeń nazw",
        "listgrouprights-namespaceprotection-restrictedto": "Uprawnienia pozwalające użytkownikom na edytowanie",
+       "listgrants": "Uprawnienia",
+       "listgrants-grant": "Uprawnienie",
        "listgrants-rights": "Uprawnienie",
        "trackingcategories": "Śledzenie kategorii",
        "trackingcategories-summary": "Ta strona zawiera listę kategorii monitorujących wypełnianych automatycznie przez oprogramowanie MediaWiki. Nazwy kategorii można zmienić edytując odpowiednie komunikaty systemowe znajdujące się w przestrzeni nazw {{ns:8}}.",
        "delete-toobig": "Ta strona ma bardzo długą historię edycji – ponad $1 {{PLURAL:$1|zmianę|zmiany|zmian}}.<br />\nUsuwanie jej zostało ograniczone ze względu na możliwość zakłócenia pracy {{GRAMMAR:D.lp|{{SITENAME}}}}.",
        "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": "''' Uwaga:''' Do strony, którą masz zamiar usunąć, odwołują się [[Special:WhatLinksHere/{{FULLPAGENAME}}|inne strony]].",
+       "deleting-backlinks-warning": "<strong>Uwaga:</strong> Do strony, którą masz zamiar usunąć, odwołują się [[Special:WhatLinksHere/{{FULLPAGENAME}}|inne strony]].",
        "rollback": "Cofnij edycję",
        "rollbacklink": "cofnij",
        "rollbacklinkcount": "cofnij $1 {{PLURAL:$1|edycję|edycje|edycji}}",
        "expand_templates_generate_xml": "Pokaż drzewo analizatora składni w formacie XML",
        "expand_templates_generate_rawhtml": "Pokaż surowy HTML",
        "expand_templates_preview": "Podgląd",
-       "expand_templates_preview_fail_html": "<em>Ponieważ {{SITENAME}} ma włączony surowy kod HTML i zaistniała strata danych z sesji, podgląd jest ukryty jako zabezpieczenie przed atakiem JavaScript.</em>\n\n<strong>Jeśli to jest próba słusznego podglądu, proszę spróbować ponownie.</strong>\nJeśli to nadal nie działa, spróbuj [[Special:UserLogout|wylogować się]] i zalogować się z powrotem.",
+       "expand_templates_preview_fail_html": "<em>Ponieważ {{SITENAME}} ma włączony surowy kod HTML i zaistniała strata danych z sesji, podgląd jest ukryty jako zabezpieczenie przed atakiem JavaScript.</em>\n\n<strong>Jeśli to jest próba słusznego podglądu, proszę spróbować ponownie.</strong>\nJeśli to nie pomoże – spróbuj [[Special:UserLogout|wylogować się]] i zalogować ponownie, a także upewnij się, że twoja przeglądarka akceptuje ciasteczka z tej witryny.",
        "pagelanguage": "Zmiana języka strony",
        "pagelang-name": "Strona",
        "pagelang-language": "Język",
index 1a2a59e..304fd47 100644 (file)
        "permissionserrors": "Erro de permissão",
        "permissionserrorstext": "Não possui permissão para fazer isso, {{PLURAL:$1|pelo seguinte motivo|pelos seguintes motivos}}:",
        "permissionserrorstext-withaction": "Não possui permissão para $2, {{PLURAL:$1|pelo seguinte motivo|pelos seguintes motivos}}:",
-       "contentmodelediterror": "Não pode editar esta revisão pois seu modelo de conteúdo é <code>$1</code>, e o modelo actual do conteúdo da página é <code>$2</code>.",
+       "contentmodelediterror": "Não pode editar esta revisão pois seu modelo de conteúdo é <code>$1</code>, que é diferente do modelo atual da página <code>$2</code>.",
        "recreate-moveddeleted-warn": "'''Aviso: Está a recriar uma página anteriormente eliminada.'''\n\nVerifique se é apropriado continuar a editar esta página.\nPara sua conveniência, é apresentado de seguida o registo de eliminação e de movimento da página:",
        "moveddeleted-notice": "Esta página foi eliminada.\nPara referência, é apresentado de seguida o registo de eliminações e de movimento da página.",
        "moveddeleted-notice-recent": "Desculpe, esta página foi eliminada recentemente (nas últimas 24 horas).\nA exclusão e registo de movimentação para a página são fornecidos abaixo para referência.",
        "apihelp-no-such-module": "Módulo \"$1\" não encontrado.",
        "apisandbox": "Testes da API",
        "apisandbox-api-disabled": "A API está desativada neste site.",
-       "apisandbox-intro": "Use esta página para fazer experiências com a '''API de <i>web services</i> do MediaWiki'''.\nConsulte a [//www.mediawiki.org/wiki/API:Main_page documentação da API] para informações sobre o uso da API. Exemplo: [//www.mediawiki.org/wiki/API#A_simple_example obter o conteúdo da Página Principal]. Selecione uma operação para ver mais exemplos.\n\nNote que, embora esta seja uma área de testes, as operações que executar nesta página podem modificar a wiki.",
+       "apisandbox-intro": "Use esta página para fazer experiências com a <strong>API de serviços da web do MediaWiki</strong>.\nConsulte a [[mw:API:Main page|documentação da API]] para informações sobre o uso da API. Exemplo: [//www.mediawiki.org/wiki/API#A_simple_example obter o conteúdo da Página Principal]. Selecione uma operação para ver mais exemplos.\n\nNote que, embora esta seja uma área de testes, as operações que executar nesta página podem modificar a wiki.",
        "apisandbox-fullscreen": "Expandir painel",
+       "apisandbox-fullscreen-tooltip": "Expandir o painel da página de testes para preencher a janela do navegador.",
        "apisandbox-unfullscreen": "Mostrar página",
        "apisandbox-submit": "Fazer o pedido",
        "apisandbox-reset": "Limpar",
        "apisandbox-retry": "Tentar novamente",
+       "apisandbox-loading": "A carregar a informação do módulo API \"$1\"...",
+       "apisandbox-load-error": "Ocorreu um erro ao carregar a informação do módulo API \"$1\": $2",
+       "apisandbox-no-parameters": "Este módulo API não possui parâmetros.",
+       "apisandbox-helpurls": "Ligações de ajuda",
        "apisandbox-examples": "Exemplos",
+       "apisandbox-dynamic-parameters": "Parâmetros adicionais",
        "apisandbox-dynamic-parameters-add-label": "Adicionar parâmetro:",
        "apisandbox-dynamic-parameters-add-placeholder": "Nome do parâmetro",
        "apisandbox-dynamic-error-exists": "Um parâmetro com o nome \"$1\" já existe.",
        "apisandbox-deprecated-parameters": "Parâmetros obsoletos",
+       "apisandbox-fetch-token": "Auto-preencher o token",
        "apisandbox-submit-invalid-fields-title": "Alguns campos são inválidos",
        "apisandbox-submit-invalid-fields-message": "Por favor, corrija os campos marcados e tente novamente.",
        "apisandbox-results": "Resultados",
        "showhideselectedlogentries": "Mostrar ou ocultar as entradas selecionadas",
        "log-edit-tags": "Editar etiquetas das entradas de registo selecionadas",
        "checkbox-select": "Selecionar: $1",
+       "checkbox-all": "Todas",
+       "checkbox-none": "Nenhuma",
        "checkbox-invert": "Inverter",
        "allpages": "Todas as páginas",
        "nextpage": "Página seguinte ($1)",
        "unblock": "Desbloquear utilizador",
        "blockip": "Bloquear {{GENDER:$1|utilizador|utilizadora|utilizador(a)}}",
        "blockip-legend": "Bloquear utilizador(a)",
-       "blockiptext": "Utilize o formulário abaixo para bloquear o acesso de escrita a um endereço IP específico ou a um nome de utilizador(a).\nIsto só deve ser feito para prevenir vandalismo e de acordo com a [[{{MediaWiki:Policy-url}}|política]]. Indique a seguir um motivo de bloqueio específico (por exemplo, indicando as páginas que foram alvo de vandalismo).",
+       "blockiptext": "Utilize o formulário abaixo para bloquear o acesso de escrita a um endereço IP específico ou a um nome de utilizador(a).\nIsto só deve ser feito para prevenir vandalismo e de acordo com a [[{{MediaWiki:Policy-url}}|política]]. Indique a seguir um motivo de bloqueio específico (por exemplo, indicando as páginas que foram alvo de vandalismo).\nPode bloquear intervalos de endereços IP com a sintaxe [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR]; o maior intervalo permitido é /$1 para IPv4 e /$2 para IPv6.",
        "ipaddressorusername": "Endereço de IP ou utilizador(a):",
        "ipbexpiry": "Expiração:",
        "ipbreason": "Motivo:",
        "block-log-flags-hiddenname": "nome de utilizador oculto",
        "range_block_disabled": "A funcionalidade de administrador para o bloqueio de gamas de IP está desativada.",
        "ipb_expiry_invalid": "Tempo de expiração inválido.",
+       "ipb_expiry_old": "O tempo de expiração está no passado.",
        "ipb_expiry_temp": "Bloqueios com nome de utilizador oculto devem ser permanentes.",
        "ipb_hide_invalid": "Não foi possível suprimir esta conta; ela possui mais de {{PLURAL:$1|uma edição|$1 edições}}.",
        "ipb_already_blocked": "\"$1\" já se encontra bloqueado",
        "import-interwiki-history": "Copiar todo o histórico de revisões desta página",
        "import-interwiki-templates": "Incluir todas as predefinições",
        "import-interwiki-submit": "Importar",
+       "import-mapping-default": "Importar para localizações predefinidas",
+       "import-mapping-namespace": "Importar para um domínio:",
+       "import-mapping-subpage": "Importar como sub-páginas da seguinte página:",
        "import-upload-filename": "Nome do ficheiro:",
        "import-comment": "Comentário:",
        "importtext": "Exporte o ficheiro da wiki de origem utilizando a página especial [[Special:Export|exportação de páginas]].\nGrave o ficheiro no seu computador e importe-o aqui.",
        "svg-long-error": "Ficheiro SVG inválido: $1",
        "show-big-image": "Ficheiro original",
        "show-big-image-preview": "Tamanho desta antevisão: $1.",
+       "show-big-image-preview-differ": "Tamanho desta antevisão em $3 do ficheiro $2: $1",
        "show-big-image-other": "{{PLURAL:$2|Outra resolução|Outras resoluções}}: $1.",
        "show-big-image-size": "$1 × $2 pixels",
        "file-info-gif-looped": "cíclico",
        "exif-compression-4": "CCITT Grupo 4 codificação de fax",
        "exif-copyrighted-true": "Direitos de autor reservados",
        "exif-copyrighted-false": "Situação dos direitos autorais não definida",
+       "exif-photometricinterpretation-1": "Preto e branco (Preto é 0)",
        "exif-unknowndate": "Data desconhecida",
        "exif-orientation-1": "Normal",
        "exif-orientation-2": "Espelhamento horizontal",
        "version-libraries-license": "Licença",
        "version-libraries-description": "Descrição",
        "version-libraries-authors": "Autores",
-       "redirect": "Redirecionar pelo ID do ficheiro, do utilizador ou da revisão",
+       "redirect": "Redirecionar por ficheiro, utilizador, página, revisão, ou ID de registo",
        "redirect-legend": "Redirecionar para um ficheiro ou página",
-       "redirect-summary": "Esta página especial redireciona para um ficheiro (dado o nome do ficheiro), para uma página (dado um ID de revisão ou página) ou para uma página de utilizador (dado um ID numérico do utilizador). Utilização: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]] ou [[{{#Special:Redirect}}/user/101]].",
+       "redirect-summary": "Esta página especial redireciona para um ficheiro (dado o nome do ficheiro), para uma página (dado um ID de revisão ou página) ou para uma página de utilizador (dado um ID numérico do utilizador), ou para uma entrada do registo (dado o ID do registo). Utilização: [[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]], [{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], ou [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Ir",
        "redirect-lookup": "Pesquisa:",
        "redirect-value": "Valor:",
        "redirect-page": "Identificador (ID) da página",
        "redirect-revision": "Revisão da página",
        "redirect-file": "Nome do ficheiro",
+       "redirect-logid": "ID do registo",
        "redirect-not-exists": "Valor não encontrado",
        "fileduplicatesearch": "Ficheiros duplicados",
        "fileduplicatesearch-summary": "Procure ficheiros duplicados tendo por base o seu resumo criptográfico.",
        "expand_templates_preview": "Antevisão do resultado",
        "expand_templates_preview_fail_html": "<em>Devido ao fato de {{SITENAME}} possuir código HTML puro ativado e de ter havido perda de dados da sessão, a pré-visualização ficará oculta como precaução contra ataques por JavaScript.</em>\n\n<strong>Se esta é uma legítima tentativa de visualização, por favor tente novamente.</strong>\nCaso continue a não funcionar, tente [[Special:UserLogout|sair]] e voltar a entrar na sua conta, e verifique se o seu navegador permite a utilização de ''cookies'' deste sítio.",
        "expand_templates_preview_fail_html_anon": "<em>Devido ao fato de {{SITENAME}} possuir código HTML puro ativado e de não ter sessão iniciada, a pré-visualização ficará oculta como precaução contra ataques do JavaScript.</em>\n\n<strong>Se esta é uma legítima tentativa de visualização, por favor [[Especial:UserLogin|inicie sessão]] e tente novamente.</strong>",
+       "expand_templates_input_missing": "Necessita de fornecer pelo menos algum texto de entrada.",
        "pagelanguage": "Alterar idioma da página",
        "pagelang-name": "Página",
        "pagelang-language": "Idioma",
        "mw-widgets-titleinput-description-new-page": "a página ainda não existe.",
        "mw-widgets-titleinput-description-redirect": "redirecionar para $1",
        "api-error-blacklisted": "Escolha um título diferente e descritivo, por favor.",
+       "sessionprovider-generic": "Sessões $1",
+       "sessionprovider-mediawiki-session-cookiesessionprovider": "sessões baseadas em cookie",
+       "sessionprovider-nocookies": "Os cookies podem estar desativados. Certifique-se de que os cookies estão ativados e inicie novamente.",
        "randomrootpage": "Página raiz aleatória"
 }
index c9a0c23..b388053 100644 (file)
        "exif-make": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nThe Manufacturer of the digital camera (or scanner) that took the photo.",
        "exif-model": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nThe model of camera (or scanner) used to take the picture.",
        "exif-software": "Short for \"The software which was used to create or modify this image\".\n\nThe property can come from the Exif Software tag, PNG software chunk, iptc-iim 2:65 Software field, or XMP's xmp:CreatorTool field.\n\nExif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].",
-       "exif-artist": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nThis message labels the author or artist of the work. Usually this means who took the photograph, or who drew the picture. The corresponding value field most commonly contains a single author, however it can contain an ordered (or unordered depending on which metadata standard is used to store the information) list of authors. Sometimes the persons position is prefixed before their name such as \"Photographer, John Smith\". The exif standard recommends multiple authors be specified by \"position, Author 1; position for author 2, Author 2's name\" however this doesn't seem to happen in practise very often. If multiple authors are specified using a non-exif standard, then a billeted (or numbered) list is used.\n\nThis property can be specified by exif Artist tag, XMP's tiff:Artist, XMP's dc:creator, iptc-iim's 2:80 byline, PNG's author textual chunk, PNG's (unofficial) artist textual chunk. XMP's photoshop:AuthorsPosition and iptc 2:85 byline-title can also affect display of this property.\n{{Identical|Author}}",
+       "exif-artist": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nThis message labels the author or artist of the work. Usually this means who took the photograph, or who drew the picture. The corresponding value field most commonly contains a single author, however it can contain an ordered (or unordered depending on which metadata standard is used to store the information) list of authors. Sometimes the persons position is prefixed before their name such as \"Photographer, John Smith\". The exif standard recommends multiple authors be specified by \"position, Author 1; position for author 2, Author 2's name\" however this doesn't seem to happen in practice very often. If multiple authors are specified using a non-exif standard, then a billeted (or numbered) list is used.\n\nThis property can be specified by exif Artist tag, XMP's tiff:Artist, XMP's dc:creator, iptc-iim's 2:80 byline, PNG's author textual chunk, PNG's (unofficial) artist textual chunk. XMP's photoshop:AuthorsPosition and iptc 2:85 byline-title can also affect display of this property.\n{{Identical|Author}}",
        "exif-copyright": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nLabel for information contained in exif Copyright tag, XMP dc:rights, IPTC-iim 2:116, or PNG copyright textual chunk.\n\nTypically the copyright statement for the photograph/drawing/video (such as ''(c) 2010 John Smith. Released under GFDL''). Sometimes contains license information. See also {{msg-mw|exif-copyrightowner}}",
        "exif-exifversion": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nVersion of exif standard photo uses. Typically this is 2.22",
        "exif-flashpixversion": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nVersion of flashpix used. Flashpix is a format used for storing some types of metadata in image. It is not as commonly used as EXIF, and mediawiki currently cannot read Flashpix data.",
        "exif-compressedbitsperpixel": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].",
        "exif-pixelydimension": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n{{Identical|Image width}}",
        "exif-pixelxdimension": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n{{Identical|Image height}}",
-       "exif-usercomment": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nComments by user. Sometimes used like ImageDescription when the ImageDescription contained non-ascii characters. (Technically ImageDescription is supposed to contain ascii characters. In practise utf-8 is used in ImageDescription, so this field isn't used too much.)",
+       "exif-usercomment": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nComments by user. Sometimes used like ImageDescription when the ImageDescription contained non-ascii characters. (Technically ImageDescription is supposed to contain ascii characters. In practice utf-8 is used in ImageDescription, so this field isn't used too much.)",
        "exif-relatedsoundfile": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nSome cameras offer the option to record an audio \"memo\" for the photo they just took. If the user did that, the name of the file is labelled with this message.",
        "exif-datetimeoriginal": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nThe date and time when the original image data was generated. For example if it was a painting from 1773, scanned in to a computer in 2007, the datetimeoriginal would be 1773 and {{msg-mw|exif-datetimedigitized}} would have the 2007 date.",
        "exif-datetimedigitized": "Exif is a format for storing metadata in image files. See this [[w:Exchangeable_image_file_format|Wikipedia article]] and the example at the bottom of [[commons:File:Phalacrocorax-auritus-020.jpg|this page on Commons]]. The tags are explained [http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html briefly] and [http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf in further detail].\n\nThe date and time when the image was stored as digital data.",
index 1571bc2..4274b07 100644 (file)
        "changecontentmodel-nodirectediting": "Model vsebine $1 ne podpira neposrednega urejanja",
        "log-name-contentmodel": "Dnevnik sprememb modela vsebine",
        "log-description-contentmodel": "Dogodki, povezani z modeli vsebin strani",
+       "logentry-contentmodel-new": "$1 je {{GENDER:$2|ustvaril|ustvarila|ustvaril(-a)}} stran $3 z neprivzetim modelom vsebine »$5«",
        "logentry-contentmodel-change": "$1 je {{GENDER:$2|spremenil|spremenila|spremenil(-a)}} model vsebine strani $3 z »$4« na »$5«",
        "logentry-contentmodel-change-revertlink": "vrni",
        "logentry-contentmodel-change-revert": "vrni",
index 849f526..e856378 100644 (file)
        "newarticle": "(Ny)",
        "newarticletext": "Du har klickat på en länk till en sida som inte finns ännu. För att skapa sidan, börja att skriva i fältet nedan (du kan läsa mer på [$1 hjälpsidan]). Om du kom hit av misstag kan du bara trycka på <strong>tillbaka</strong>-knappen i din webbläsare.",
        "anontalkpagetext": "----''Detta är diskussionssidan för en anonym användare som inte ännu skapat ett konto, eller som inte använder det.\nDärför måste vi använda den numeriska IP-adressen för att identifiera honom/henne.\nEn sådan IP-adress kan delas av flera användare.\nOm du är en anonym användare och känner att irrelevanta kommentarer har riktats mot dig, vänligen [[Special:UserLogin/signup|skapa ett konto]] eller [[Special:UserLogin|logga in]] för att undvika framtida förväxlingar med andra anonyma användare.''",
-       "noarticletext": "Det finns just nu ingen text på denna sida.\nDu kan [[Special:Search/{{PAGENAME}}|söka efter denna sidtitel]] på andra sidor, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} söka i relaterade loggar], eller [{{fullurl:{{FULLPAGENAME}}|action=edit}} redigera denna sida]</span>.",
+       "noarticletext": "Det finns just nu ingen text på denna sida.\nDu kan [[Special:Search/{{PAGENAME}}|söka efter denna sidtitel]] på andra sidor, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} söka i relaterade loggar], eller [{{fullurl:{{FULLPAGENAME}}|action=edit}} skapa denna sida]</span>.",
        "noarticletext-nopermission": "Det finns för tillfället ingen text på denna sida.\nDu kan [[Special:Search/{{PAGENAME}}|söka efter denna sidas titel]] på andra sidor,\neller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} söka i relaterade loggar]</span> men du har inte behörighet att skapa sidan.",
        "missing-revision": "Revisionen #$1 av sidan med namnet \"{{FULLPAGENAME}}\" finns inte.\n\nDetta orsakas vanligen av efter en gammal historiklänk till en sida som har raderats.\nDetaljer kan hittas i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} raderingsloggen].",
        "userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" är inte ett registrerat användarkonto. Tänk efter om du vill skapa/redigera den här sidan.",
        "recentchanges-label-bot": "Denna redigering gjordes av en bot",
        "recentchanges-label-unpatrolled": "Denna redigering har inte blivit patrullerad ännu",
        "recentchanges-label-plusminus": "Sidans storlek ändrades med detta antal byte",
-       "recentchanges-legend-heading": "'''Teckenförklaring:'''",
+       "recentchanges-legend-heading": "<strong>Teckenförklaring:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (se även [[Special:NewPages|listan över nya sidor]])",
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "Visa",
        "backend-fail-read": "Kunde inte läsa filen ''$1''.",
        "backend-fail-create": "Kunde inte skapa filen $1.",
        "backend-fail-maxsize": "Kunde inte skapa filen $1 eftersom den är större än {{PLURAL:$2|en byte|$2 bytes}}.",
-       "backend-fail-readonly": "Lagringssystemet \"$1\" är för närvarande skrivskyddad. Den angivna anledningen är: \"$2\"",
+       "backend-fail-readonly": "Lagringssystemet \"$1\" är för närvarande skrivskyddat. Den angivna anledningen var: <em>$2</em>",
        "backend-fail-synced": "Filen \"$1\" är i ett inkonsekvent tillstånd inom de interna lagringssystemen",
        "backend-fail-connect": "Kunde inte ansluta till lagringssystemet \"$1\".",
        "backend-fail-internal": "Ett okänt fel uppstod i lagringssystemet \"$1\".",
        "delete-toobig": "Denna sida har en lång redigeringshistorik med mer än $1 {{PLURAL:$1|sidversion|sidversioner}}. Borttagning av sådana sidor har begränsats för att förhindra oavsiktliga driftstörningar på {{SITENAME}}.",
        "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": "'''Varning:'''\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Andra sidor]] länkar till eller inkluderar sidan som du är på väg att radera.",
+       "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.",
        "rollback": "Rulla tillbaka ändringar",
        "rollbacklink": "rulla tillbaka",
        "rollbacklinkcount": "rulla tillbaka $1 {{PLURAL:$1|redigering|redigeringar}}",
        "changecontentmodel-nodirectediting": "Innehållsmodellen $1 stöder inte direkt redigering",
        "log-name-contentmodel": "Ändringslogg för innehållsmodellen",
        "log-description-contentmodel": "Händelser som är relaterade till en sidas innehållsmodeller",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|skapade}} sidan $3 med den icke-standardiserade innehållsmodellen \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|ändrade}} innehållsmodellen för sidan $3 från \"$4\" till \"$5\"",
        "logentry-contentmodel-change-revertlink": "återställ",
        "logentry-contentmodel-change-revert": "återställ",
        "tags-edit-revision-legend": "Lägg eller ta bort märken från {{PLURAL:$1|denna sidversion|alla $1 sidversioner}}",
        "tags-edit-logentry-legend": "Lägg till eller ta bort märken från {{PLURAL:$1|denna loggpost|alla $1 loggposter}}",
        "tags-edit-existing-tags": "Befintliga märken:",
-       "tags-edit-existing-tags-none": "''Inga''",
+       "tags-edit-existing-tags-none": "<em>Inga</em>",
        "tags-edit-new-tags": "Nya märken:",
        "tags-edit-add": "Lägg till dessa märken:",
        "tags-edit-remove": "Ta bort dessa märken:",
index f053661..512fb5d 100644 (file)
        "import-rootpage-invalid": "கொடுக்கப்பட்ட மூலப்பக்கம் செல்லாத தலைப்பாகும்.",
        "importlogpage": "இறக்குமதி பதிகை",
        "importlogpagetext": "வேறு விக்கிகளிலில் தொகுப்பு வரலாற்றைக் கொண்டப் பக்கங்களின் மேலாண்மை இறக்குமதிகள்.",
-       "import-logentry-upload-detail": "{{PLURAL:$1|ஒரு திருத்தம்|$1 திருத்தங்கள்}}",
-       "import-logentry-interwiki-detail": "$2 à®\87லிரà¯\81நà¯\8dதà¯\81 {{PLURAL:$1|à®\92à®°à¯\81 à®¤à®¿à®°à¯\81தà¯\8dதமà¯\8d|$1 à®¤à®¿à®°à¯\81தà¯\8dதà®\99à¯\8dà®\95ளà¯\8d}}",
+       "import-logentry-upload-detail": "$1 {{PLURAL:$1|திருத்தம்|திருத்தங்கள்}} இறக்குமதி செய்யப்பட்டன",
+       "import-logentry-interwiki-detail": "$2 à®\87லிரà¯\81நà¯\8dதà¯\81 {{PLURAL:$1|திரà¯\81தà¯\8dதமà¯\8d|திரà¯\81தà¯\8dதà®\99à¯\8dà®\95ளà¯\8d}} à®\87à®±à®\95à¯\8dà®\95à¯\81மதி à®\9aà¯\86யà¯\8dயபà¯\8dபà®\9fà¯\8dà®\9fன",
        "javascripttest": "சாவாநிரல் சோதனை நடக்கின்றது",
        "javascripttest-pagetext-noframework": "இந்த பக்கம் JavaScript பரிசோதனை ஓட்டத்திற்காக ஒதுக்கப்பட்டுள்ளது",
        "javascripttest-pagetext-unknownframework": "அறியப்படாத சோதனை பணிச்சட்டம் \"$1\".",
        "special-characters-group-thai": "தாய்",
        "special-characters-group-lao": "இலாவோ",
        "special-characters-group-khmer": "கெமெர்",
+       "special-characters-title-endash": "சிறு கோடு",
+       "special-characters-title-emdash": "பெரு கோடு",
        "special-characters-title-minus": "கழித்தல் குறி",
        "mw-widgets-dateinput-no-date": "திகதி தெரிவுச் செய்யப்படவில்லை",
        "mw-widgets-titleinput-description-new-page": "இப்பக்கம் இன்னும் உருவாக்கப்படவில்லை",
index bfe89bd..e5f2d1d 100644 (file)
        "rcshowhidemine": "Benim değişikliklerimi $1",
        "rcshowhidemine-show": "göster",
        "rcshowhidemine-hide": "gizle",
-       "rcshowhidecategorization": "$1 Sayfa kategorizasyonu",
+       "rcshowhidecategorization": "$1 sayfa kategorizasyonu",
        "rcshowhidecategorization-show": "Göster",
        "rcshowhidecategorization-hide": "Gizle",
        "rclinks": "Son $2 günde yapılan son $1 değişikliği göster;<br /> $3",
        "wlshowhideanons": "anonim kullanıcılar",
        "wlshowhidepatr": "incelenmiş değişiklikler",
        "wlshowhidemine": "değişikliklerim",
+       "wlshowhidecategorization": "sayfa kategorizasyonu",
        "watchlist-options": "İzleme listesi seçenekleri",
        "watching": "İzleniyor...",
        "unwatching": "İzlenmiyor...",
index f36eb07..2d33eb1 100644 (file)
        "changecontentmodel-nodirectediting": "Модель вмісту $1 не підтримує пряме редагування",
        "log-name-contentmodel": "Журнал змін моделі вмісту",
        "log-description-contentmodel": "Події, пов'язані з моделями вмісту сторінки",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|створив|створила}} сторінку $3, використовуючи нестандартну модель вмісту «$5»",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|змінив|змінила}} модель вмісту сторінки $3 з «$4» на «$5»",
        "logentry-contentmodel-change-revertlink": "відкинути",
        "logentry-contentmodel-change-revert": "відкинути",
index c6452fb..d30a348 100644 (file)
--- a/load.php
+++ b/load.php
 
 use MediaWiki\Logger\LoggerFactory;
 
+// This endpoint is supposed to be independent of request cookies and other
+// details of the session. Log warnings for violations of the no-session
+// constraint.
+define( 'MW_NO_SESSION', 'warn' );
+
 require __DIR__ . '/includes/WebStart.php';
 
 // URL safety checks
index 8651a68..5fab082 100644 (file)
@@ -87,7 +87,7 @@ abstract class Benchmarker extends Maintenance {
                        $ret .= sprintf( "%s times: function %s(%s) :\n",
                                $res['count'],
                                $res['function'],
-                               join( ', ', $res['arguments'] )
+                               implode( ', ', $res['arguments'] )
                        );
                        $ret .= sprintf( "   %6.2fms (%6.2fms each)\n",
                                $res['delta'] * 1000,
index 6bc9a6a..3c679e6 100644 (file)
@@ -53,7 +53,7 @@ class GetConfiguration extends Maintenance {
                $this->addOption( 'regex', 'regex to filter variables with', false, true );
                $this->addOption( 'iregex', 'same as --regex but case insensitive', false, true );
                $this->addOption( 'settings', 'Space-separated list of wg* variables', false, true );
-               $this->addOption( 'format', join( ', ', self::$outFormats ), false, true );
+               $this->addOption( 'format', implode( ', ', self::$outFormats ), false, true );
        }
 
        protected function validateParamsAndArgs() {
index 7e62b89..b2530ce 100644 (file)
@@ -63,6 +63,9 @@ class InitSiteStats extends Maintenance {
                        $this->output( "\nUpdating site statistics..." );
                        $counter->refresh();
                        $this->output( "done.\n" );
+               } else {
+                       $this->output( "\nTo update the site statistics table, run the script "
+                               . "with the --update option.\n" );
                }
 
                if ( $this->hasOption( 'active' ) ) {
index 29322f4..a756f22 100644 (file)
 
                // Check if all of the form values are unchanged
                function isPrefsChanged() {
-                       var inputs = $( '#mw-prefs-form :input' ),
+                       var inputs = $( '#mw-prefs-form :input[name]' ),
                                input, $input, inputType,
                                index, optIndex,
                                opt;
                                $input = $( input );
 
                                // Different types of inputs have different methods for accessing defaults
-                               if ( $input.is( 'select' ) ) { // <select> has the property defaultSelected for each option
+                               if ( $input.is( 'select' ) ) {
+                                       // <select> has the property defaultSelected for each option
                                        for ( optIndex = 0; optIndex < input.options.length; optIndex++ ) {
                                                opt = input.options[ optIndex ];
                                                if ( opt.selected !== opt.defaultSelected ) {
diff --git a/tests/phpunit/includes/WatchedItemIntegrationTest.php b/tests/phpunit/includes/WatchedItemIntegrationTest.php
new file mode 100644 (file)
index 0000000..20fcedb
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Database
+ *
+ * @covers WatchedItem
+ */
+class WatchedItemIntegrationTest extends MediaWikiTestCase {
+
+       public function setUp() {
+               parent::setUp();
+               self::$users['WatchedItemIntegrationTestUser']
+                       = new TestUser( 'WatchedItemIntegrationTestUser' );
+       }
+
+       private function getUser() {
+               return self::$users['WatchedItemIntegrationTestUser']->getUser();
+       }
+
+       public function testWatchAndUnWatchItem() {
+               $user = $this->getUser();
+               $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
+               // Cleanup after previous tests
+               WatchedItem::fromUserTitle( $user, $title )->removeWatch();
+
+               $this->assertFalse(
+                       WatchedItem::fromUserTitle( $user, $title )->isWatched(),
+                       'Page should not initially be watched'
+               );
+               WatchedItem::fromUserTitle( $user, $title )->addWatch();
+               $this->assertTrue(
+                       WatchedItem::fromUserTitle( $user, $title )->isWatched(),
+                       'Page should be watched'
+               );
+               WatchedItem::fromUserTitle( $user, $title )->removeWatch();
+               $this->assertFalse(
+                       WatchedItem::fromUserTitle( $user, $title )->isWatched(),
+                       'Page should be unwatched'
+               );
+       }
+
+       public function testUpdateAndResetNotificationTimestamp() {
+               $user = $this->getUser();
+               $otherUser = ( new TestUser( 'WatchedItemIntegrationTestUser_otherUser' ) )->getUser();
+               $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
+               WatchedItem::fromUserTitle( $user, $title )->addWatch();
+               $this->assertNull( WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp() );
+
+               EmailNotification::updateWatchlistTimestamp( $otherUser, $title, '20150202010101' );
+               $this->assertEquals(
+                       '20150202010101',
+                       WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp()
+               );
+
+               WatchedItem::fromUserTitle( $user, $title )->resetNotificationTimestamp();
+               $this->assertNull( WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp() );
+       }
+
+       public function testDuplicateAllAssociatedEntries() {
+               $user = $this->getUser();
+               $titleOld = Title::newFromText( 'WatchedItemIntegrationTestPageOld' );
+               $titleNew = Title::newFromText( 'WatchedItemIntegrationTestPageNew' );
+               WatchedItem::fromUserTitle( $user, $titleOld->getSubjectPage() )->addWatch();
+               WatchedItem::fromUserTitle( $user, $titleOld->getTalkPage() )->addWatch();
+               // Cleanup after previous tests
+               WatchedItem::fromUserTitle( $user, $titleNew->getSubjectPage() )->removeWatch();
+               WatchedItem::fromUserTitle( $user, $titleNew->getTalkPage() )->removeWatch();
+
+               WatchedItem::duplicateEntries( $titleOld, $titleNew );
+
+               $this->assertTrue(
+                       WatchedItem::fromUserTitle( $user, $titleOld->getSubjectPage() )->isWatched()
+               );
+               $this->assertTrue(
+                       WatchedItem::fromUserTitle( $user, $titleOld->getTalkPage() )->isWatched()
+               );
+               $this->assertTrue(
+                       WatchedItem::fromUserTitle( $user, $titleNew->getSubjectPage() )->isWatched()
+               );
+               $this->assertTrue(
+                       WatchedItem::fromUserTitle( $user, $titleNew->getTalkPage() )->isWatched()
+               );
+       }
+
+       public function testIsWatched_falseOnNotAllowed() {
+               $user = $this->getUser();
+               $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
+               WatchedItem::fromUserTitle( $user, $title )->addWatch();
+
+               $this->assertTrue( WatchedItem::fromUserTitle( $user, $title )->isWatched() );
+               $user->mRights = [];
+               $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->isWatched() );
+       }
+
+       public function testGetNotificationTimestamp_falseOnNotAllowed() {
+               $user = $this->getUser();
+               $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
+               WatchedItem::fromUserTitle( $user, $title )->addWatch();
+               WatchedItem::fromUserTitle( $user, $title )->resetNotificationTimestamp();
+
+               $this->assertEquals(
+                       null,
+                       WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp()
+               );
+               $user->mRights = [];
+               $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->isWatched() );
+       }
+
+       public function testRemoveWatch_falseOnNotAllowed() {
+               $user = $this->getUser();
+               $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
+               WatchedItem::fromUserTitle( $user, $title )->addWatch();
+
+               $previousRights = $user->mRights;
+               $user->mRights = [];
+               $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->removeWatch() );
+               $user->mRights = $previousRights;
+               $this->assertTrue( WatchedItem::fromUserTitle( $user, $title )->removeWatch() );
+       }
+
+}
diff --git a/tests/phpunit/includes/WatchedItemStoreIntegrationTest.php b/tests/phpunit/includes/WatchedItemStoreIntegrationTest.php
new file mode 100644 (file)
index 0000000..9341fb8
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Database
+ *
+ * @covers WatchedItemStore
+ */
+class WatchedItemStoreIntegrationTest extends MediaWikiTestCase {
+
+       public function setUp() {
+               parent::setUp();
+               self::$users['WatchedItemStoreIntegrationTestUser']
+                       = new TestUser( 'WatchedItemStoreIntegrationTestUser' );
+       }
+
+       private function getUser() {
+               return self::$users['WatchedItemStoreIntegrationTestUser']->getUser();
+       }
+
+       public function testWatchAndUnWatchItem() {
+               $user = $this->getUser();
+               $title = Title::newFromText( 'WatchedItemStoreIntegrationTestPage' );
+               $store = WatchedItemStore::getDefaultInstance();
+               // Cleanup after previous tests
+               $store->removeWatch( $user, $title );
+
+               $this->assertFalse(
+                       $store->isWatched( $user, $title ),
+                       'Page should not initially be watched'
+               );
+               $store->addWatch( $user, $title );
+               $this->assertTrue(
+                       $store->isWatched( $user, $title ),
+                       'Page should be watched'
+               );
+               $store->removeWatch( $user, $title );
+               $this->assertFalse(
+                       $store->isWatched( $user, $title ),
+                       'Page should be unwatched'
+               );
+       }
+
+       public function testUpdateAndResetNotificationTimestamp() {
+               $user = $this->getUser();
+               $otherUser = ( new TestUser( 'WatchedItemStoreIntegrationTestUser_otherUser' ) )->getUser();
+               $title = Title::newFromText( 'WatchedItemStoreIntegrationTestPage' );
+               $store = WatchedItemStore::getDefaultInstance();
+               $store->addWatch( $user, $title );
+               $this->assertNull( $store->loadWatchedItem( $user, $title )->getNotificationTimestamp() );
+
+               $store->updateNotificationTimestamp( $otherUser, $title, '20150202010101' );
+               $this->assertEquals(
+                       '20150202010101',
+                       $store->loadWatchedItem( $user, $title )->getNotificationTimestamp()
+               );
+
+               $this->assertTrue( $store->resetNotificationTimestamp( $user, $title ) );
+               $this->assertNull( $store->loadWatchedItem( $user, $title )->getNotificationTimestamp() );
+       }
+
+       public function testDuplicateAllAssociatedEntries() {
+               $user = $this->getUser();
+               $titleOld = Title::newFromText( 'WatchedItemStoreIntegrationTestPageOld' );
+               $titleNew = Title::newFromText( 'WatchedItemStoreIntegrationTestPageNew' );
+               $store = WatchedItemStore::getDefaultInstance();
+               $store->addWatch( $user, $titleOld->getSubjectPage() );
+               $store->addWatch( $user, $titleOld->getTalkPage() );
+               // Cleanup after previous tests
+               $store->removeWatch( $user, $titleNew->getSubjectPage() );
+               $store->removeWatch( $user, $titleNew->getTalkPage() );
+
+               $store->duplicateAllAssociatedEntries( $titleOld, $titleNew );
+
+               $this->assertTrue( $store->isWatched( $user, $titleOld->getSubjectPage() ) );
+               $this->assertTrue( $store->isWatched( $user, $titleOld->getTalkPage() ) );
+               $this->assertTrue( $store->isWatched( $user, $titleNew->getSubjectPage() ) );
+               $this->assertTrue( $store->isWatched( $user, $titleNew->getTalkPage() ) );
+       }
+
+}
diff --git a/tests/phpunit/includes/WatchedItemStoreTest.php b/tests/phpunit/includes/WatchedItemStoreTest.php
deleted file mode 100644 (file)
index fc132b0..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-/**
- * @author Addshore
- *
- * @covers WatchedItemStore
- */
-class WatchedItemStoreTest extends PHPUnit_Framework_TestCase {
-
-       /**
-        * @return PHPUnit_Framework_MockObject_MockObject|IDatabase
-        */
-       private function getMockDb() {
-               return $this->getMock( 'IDatabase' );
-       }
-
-       /**
-        * @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
-        */
-       private function getMockLoadBalancer( $mockDb ) {
-               $mock = $this->getMockBuilder( 'LoadBalancer' )
-                       ->disableOriginalConstructor()
-                       ->getMock();
-               $mock->expects( $this->any() )
-                       ->method( 'getConnection' )
-                       ->will( $this->returnValue( $mockDb ) );
-               return $mock;
-       }
-
-       private function getFakeRow( $userId, $timestamp ) {
-               $fakeRow = new stdClass();
-               $fakeRow->wl_user = $userId;
-               $fakeRow->wl_notificationtimestamp = $timestamp;
-               return $fakeRow;
-       }
-
-       public function testDuplicateEntry_nothingToDuplicate() {
-               $mockDb = $this->getMockDb();
-               $mockDb->expects( $this->exactly( 1 ) )
-                       ->method( 'select' )
-                       ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
-
-               $store = new WatchedItemStore( $this->getMockLoadBalancer( $mockDb ) );
-
-               $store->duplicateEntry(
-                       Title::newFromText( 'Old_Title' ),
-                       Title::newFromText( 'New_Title' )
-               );
-       }
-
-       public function testDuplicateEntry_somethingToDuplicate() {
-               $fakeRows = [
-                       $this->getFakeRow( 1, '20151212010101' ),
-                       $this->getFakeRow( 2, null ),
-               ];
-
-               $mockDb = $this->getMockDb();
-               $mockDb->expects( $this->at( 0 ) )
-                       ->method( 'select' )
-                       ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
-               $mockDb->expects( $this->at( 1 ) )
-                       ->method( 'replace' )
-                       ->with(
-                               'watchlist',
-                               [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
-                               [
-                                       [
-                                               'wl_user' => 1,
-                                               'wl_namespace' => 0,
-                                               'wl_title' => 'New_Title',
-                                               'wl_notificationtimestamp' => '20151212010101',
-                                       ],
-                                       [
-                                               'wl_user' => 2,
-                                               'wl_namespace' => 0,
-                                               'wl_title' => 'New_Title',
-                                               'wl_notificationtimestamp' => null,
-                                       ],
-                               ],
-                               $this->isType( 'string' )
-                       );
-
-               $store = new WatchedItemStore( $this->getMockLoadBalancer( $mockDb ) );
-
-               $store->duplicateEntry(
-                       Title::newFromText( 'Old_Title' ),
-                       Title::newFromText( 'New_Title' )
-               );
-       }
-
-}
diff --git a/tests/phpunit/includes/WatchedItemStoreUnitTest.php b/tests/phpunit/includes/WatchedItemStoreUnitTest.php
new file mode 100644 (file)
index 0000000..709b4b4
--- /dev/null
@@ -0,0 +1,1236 @@
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @covers WatchedItemStore
+ */
+class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
+
+       /**
+        * @return PHPUnit_Framework_MockObject_MockObject|IDatabase
+        */
+       private function getMockDb() {
+               return $this->getMock( IDatabase::class );
+       }
+
+       /**
+        * @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
+        */
+       private function getMockLoadBalancer( $mockDb ) {
+               $mock = $this->getMockBuilder( LoadBalancer::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $mock->expects( $this->any() )
+                       ->method( 'getConnection' )
+                       ->will( $this->returnValue( $mockDb ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getReadOnlyReason' )
+                       ->will( $this->returnValue( false ) );
+               return $mock;
+       }
+
+       /**
+        * @return PHPUnit_Framework_MockObject_MockObject|BagOStuff
+        */
+       private function getMockCache() {
+               $mock = $this->getMockBuilder( BagOStuff::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $mock->expects( $this->any() )
+                       ->method( 'makeKey' )
+                       ->will( $this->returnCallback( function() {
+                               return implode( ':', func_get_args() );
+                       } ) );
+               return $mock;
+       }
+
+       /**
+        * @param int $id
+        * @return PHPUnit_Framework_MockObject_MockObject|User
+        */
+       private function getMockNonAnonUserWithId( $id ) {
+               $mock = $this->getMock( User::class );
+               $mock->expects( $this->any() )
+                       ->method( 'isAnon' )
+                       ->will( $this->returnValue( false ) );
+               $mock->expects( $this->any() )
+                       ->method( 'getId' )
+                       ->will( $this->returnValue( $id ) );
+               return $mock;
+       }
+
+       /**
+        * @return User
+        */
+       private function getAnonUser() {
+               return User::newFromName( 'Anon_User' );
+       }
+
+       private function getFakeRow( array $rowValues ) {
+               $fakeRow = new stdClass();
+               foreach ( $rowValues as $valueName => $value ) {
+                       $fakeRow->$valueName = $value;
+               }
+               return $fakeRow;
+       }
+
+       public function testGetDefaultInstance() {
+               $instanceOne = WatchedItemStore::getDefaultInstance();
+               $instanceTwo = WatchedItemStore::getDefaultInstance();
+               $this->assertSame( $instanceOne, $instanceTwo );
+       }
+
+       public function testDuplicateEntry_nothingToDuplicate() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user',
+                                       'wl_notificationtimestamp',
+                               ],
+                               [
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'Old_Title',
+                               ],
+                               'WatchedItemStore::duplicateEntry',
+                               [ 'FOR UPDATE' ]
+                       )
+                       ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+               );
+
+               $store->duplicateEntry(
+                       Title::newFromText( 'Old_Title' ),
+                       Title::newFromText( 'New_Title' )
+               );
+       }
+
+       public function testDuplicateEntry_somethingToDuplicate() {
+               $fakeRows = [
+                       $this->getFakeRow( [ 'wl_user' => 1, 'wl_notificationtimestamp' => '20151212010101' ] ),
+                       $this->getFakeRow( [ 'wl_user' => 2, 'wl_notificationtimestamp' => null ] ),
+               ];
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->at( 0 ) )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user',
+                                       'wl_notificationtimestamp',
+                               ],
+                               [
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'Old_Title',
+                               ]
+                       )
+                       ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
+               $mockDb->expects( $this->at( 1 ) )
+                       ->method( 'replace' )
+                       ->with(
+                               'watchlist',
+                               [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
+                               [
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 0,
+                                               'wl_title' => 'New_Title',
+                                               'wl_notificationtimestamp' => '20151212010101',
+                                       ],
+                                       [
+                                               'wl_user' => 2,
+                                               'wl_namespace' => 0,
+                                               'wl_title' => 'New_Title',
+                                               'wl_notificationtimestamp' => null,
+                                       ],
+                               ],
+                               $this->isType( 'string' )
+                       );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+               );
+
+               $store->duplicateEntry(
+                       Title::newFromText( 'Old_Title' ),
+                       Title::newFromText( 'New_Title' )
+               );
+       }
+
+       public function testDuplicateAllAssociatedEntries_nothingToDuplicate() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->at( 0 ) )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user',
+                                       'wl_notificationtimestamp',
+                               ],
+                               [
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'Old_Title',
+                               ]
+                       )
+                       ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
+               $mockDb->expects( $this->at( 1 ) )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user',
+                                       'wl_notificationtimestamp',
+                               ],
+                               [
+                                       'wl_namespace' => 1,
+                                       'wl_title' => 'Old_Title',
+                               ]
+                       )
+                       ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+               );
+
+               $store->duplicateAllAssociatedEntries(
+                       Title::newFromText( 'Old_Title' ),
+                       Title::newFromText( 'New_Title' )
+               );
+       }
+
+       public function testDuplicateAllAssociatedEntries_somethingToDuplicate() {
+               $fakeRows = [
+                       $this->getFakeRow( [ 'wl_user' => 1, 'wl_notificationtimestamp' => '20151212010101' ] ),
+               ];
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->at( 0 ) )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user',
+                                       'wl_notificationtimestamp',
+                               ],
+                               [
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'Old_Title',
+                               ]
+                       )
+                       ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
+               $mockDb->expects( $this->at( 1 ) )
+                       ->method( 'replace' )
+                       ->with(
+                               'watchlist',
+                               [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
+                               [
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 0,
+                                               'wl_title' => 'New_Title',
+                                               'wl_notificationtimestamp' => '20151212010101',
+                                       ],
+                               ],
+                               $this->isType( 'string' )
+                       );
+               $mockDb->expects( $this->at( 2 ) )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user',
+                                       'wl_notificationtimestamp',
+                               ],
+                               [
+                                       'wl_namespace' => 1,
+                                       'wl_title' => 'Old_Title',
+                               ]
+                       )
+                       ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
+               $mockDb->expects( $this->at( 3 ) )
+                       ->method( 'replace' )
+                       ->with(
+                               'watchlist',
+                               [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
+                               [
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 1,
+                                               'wl_title' => 'New_Title',
+                                               'wl_notificationtimestamp' => '20151212010101',
+                                       ],
+                               ],
+                               $this->isType( 'string' )
+                       );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+               );
+
+               $store->duplicateAllAssociatedEntries(
+                       Title::newFromText( 'Old_Title' ),
+                       Title::newFromText( 'New_Title' )
+               );
+       }
+
+       public function testAddWatch_nonAnonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'insert' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 0,
+                                               'wl_title' => 'Some_Page',
+                                               'wl_notificationtimestamp' => null,
+                                       ]
+                               ]
+                       );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with( '0:Some_Page:1' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $store->addWatch(
+                       $this->getMockNonAnonUserWithId( 1 ),
+                       Title::newFromText( 'Some_Page' )
+               );
+       }
+
+       public function testAddWatch_anonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'insert' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $store->addWatch(
+                       $this->getAnonUser(),
+                       Title::newFromText( 'Some_Page' )
+               );
+       }
+
+       public function testAddWatchBatch_nonAnonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'insert' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 0,
+                                               'wl_title' => 'Some_Page',
+                                               'wl_notificationtimestamp' => null,
+                                       ],
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 1,
+                                               'wl_title' => 'Some_Page',
+                                               'wl_notificationtimestamp' => null,
+                                       ]
+                               ]
+                       );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->exactly( 2 ) )
+                       ->method( 'delete' );
+               $mockCache->expects( $this->at( 1 ) )
+                       ->method( 'delete' )
+                       ->with( '0:Some_Page:1' );
+               $mockCache->expects( $this->at( 3 ) )
+                       ->method( 'delete' )
+                       ->with( '1:Some_Page:1' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $mockUser = $this->getMockNonAnonUserWithId( 1 );
+
+               $this->assertTrue(
+                       $store->addWatchBatch(
+                               [
+                                       [ $mockUser, new TitleValue( 0, 'Some_Page' ) ],
+                                       [ $mockUser, new TitleValue( 1, 'Some_Page' ) ],
+                               ]
+                       )
+               );
+       }
+
+       public function testAddWatchBatch_anonymousUserCombinationsAreSkipped() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'insert' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       [
+                                               'wl_user' => 1,
+                                               'wl_namespace' => 0,
+                                               'wl_title' => 'Some_Page',
+                                               'wl_notificationtimestamp' => null,
+                                       ]
+                               ]
+                       );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with( '0:Some_Page:1' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertTrue(
+                       $store->addWatchBatch(
+                               [
+                                       [ $this->getMockNonAnonUserWithId( 1 ), new TitleValue( 0, 'Some_Page' ) ],
+                                       [ $this->getAnonUser(), new TitleValue( 0, 'Other_Page' ) ],
+                               ]
+                       )
+               );
+       }
+
+       public function testAddWatchBatchReturnsFalse_whenOnlyGivenAnonymousUserCombinations() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'insert' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $anonUser = $this->getAnonUser();
+               $this->assertFalse(
+                       $store->addWatchBatch(
+                               [
+                                       [ $anonUser, new TitleValue( 0, 'Some_Page' ) ],
+                                       [ $anonUser, new TitleValue( 1, 'Other_Page' ) ],
+                               ]
+                       )
+               );
+       }
+
+       public function testAddWatchBatchReturnsFalse_whenGivenEmptyList() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'insert' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->addWatchBatch( [] )
+               );
+       }
+
+       public function testLoadWatchedItem_existingItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue(
+                               $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
+                       ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'set' )
+                       ->with(
+                               '0:SomeDbKey:1'
+                       );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $watchedItem = $store->loadWatchedItem(
+                       $this->getMockNonAnonUserWithId( 1 ),
+                       new TitleValue( 0, 'SomeDbKey' )
+               );
+               $this->assertInstanceOf( 'WatchedItem', $watchedItem );
+               $this->assertEquals( 1, $watchedItem->getUser()->getId() );
+               $this->assertEquals( 'SomeDbKey', $watchedItem->getLinkTarget()->getDBkey() );
+               $this->assertEquals( 0, $watchedItem->getLinkTarget()->getNamespace() );
+       }
+
+       public function testLoadWatchedItem_noItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue( [] ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->loadWatchedItem(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testLoadWatchedItem_anonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->loadWatchedItem(
+                               $this->getAnonUser(),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testRemoveWatch_existingItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       );
+               $mockDb->expects( $this->once() )
+                       ->method( 'affectedRows' )
+                       ->will( $this->returnValue( 1 ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with( '0:SomeDbKey:1' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertTrue(
+                       $store->removeWatch(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testRemoveWatch_noItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with(
+                               'watchlist',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       );
+               $mockDb->expects( $this->once() )
+                       ->method( 'affectedRows' )
+                       ->will( $this->returnValue( 0 ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with( '0:SomeDbKey:1' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->removeWatch(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testRemoveWatch_anonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->removeWatch(
+                               $this->getAnonUser(),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testGetWatchedItem_existingItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue(
+                               $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
+                       ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'get' )
+                       ->with(
+                               '0:SomeDbKey:1'
+                       )
+                       ->will( $this->returnValue( null ) );
+               $mockCache->expects( $this->once() )
+                       ->method( 'set' )
+                       ->with(
+                               '0:SomeDbKey:1'
+                       );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $watchedItem = $store->getWatchedItem(
+                       $this->getMockNonAnonUserWithId( 1 ),
+                       new TitleValue( 0, 'SomeDbKey' )
+               );
+               $this->assertInstanceOf( 'WatchedItem', $watchedItem );
+               $this->assertEquals( 1, $watchedItem->getUser()->getId() );
+               $this->assertEquals( 'SomeDbKey', $watchedItem->getLinkTarget()->getDBkey() );
+               $this->assertEquals( 0, $watchedItem->getLinkTarget()->getNamespace() );
+       }
+
+       public function testGetWatchedItem_cachedItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockUser = $this->getMockNonAnonUserWithId( 1 );
+               $linkTarget = new TitleValue( 0, 'SomeDbKey' );
+               $cachedItem = new WatchedItem( $mockUser, $linkTarget, '20151212010101' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'get' )
+                       ->with(
+                               '0:SomeDbKey:1'
+                       )
+                       ->will( $this->returnValue( $cachedItem ) );
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertEquals(
+                       $cachedItem,
+                       $store->getWatchedItem(
+                               $mockUser,
+                               $linkTarget
+                       )
+               );
+       }
+
+       public function testGetWatchedItem_noItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue( [] ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->getWatchedItem(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testGetWatchedItem_anonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->getWatchedItem(
+                               $this->getAnonUser(),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testIsWatchedItem_existingItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue(
+                               $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
+                       ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'set' )
+                       ->with(
+                               '0:SomeDbKey:1'
+                       );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertTrue(
+                       $store->isWatched(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testIsWatchedItem_noItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue( [] ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->isWatched(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testIsWatchedItem_anonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->isWatched(
+                               $this->getAnonUser(),
+                               new TitleValue( 0, 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testResetNotificationTimestamp_anonymousUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->resetNotificationTimestamp(
+                               $this->getAnonUser(),
+                               Title::newFromText( 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testResetNotificationTimestamp_noItem() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue( [] ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )
+                       ->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertFalse(
+                       $store->resetNotificationTimestamp(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               Title::newFromText( 'SomeDbKey' )
+                       )
+               );
+       }
+
+       public function testResetNotificationTimestamp_item() {
+               $user = $this->getMockNonAnonUserWithId( 1 );
+               $title = Title::newFromText( 'SomeDbKey' );
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue(
+                               $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
+                       ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'set' )
+                       ->with(
+                               '0:SomeDbKey:1',
+                               $this->isInstanceOf( WatchedItem::class )
+                       );
+               $mockCache->expects( $this->once() )
+                       ->method( 'delete' )
+                       ->with( '0:SomeDbKey:1' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               // Note: This does not actually assert the job is correct
+               $callableCallCounter = 0;
+               $mockCallback = function( $callable ) use ( &$callableCallCounter ) {
+                       $callableCallCounter++;
+                       $this->assertInternalType( 'callable', $callable );
+               };
+               $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
+
+               $this->assertTrue(
+                       $store->resetNotificationTimestamp(
+                               $user,
+                               $title
+                       )
+               );
+               $this->assertEquals( 1, $callableCallCounter );
+       }
+
+       public function testResetNotificationTimestamp_noItemForced() {
+               $user = $this->getMockNonAnonUserWithId( 1 );
+               $title = Title::newFromText( 'SomeDbKey' );
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockCache = $this->getMockCache();
+               $mockDb->expects( $this->never() )
+                       ->method( 'set' );
+               $mockDb->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               // Note: This does not actually assert the job is correct
+               $callableCallCounter = 0;
+               $mockCallback = function( $callable ) use ( &$callableCallCounter ) {
+                       $callableCallCounter++;
+                       $this->assertInternalType( 'callable', $callable );
+               };
+               $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
+
+               $this->assertTrue(
+                       $store->resetNotificationTimestamp(
+                               $user,
+                               $title,
+                               'force'
+                       )
+               );
+               $this->assertEquals( 1, $callableCallCounter );
+       }
+
+       /**
+        * @param $text
+        * @param int $ns
+        *
+        * @return PHPUnit_Framework_MockObject_MockObject|Title
+        */
+       private function getMockTitle( $text, $ns = 0 ) {
+               $title = $this->getMock( Title::class );
+               $title->expects( $this->any() )
+                       ->method( 'getText' )
+                       ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) );
+               $title->expects( $this->any() )
+                       ->method( 'getDbKey' )
+                       ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) );
+               $title->expects( $this->any() )
+                       ->method( 'getNamespace' )
+                       ->will( $this->returnValue( $ns ) );
+               return $title;
+       }
+
+       public function testResetNotificationTimestamp_oldidSpecifiedLatestRevisionForced() {
+               $user = $this->getMockNonAnonUserWithId( 1 );
+               $oldid = 22;
+               $title = $this->getMockTitle( 'SomeTitle' );
+               $title->expects( $this->once() )
+                       ->method( 'getNextRevisionID' )
+                       ->with( $oldid )
+                       ->will( $this->returnValue( false ) );
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )
+                       ->method( 'selectRow' );
+
+               $mockCache = $this->getMockCache();
+               $mockDb->expects( $this->never() )
+                       ->method( 'set' );
+               $mockDb->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               // Note: This does not actually assert the job is correct
+               $callableCallCounter = 0;
+               $store->overrideDeferredUpdatesAddCallableUpdateCallback(
+                       function( $callable ) use ( &$callableCallCounter ) {
+                               $callableCallCounter++;
+                               $this->assertInternalType( 'callable', $callable );
+                       }
+               );
+
+               $this->assertTrue(
+                       $store->resetNotificationTimestamp(
+                               $user,
+                               $title,
+                               'force',
+                               $oldid
+                       )
+               );
+               $this->assertEquals( 1, $callableCallCounter );
+       }
+
+       public function testResetNotificationTimestamp_oldidSpecifiedNotLatestRevisionForced() {
+               $user = $this->getMockNonAnonUserWithId( 1 );
+               $oldid = 22;
+               $title = $this->getMockTitle( 'SomeDbKey' );
+               $title->expects( $this->once() )
+                       ->method( 'getNextRevisionID' )
+                       ->with( $oldid )
+                       ->will( $this->returnValue( 33 ) );
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'selectRow' )
+                       ->with(
+                               'watchlist',
+                               'wl_notificationtimestamp',
+                               [
+                                       'wl_user' => 1,
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       )
+                       ->will( $this->returnValue(
+                               $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
+                       ) );
+
+               $mockCache = $this->getMockCache();
+               $mockDb->expects( $this->never() )
+                       ->method( 'set' );
+               $mockDb->expects( $this->never() )
+                       ->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               // Note: This does not actually assert the job is correct
+               $addUpdateCallCounter = 0;
+               $store->overrideDeferredUpdatesAddCallableUpdateCallback(
+                       function( $callable ) use ( &$addUpdateCallCounter ) {
+                               $addUpdateCallCounter++;
+                               $this->assertInternalType( 'callable', $callable );
+                       }
+               );
+
+               $getTimestampCallCounter = 0;
+               $store->overrideRevisionGetTimestampFromIdCallback(
+                       function( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) {
+                               $getTimestampCallCounter++;
+                               $this->assertEquals( $title, $titleParam );
+                               $this->assertEquals( $oldid, $oldidParam );
+                       }
+               );
+
+               $this->assertTrue(
+                       $store->resetNotificationTimestamp(
+                               $user,
+                               $title,
+                               'force',
+                               $oldid
+                       )
+               );
+               $this->assertEquals( 1, $addUpdateCallCounter );
+               $this->assertEquals( 1, $getTimestampCallCounter );
+       }
+
+       public function testUpdateNotificationTimestamp_watchersExist() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               [ 'watchlist' ],
+                               [ 'wl_user' ],
+                               [
+                                       'wl_user != 1',
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                                       'wl_notificationtimestamp IS NULL'
+                               ]
+                       )
+                       ->will(
+                               $this->returnValue( [
+                                       $this->getFakeRow( [ 'wl_user' => '2' ] ),
+                                       $this->getFakeRow( [ 'wl_user' => '3' ] )
+                               ] )
+                       );
+               $mockDb->expects( $this->once() )
+                       ->method( 'onTransactionIdle' )
+                       ->with( $this->isType( 'callable' ) )
+                       ->will( $this->returnCallback( function( $callable ) {
+                               $callable();
+                       } ) );
+               $mockDb->expects( $this->once() )
+                       ->method( 'update' )
+                       ->with(
+                               'watchlist',
+                               [ 'wl_notificationtimestamp' => null ],
+                               [
+                                       'wl_user' => [ 2, 3 ],
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                               ]
+                       );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+               );
+
+               $this->assertEquals(
+                       [ 2, 3 ],
+                       $store->updateNotificationTimestamp(
+                               $this->getMockNonAnonUserWithId( 1 ),
+                               new TitleValue( 0, 'SomeDbKey' ),
+                               '20151212010101'
+                       )
+               );
+       }
+
+       public function testUpdateNotificationTimestamp_noWatchers() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               [ 'watchlist' ],
+                               [ 'wl_user' ],
+                               [
+                                       'wl_user != 1',
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'SomeDbKey',
+                                       'wl_notificationtimestamp IS NULL'
+                               ]
+                       )
+                       ->will(
+                               $this->returnValue( [] )
+                       );
+               $mockDb->expects( $this->never() )
+                       ->method( 'onTransactionIdle' );
+               $mockDb->expects( $this->never() )
+                       ->method( 'update' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+               );
+
+               $watchers = $store->updateNotificationTimestamp(
+                       $this->getMockNonAnonUserWithId( 1 ),
+                       new TitleValue( 0, 'SomeDbKey' ),
+                       '20151212010101'
+               );
+               $this->assertInternalType( 'array', $watchers );
+               $this->assertEmpty( $watchers );
+       }
+
+}
diff --git a/tests/phpunit/includes/WatchedItemUnitTest.php b/tests/phpunit/includes/WatchedItemUnitTest.php
new file mode 100644 (file)
index 0000000..bc37311
--- /dev/null
@@ -0,0 +1,183 @@
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @covers WatchedItem
+ */
+class WatchedItemUnitTest extends PHPUnit_Framework_TestCase {
+
+       public function provideUserTitleTimestamp() {
+               return [
+                       [ User::newFromId( 111 ), Title::newFromText( 'SomeTitle' ), null ],
+                       [ User::newFromId( 111 ), Title::newFromText( 'SomeTitle' ), '20150101010101' ],
+                       [ User::newFromId( 111 ), new TitleValue( 0, 'TVTitle', 'frag' ), '20150101010101' ],
+               ];
+       }
+
+       /**
+        * @return PHPUnit_Framework_MockObject_MockObject|WatchedItemStore
+        */
+       private function getMockWatchedItemStore() {
+               return $this->getMockBuilder( WatchedItemStore::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+       }
+
+       /**
+        * @dataProvider provideUserTitleTimestamp
+        */
+       public function testConstruction( $user, LinkTarget $linkTarget, $notifTimestamp ) {
+               $item = new WatchedItem( $user, $linkTarget, $notifTimestamp );
+
+               $this->assertSame( $user, $item->getUser() );
+               $this->assertSame( $linkTarget, $item->getLinkTarget() );
+               $this->assertSame( $notifTimestamp, $item->getNotificationTimestamp() );
+
+               // The below tests the internal WatchedItem::getTitle method
+               $this->assertInstanceOf( 'Title', $item->getTitle() );
+               $this->assertSame( $linkTarget->getDBkey(), $item->getTitle()->getDBkey() );
+               $this->assertSame( $linkTarget->getFragment(), $item->getTitle()->getFragment() );
+               $this->assertSame( $linkTarget->getNamespace(), $item->getTitle()->getNamespace() );
+               $this->assertSame( $linkTarget->getText(), $item->getTitle()->getText() );
+       }
+
+       /**
+        * @dataProvider provideUserTitleTimestamp
+        */
+       public function testFromUserTitle( $user, $linkTarget, $timestamp ) {
+               $store = $this->getMockWatchedItemStore();
+               $store->expects( $this->once() )
+                       ->method( 'loadWatchedItem' )
+                       ->with( $user, $linkTarget )
+                       ->will( $this->returnValue( new WatchedItem( $user, $linkTarget, $timestamp ) ) );
+               WatchedItemStore::overrideDefaultInstance( $store );
+
+               $item = WatchedItem::fromUserTitle( $user, $linkTarget, User::IGNORE_USER_RIGHTS );
+
+               $this->assertEquals( $user, $item->getUser() );
+               $this->assertEquals( $linkTarget, $item->getLinkTarget() );
+               $this->assertEquals( $timestamp, $item->getNotificationTimestamp() );
+       }
+
+       /**
+        * @dataProvider provideUserTitleTimestamp
+        */
+       public function testResetNotificationTimestamp( $user, $linkTarget, $timestamp ) {
+               $force = 'XXX';
+               $oldid = 999;
+
+               $store = $this->getMockWatchedItemStore();
+               $store->expects( $this->once() )
+                       ->method( 'resetNotificationTimestamp' )
+                       ->with( $user, $this->isInstanceOf( Title::class ), $force, $oldid )
+                       ->will( $this->returnCallback(
+                               function ( $user, Title $title, $force, $oldid ) use ( $linkTarget ) {
+                                       /** @var LinkTarget $linkTarget */
+                                       $this->assertInstanceOf( 'Title', $title );
+                                       $this->assertSame( $linkTarget->getDBkey(), $title->getDBkey() );
+                                       $this->assertSame( $linkTarget->getFragment(), $title->getFragment() );
+                                       $this->assertSame( $linkTarget->getNamespace(), $title->getNamespace() );
+                                       $this->assertSame( $linkTarget->getText(), $title->getText() );
+
+                                       return true;
+                               }
+                       ) );
+               WatchedItemStore::overrideDefaultInstance( $store );
+
+               $item = new WatchedItem( $user, $linkTarget, $timestamp );
+               $item->resetNotificationTimestamp( $force, $oldid );
+       }
+
+       public function testAddWatch() {
+               $title = Title::newFromText( 'SomeTitle' );
+               $timestamp = null;
+               $checkRights = 0;
+
+               /** @var User|PHPUnit_Framework_MockObject_MockObject $user */
+               $user = $this->getMock( User::class );
+               $user->expects( $this->once() )
+                       ->method( 'addWatch' )
+                       ->with( $title, $checkRights );
+
+               $item = new WatchedItem( $user, $title, $timestamp, $checkRights );
+               $this->assertTrue( $item->addWatch() );
+       }
+
+       public function testRemoveWatch() {
+               $title = Title::newFromText( 'SomeTitle' );
+               $timestamp = null;
+               $checkRights = 0;
+
+               /** @var User|PHPUnit_Framework_MockObject_MockObject $user */
+               $user = $this->getMock( User::class );
+               $user->expects( $this->once() )
+                       ->method( 'removeWatch' )
+                       ->with( $title, $checkRights );
+
+               $item = new WatchedItem( $user, $title, $timestamp, $checkRights );
+               $this->assertTrue( $item->removeWatch() );
+       }
+
+       public function provideBooleans() {
+               return [
+                       [ true ],
+                       [ false ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideBooleans
+        */
+       public function testIsWatched( $returnValue ) {
+               $title = Title::newFromText( 'SomeTitle' );
+               $timestamp = null;
+               $checkRights = 0;
+
+               /** @var User|PHPUnit_Framework_MockObject_MockObject $user */
+               $user = $this->getMock( User::class );
+               $user->expects( $this->once() )
+                       ->method( 'isWatched' )
+                       ->with( $title, $checkRights )
+                       ->will( $this->returnValue( $returnValue ) );
+
+               $item = new WatchedItem( $user, $title, $timestamp, $checkRights );
+               $this->assertEquals( $returnValue, $item->isWatched() );
+       }
+
+       public function testDuplicateEntries() {
+               $oldTitle = Title::newFromText( 'OldTitle' );
+               $newTitle = Title::newFromText( 'NewTitle' );
+
+               $store = $this->getMockWatchedItemStore();
+               $store->expects( $this->once() )
+                       ->method( 'duplicateAllAssociatedEntries' )
+                       ->with( $oldTitle, $newTitle );
+               WatchedItemStore::overrideDefaultInstance( $store );
+
+               WatchedItem::duplicateEntries( $oldTitle, $newTitle );
+       }
+
+       public function testBatchAddWatch() {
+               /** @var WatchedItem[] $items */
+               $items = [
+                       new WatchedItem( User::newFromId( 1 ), new TitleValue( 0, 'Title1' ), null ),
+                       new WatchedItem( User::newFromId( 3 ), Title::newFromText( 'Title2' ), '20150101010101' ),
+               ];
+
+               $userTargetCombinations = [];
+               foreach ( $items as $item ) {
+                       $userTargetCombinations[] = [ $item->getUser(), $item->getTitle()->getSubjectPage() ];
+                       $userTargetCombinations[] = [ $item->getUser(), $item->getTitle()->getTalkPage() ];
+               }
+
+               $store = $this->getMockWatchedItemStore();
+               $store->expects( $this->once() )
+                       ->method( 'addWatchBatch' )
+                       ->with( $userTargetCombinations );
+               WatchedItemStore::overrideDefaultInstance( $store );
+
+               WatchedItem::batchAddWatch( $items );
+       }
+
+}
index 62e175b..78cb7fb 100644 (file)
@@ -230,7 +230,7 @@ class RandomImageGenerator {
                        $points[] = $point['x'] . ',' . $point['y'];
                }
 
-               return join( " ", $points );
+               return implode( " ", $points );
        }
 
        /**
@@ -425,7 +425,7 @@ class RandomImageGenerator {
                        $components[] = mt_rand( 0, 255 );
                }
 
-               return 'rgb(' . join( ', ', $components ) . ')';
+               return 'rgb(' . implode( ', ', $components ) . ')';
        }
 
        /**
index 193034f..79cc666 100644 (file)
@@ -108,13 +108,13 @@ class OldChangesListTest extends MediaWikiLangTestCase {
                $line = $oldChangesList->recentChangesLine( $recentChange, false, 1 );
 
                $this->assertContains(
-                       "<abbr class='newpage' title='(recentchanges-label-newpage)'>(newpageletter)</abbr>",
+                       '<abbr class="newpage" title="(recentchanges-label-newpage)">(newpageletter)</abbr>',
                        $line,
                        'new page flag'
                );
 
                $this->assertContains(
-                       "<abbr class='botedit' title='(recentchanges-label-bot)'>(boteditletter)</abbr>",
+                       '<abbr class="botedit" title="(recentchanges-label-bot)">(boteditletter)</abbr>',
                        $line,
                        'bot flag'
                );
index 8e8002c..168b2c6 100644 (file)
@@ -247,14 +247,64 @@ class DatabaseMysqlBaseTest extends MediaWikiTestCase {
                ];
        }
 
-       function testMasterPos() {
-               $pos1 = new MySQLMasterPos( 'db1034-bin.000976', '843431247' );
-               $pos2 = new MySQLMasterPos( 'db1034-bin.000976', '843431248' );
-
-               $this->assertTrue( $pos1->hasReached( $pos1 ) );
-               $this->assertTrue( $pos2->hasReached( $pos2 ) );
-               $this->assertTrue( $pos2->hasReached( $pos1 ) );
-               $this->assertFalse( $pos1->hasReached( $pos2 ) );
+       /**
+        * @dataProvider provideComparePositions
+        */
+       function testHasReached( MySQLMasterPos $lowerPos, MySQLMasterPos $higherPos ) {
+               $this->assertTrue( $higherPos->hasReached( $lowerPos ) );
+               $this->assertTrue( $higherPos->hasReached( $higherPos ) );
+               $this->assertTrue( $lowerPos->hasReached( $lowerPos ) );
+               $this->assertFalse( $lowerPos->hasReached( $higherPos ) );
+       }
+
+       function provideComparePositions() {
+               return [
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '843431247' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '843431248' )
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '1000' )
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1035-bin.000976', '1000' )
+                       ],
+               ];
+       }
+
+       /**
+        * @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
+                       ],
+               ];
        }
 
        /**
index 519c8c3..6eb96b1 100644 (file)
@@ -4,7 +4,7 @@
  * in an instance property rather than APC.
  */
 class ArrayBackedMemoizedCallable extends MemoizedCallable {
-       public $cache = [];
+       private $cache = [];
 
        protected function fetchResult( $key, &$success ) {
                if ( array_key_exists( $key, $this->cache ) ) {
@@ -112,6 +112,11 @@ class MemoizedCallableTest extends PHPUnit_Framework_TestCase {
                        $this->readAttribute( $a, 'callableName' ),
                        $this->readAttribute( $b, 'callableName' )
                );
+
+               $c = new ArrayBackedMemoizedCallable( function () {
+                       return rand();
+               } );
+               $this->assertEquals( $c->invokeArgs(), $c->invokeArgs(), 'memoized random' );
        }
 
        /**
index b50fe80..dfa92f1 100644 (file)
@@ -137,5 +137,5 @@ class WebPHandlerTest extends MediaWikiTestCase {
 }
 
 /* Python code to extract a header and convert to PHP format:
- * print '"%s"' % ''.join( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
+ * print '"%s"' % ''.implode( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
  */
index 998d2bb..534cf9b 100644 (file)
@@ -171,7 +171,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
                $gotWarnings = count( $warnings );
                if ( $gotWarnings !== $expectWarnings ) {
                        $this->fail( "Expected $expectWarnings warning(s), but got $gotWarnings:\n" .
-                               join( "\n", $warnings )
+                               implode( "\n", $warnings )
                        );
                }
        }
index b9cb6c1..542420a 100644 (file)
@@ -153,7 +153,7 @@ class ApiDocumentationTest extends MediaWikiTestCase {
                                foreach ( $globals as $k => $v ) {
                                        $g[] = "$k=" . var_export( $v, 1 );
                                }
-                               $k = "Module $path with " . join( ', ', $g );
+                               $k = "Module $path with " . implode( ', ', $g );
                                $ret[$k] = [ $path, $globals ];
                        }
                }
index 456787c..5a96dc3 100644 (file)
@@ -110,7 +110,7 @@ class GenerateJqueryMsgData extends Maintenance {
                                        $langKey = $languageCode . '_' . $key;
                                        $messages[$langKey] = $template;
                                        $tests[] = [
-                                               'name' => $languageCode . ' ' . $key . ' ' . join( ',', $args ),
+                                               'name' => $languageCode . ' ' . $key . ' ' . implode( ',', $args ),
                                                'key' => $langKey,
                                                'args' => $args,
                                                'result' => $result,