Merge "objectcache: add mcrouter support to WANObjectCache"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 19 Aug 2016 02:57:18 +0000 (02:57 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 19 Aug 2016 02:57:18 +0000 (02:57 +0000)
215 files changed:
Gemfile
Gemfile.lock
RELEASE-NOTES-1.28
autoload.php
composer.json
includes/DefaultSettings.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/MovePage.php
includes/OutputPage.php
includes/StubObject.php
includes/WatchedItemStore.php
includes/actions/InfoAction.php
includes/api/ApiAuthManagerHelper.php
includes/api/ApiBase.php
includes/api/ApiLogin.php
includes/api/ApiMain.php
includes/api/ApiQueryBacklinksprop.php
includes/api/ApiUpload.php
includes/api/i18n/bg.json
includes/api/i18n/fr.json
includes/api/i18n/gl.json
includes/api/i18n/he.json
includes/api/i18n/hu.json
includes/api/i18n/zh-hans.json
includes/auth/AuthManager.php
includes/auth/AuthenticationRequest.php
includes/auth/PasswordAuthenticationRequest.php
includes/auth/PrimaryAuthenticationProvider.php
includes/auth/TemporaryPasswordPrimaryAuthenticationProvider.php
includes/cache/BacklinkCache.php
includes/changes/RecentChange.php
includes/content/CodeContentHandler.php
includes/content/ContentHandler.php
includes/content/CssContentHandler.php
includes/content/JavaScriptContentHandler.php
includes/content/JsonContentHandler.php
includes/content/TextContent.php
includes/content/TextContentHandler.php
includes/content/WikitextContentHandler.php
includes/db/DBConnRef.php
includes/db/Database.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabasePostgres.php
includes/db/DatabaseSqlite.php
includes/db/IDatabase.php
includes/db/loadbalancer/LBFactory.php
includes/db/loadbalancer/LBFactoryMulti.php
includes/db/loadbalancer/LBFactorySimple.php
includes/db/loadbalancer/LoadBalancer.php
includes/deferred/AtomicSectionUpdate.php
includes/deferred/AutoCommitUpdate.php
includes/deferred/DataUpdate.php
includes/deferred/DeferredUpdates.php
includes/deferred/LinksDeletionUpdate.php
includes/deferred/LinksUpdate.php
includes/deferred/MWCallableUpdate.php
includes/exception/MWException.php
includes/filebackend/lockmanager/DBLockManager.php
includes/filerepo/RepoGroup.php
includes/filerepo/file/LocalFile.php
includes/htmlform/HTMLForm.php
includes/htmlform/fields/HTMLFormFieldCloner.php
includes/installer/Installer.php
includes/installer/i18n/sv.json
includes/jobqueue/JobRunner.php
includes/jobqueue/jobs/AssembleUploadChunksJob.php
includes/jobqueue/jobs/CategoryMembershipChangeJob.php
includes/jobqueue/jobs/DeleteLinksJob.php
includes/jobqueue/jobs/HTMLCacheUpdateJob.php
includes/jobqueue/jobs/RecentChangesUpdateJob.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/libs/objectcache/WANObjectCache.php
includes/objectcache/ObjectCache.php
includes/objectcache/SqlBagOStuff.php
includes/page/WikiPage.php
includes/pager/IndexPager.php
includes/parser/Parser.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderClientHtml.php
includes/resourceloader/ResourceLoaderContext.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderImage.php
includes/resourceloader/ResourceLoaderImageModule.php
includes/revisiondelete/RevDelList.php
includes/skins/SkinTemplate.php
includes/specials/SpecialConfirmemail.php
includes/specials/SpecialContributions.php
includes/specials/SpecialEmailInvalidate.php
includes/specials/SpecialSearch.php
includes/specials/SpecialTags.php
includes/specials/SpecialUndelete.php
includes/upload/UploadBase.php
includes/upload/UploadFromChunks.php
includes/upload/UploadFromStash.php
includes/user/User.php
languages/Language.php
languages/i18n/ang.json
languages/i18n/ar.json
languages/i18n/ast.json
languages/i18n/az.json
languages/i18n/azb.json
languages/i18n/ba.json
languages/i18n/be.json
languages/i18n/bg.json
languages/i18n/bho.json
languages/i18n/bn.json
languages/i18n/ca.json
languages/i18n/ckb.json
languages/i18n/cs.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/fa.json
languages/i18n/fr.json
languages/i18n/gl.json
languages/i18n/gor.json
languages/i18n/got.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/id.json
languages/i18n/is.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/jv.json
languages/i18n/kk-cyrl.json
languages/i18n/ko.json
languages/i18n/ky.json
languages/i18n/lb.json
languages/i18n/lij.json
languages/i18n/map-bms.json
languages/i18n/mg.json
languages/i18n/mk.json
languages/i18n/mr.json
languages/i18n/ms.json
languages/i18n/nap.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ru.json
languages/i18n/si.json
languages/i18n/sl.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/i18n/ta.json
languages/i18n/te.json
languages/i18n/tr.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/uz.json
languages/i18n/wuu.json
languages/i18n/yo.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/messages/MessagesCs.php
languages/messages/MessagesSk.php
maintenance/Maintenance.php
maintenance/cleanupCaps.php
maintenance/findDeprecated.php
maintenance/hhvm/makeRepo.php [new file with mode: 0644]
maintenance/hhvm/run-server [new file with mode: 0755]
maintenance/hhvm/server.conf [new file with mode: 0644]
maintenance/hiphop/run-server [deleted file]
maintenance/hiphop/server.conf [deleted file]
maintenance/refreshImageMetadata.php
mw-config/overrides/README
resources/Resources.php
resources/ResourcesOOUI.php
resources/assets/licenses/README [new file with mode: 0644]
resources/lib/oojs-ui/i18n/ckb.json
resources/lib/oojs-ui/i18n/da.json
resources/lib/oojs-ui/i18n/diq.json
resources/lib/oojs-ui/oojs-ui-apex.js
resources/lib/oojs-ui/oojs-ui-core-apex.css
resources/lib/oojs-ui/oojs-ui-core-mediawiki.css
resources/lib/oojs-ui/oojs-ui-core.js
resources/lib/oojs-ui/oojs-ui-mediawiki.js
resources/lib/oojs-ui/oojs-ui-toolbars-apex.css
resources/lib/oojs-ui/oojs-ui-toolbars-mediawiki.css
resources/lib/oojs-ui/oojs-ui-toolbars.js
resources/lib/oojs-ui/oojs-ui-widgets-apex.css
resources/lib/oojs-ui/oojs-ui-widgets-mediawiki.css
resources/lib/oojs-ui/oojs-ui-widgets.js
resources/lib/oojs-ui/oojs-ui-windows-apex.css
resources/lib/oojs-ui/oojs-ui-windows-mediawiki.css
resources/lib/oojs-ui/oojs-ui-windows.js
resources/src/mediawiki.skinning/content.css
resources/src/mediawiki.ui/components/icons.less
resources/src/mediawiki/mediawiki.raggett.css [deleted file]
resources/src/mediawiki/page/gallery-slideshow.js
resources/src/mediawiki/page/watch.js
resources/src/oojs-ui-styles-skip.js [deleted file]
tests/browser/environments.yml
tests/parser/parserTest.inc
tests/phpunit/includes/auth/AuthManagerTest.php
tests/phpunit/includes/auth/AuthenticationRequestTest.php
tests/phpunit/includes/auth/AuthenticationRequestTestCase.php
tests/phpunit/includes/content/ContentHandlerTest.php
tests/phpunit/includes/content/TextContentTest.php
tests/phpunit/includes/db/DatabaseTest.php
tests/phpunit/includes/libs/ObjectFactoryTest.php
tests/phpunit/includes/search/SearchEngineTest.php
tests/phpunit/specials/SpecialSearchTest.php [new file with mode: 0644]
tests/phpunit/structure/ResourcesTest.php
tests/qunit/QUnitTestResources.php
tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js [new file with mode: 0644]
tests/qunit/suites/resources/mediawiki/mediawiki.test.js

diff --git a/Gemfile b/Gemfile
index 19d2f52..8a349bf 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,5 @@
 source 'https://rubygems.org'
 
-gem 'mediawiki_selenium', '~> 1.7', '>= 1.7.1'
+gem 'mediawiki_selenium', '~> 1.7', '>= 1.7.2'
 gem 'rake', '~> 11.1', '>= 11.1.1'
 gem 'rubocop', '~> 0.32.1', require: false
index 2d6e655..982619a 100644 (file)
@@ -17,16 +17,18 @@ GEM
       faker (>= 1.1.2)
       yml_reader (>= 0.6)
     diff-lcs (1.2.5)
-    domain_name (0.5.20160310)
+    domain_name (0.5.20160615)
       unf (>= 0.0.5, < 1.0.0)
-    faker (1.6.3)
+    faker (1.6.6)
       i18n (~> 0.5)
     faraday (0.9.2)
       multipart-post (>= 1.2, < 3)
     faraday-cookie_jar (0.0.6)
       faraday (>= 0.7.4)
       http-cookie (~> 1.0.0)
-    ffi (1.9.10)
+    faraday_middleware (0.10.0)
+      faraday (>= 0.7.4, < 0.10)
+    ffi (1.9.14)
     gherkin (2.12.2)
       multi_json (~> 1.3)
     headless (2.2.3)
@@ -34,14 +36,15 @@ GEM
       domain_name (~> 0.5)
     i18n (0.7.0)
     json (1.8.3)
-    mediawiki_api (0.6.0)
+    mediawiki_api (0.7.0)
       faraday (~> 0.9, >= 0.9.0)
       faraday-cookie_jar (~> 0.0, >= 0.0.6)
-    mediawiki_selenium (1.7.1)
+      faraday_middleware (~> 0.10, >= 0.10.0)
+    mediawiki_selenium (1.7.2)
       cucumber (~> 1.3, >= 1.3.20)
       headless (~> 2.0, >= 2.1.0)
       json (~> 1.8, >= 1.8.1)
-      mediawiki_api (~> 0.6, >= 0.6.0)
+      mediawiki_api (~> 0.7, >= 0.7.0)
       page-object (~> 1.0)
       rest-client (~> 1.6, >= 1.6.7)
       rspec-core (~> 2.14, >= 2.14.4)
@@ -53,7 +56,7 @@ GEM
     multi_test (0.1.2)
     multipart-post (2.0.0)
     netrc (0.11.0)
-    page-object (1.1.1)
+    page-object (1.2.0)
       page_navigation (>= 0.9)
       selenium-webdriver (>= 2.44.0)
       watir-webdriver (>= 0.6.11)
@@ -79,7 +82,7 @@ GEM
       ruby-progressbar (~> 1.4)
     ruby-progressbar (1.7.5)
     rubyzip (1.2.0)
-    selenium-webdriver (2.53.1)
+    selenium-webdriver (2.53.4)
       childprocess (~> 0.5)
       rubyzip (~> 1.0)
       websocket (~> 1.0)
@@ -88,7 +91,7 @@ GEM
     unf (0.1.4)
       unf_ext
     unf_ext (0.0.7.2)
-    watir-webdriver (0.9.1)
+    watir-webdriver (0.9.3)
       selenium-webdriver (>= 2.46.2)
     websocket (1.2.3)
     yml_reader (0.7)
@@ -97,9 +100,6 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
-  mediawiki_selenium (~> 1.7, >= 1.7.1)
+  mediawiki_selenium (~> 1.7, >= 1.7.2)
   rake (~> 11.1, >= 11.1.1)
   rubocop (~> 0.32.1)
-
-BUNDLED WITH
-   1.10.6
index eb9bc17..eac4e2c 100644 (file)
@@ -61,6 +61,13 @@ production.
 * The following response properties from action=login, deprecated in 1.27, are
   now removed: lgtoken, cookieprefix, sessionid. Clients should handle cookies
   to properly manage session state.
+* Submitting the lgtoken and lgpassword parameters in the query string to
+  action=login is now deprecated and outputs a warning. They should be submitted
+  in the POST body instead.
+* Submitting sensitive authentication request parameters to action=clientlogin,
+  action=createaccount, action=linkaccount, and action=changeauthenticationdata
+  in the query string is now deprecated and outputs a warning. They should be
+  submitted in the POST body instead.
 
 === Action API internal changes in 1.28 ===
 * Added a new hook, 'ApiMakeParserOptions', to allow extensions to better
@@ -76,6 +83,7 @@ changes to languages because of Phabricator reports.
   BASAbali, M. Adiputra, Naval Scene, Nemo bis, NoiX180, and 아라.
 * (T135867) shn (Shan), thanks to translators Khun Sar, Piangpha,
   Saiddzone Saimawnkham, Saosukham, and Sengwan.
+* Czech (cs) and Slovak (sk) set as reciprocal fallbacks
 
 === Other changes in 1.28 ===
 * (T128697) Improved handling of large diffs.
@@ -105,6 +113,11 @@ changes to languages because of Phabricator reports.
 * DifferenceEngine::generateDiffBody() was removed (deprecated since 1.21).
 * UploadBase::stashFileGetKey() and UploadBase::stashSession() were deprecated.
   Use ...->stashFile()->getFileKey() instead.
+* "Public domain" was removed as a wiki license option from the installer, in
+  favour of CC-0.
+* AuthenticationRequest::$required is now changed from REQUIRED to PRIMARY_REQUIRED
+  on requests needed by primary providers even if all primaries need them.
+  Primary providers are discouraged from returning multiple REQUIRED requests.
 
 == Compatibility ==
 
index f6edd94..fc6577e 100644 (file)
@@ -513,6 +513,7 @@ $wgAutoloadLocalClasses = [
        'GitInfo' => __DIR__ . '/includes/GitInfo.php',
        'GlobalDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
        'GlobalVarConfig' => __DIR__ . '/includes/config/GlobalVarConfig.php',
+       'HHVMMakeRepo' => __DIR__ . '/maintenance/hhvm/makeRepo.php',
        'HTMLApiField' => __DIR__ . '/includes/htmlform/fields/HTMLApiField.php',
        'HTMLAutoCompleteSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLAutoCompleteSelectField.php',
        'HTMLButtonField' => __DIR__ . '/includes/htmlform/fields/HTMLButtonField.php',
index 9bd0fa1..956739d 100644 (file)
@@ -25,7 +25,7 @@
                "ext-xml": "*",
                "liuggio/statsd-php-client": "1.0.18",
                "mediawiki/at-ease": "1.1.0",
-               "oojs/oojs-ui": "0.17.7",
+               "oojs/oojs-ui": "0.17.8",
                "oyejorge/less.php": "1.7.0.10",
                "php": ">=5.5.9",
                "psr/log": "1.0.0",
@@ -48,7 +48,7 @@
                "justinrainbow/json-schema": "~1.6",
                "mediawiki/mediawiki-codesniffer": "0.7.2",
                "monolog/monolog": "~1.18.2",
-               "nikic/php-parser": "1.4.1",
+               "nikic/php-parser": "2.1.0",
                "nmred/kafka-php": "0.1.5",
                "phpunit/phpunit": "4.8.24",
                "wikimedia/avro": "1.7.7"
index 2ac31bf..4e08aa6 100644 (file)
@@ -1670,6 +1670,9 @@ $wgEnotifWatchlist = false;
 /**
  * Allow users to enable email notification ("enotif") when someone edits their
  * user talk page.
+ *
+ * The owner of the user talk page must also have the 'enotifusertalkpages' user
+ * preference set to true.
  */
 $wgEnotifUserTalk = false;
 
@@ -1680,9 +1683,17 @@ $wgEnotifUserTalk = false;
 $wgEnotifRevealEditorAddress = false;
 
 /**
- * Send notification mails on minor edits to watchlist pages. This is enabled
- * by default. User talk notifications are affected by this, $wgEnotifUserTalk, and
- * the nominornewtalk user right.
+ * Potentially send notification mails on minor edits to pages. This is enabled
+ * by default.  If this is false, users will never be notified on minor edits.
+ *
+ * If it is true, editors with the 'nominornewtalk' right (typically bots) will still not
+ * trigger notifications for minor edits they make (to any page, not just user talk).
+ *
+ * Finally, if the watcher/recipient has the 'enotifminoredits' user preference set to
+ * false, they will not receive notifications for minor edits.
+ *
+ * User talk notifications are also affected by $wgEnotifMinorEdits, the above settings,
+ * $wgEnotifUserTalk, and the preference described there.
  */
 $wgEnotifMinorEdits = true;
 
@@ -5699,6 +5710,8 @@ $wgGrantPermissions['sendemail']['sendemail'] = true;
 
 $wgGrantPermissions['createaccount']['createaccount'] = true;
 
+$wgGrantPermissions['privateinfo']['viewmyprivateinfo'] = true;
+
 /**
  * @var Array Map of grants to their UI grouping
  * @since 1.27
@@ -5732,6 +5745,8 @@ $wgGrantPermissionGroups = [
        'createaccount'       => 'administration',
 
        'highvolume'          => 'high-volume',
+
+       'privateinfo'         => 'private-information',
 ];
 
 /**
index ee06993..9b862b9 100644 (file)
@@ -1474,7 +1474,7 @@ class EditPage {
 
                        case self::AS_CANNOT_USE_CUSTOM_MODEL:
                        case self::AS_PARSE_ERROR:
-                               $wgOut->addWikiText( '<div class="error">' . $status->getWikiText() . '</div>' );
+                               $wgOut->addWikiText( '<div class="error">' . "\n" . $status->getWikiText() . '</div>' );
                                return true;
 
                        case self::AS_SUCCESS_NEW_ARTICLE:
@@ -1551,7 +1551,7 @@ class EditPage {
                                // is if an extension hook aborted from inside ArticleSave.
                                // Render the status object into $this->hookError
                                // FIXME this sucks, we should just use the Status object throughout
-                               $this->hookError = '<div class="error">' . $status->getWikiText() .
+                               $this->hookError = '<div class="error">' ."\n" . $status->getWikiText() .
                                        '</div>';
                                return true;
                }
index 7117f4c..0d66908 100644 (file)
@@ -811,7 +811,7 @@ function wfUrlProtocolsWithoutProtRel() {
  * 3) Adds a "delimiter" element to the array, either '://', ':' or '//' (see (2)).
  *
  * @param string $url A URL to parse
- * @return string[] Bits of the URL in an associative array, per PHP docs
+ * @return string[]|bool Bits of the URL in an associative array, per PHP docs, false on failure
  */
 function wfParseUrl( $url ) {
        global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
index 70b6738..bc3305a 100644 (file)
@@ -256,7 +256,7 @@ class MovePage {
                $pageid = $this->oldTitle->getArticleID( Title::GAID_FOR_UPDATE );
                $protected = $this->oldTitle->isProtected();
 
-               // Do the actual move
+               // Do the actual move; if this fails, it will throw an MWException(!)
                $nullRevision = $this->moveToInternal( $user, $this->newTitle, $reason, $createRedirect );
 
                // Refresh the sortkey for this row.  Be careful to avoid resetting
@@ -412,7 +412,7 @@ class MovePage {
         *
         * @fixme This was basically directly moved from Title, it should be split into smaller functions
         * @param User $user the User doing the move
-        * @param Title $nt The page to move to, which should be a redirect or nonexistent
+        * @param Title $nt The page to move to, which should be a redirect or non-existent
         * @param string $reason The reason for the move
         * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check
         *   if the user has the suppressredirect right
@@ -430,6 +430,29 @@ class MovePage {
                        $logType = 'move';
                }
 
+               if ( $moveOverRedirect ) {
+                       $overwriteMessage = wfMessage(
+                                       'delete_and_move_reason',
+                                       $this->oldTitle->getPrefixedText()
+                               )->text();
+                       $newpage = WikiPage::factory( $nt );
+                       $errs = [];
+                       $status = $newpage->doDeleteArticleReal(
+                               $overwriteMessage,
+                               /* $suppress */ false,
+                               $nt->getArticleId(),
+                               /* $commit */ false,
+                               $errs,
+                               $user
+                       );
+
+                       if ( !$status->isGood() ) {
+                               throw new MWException( 'Failed to delete page-move revision: ' . $status );
+                       }
+
+                       $nt->resetArticleID( false );
+               }
+
                if ( $createRedirect ) {
                        if ( $this->oldTitle->getNamespace() == NS_CATEGORY
                                && !wfMessage( 'category-move-redirect-override' )->inContentLanguage()->isDisabled()
@@ -484,19 +507,6 @@ class MovePage {
 
                $newpage = WikiPage::factory( $nt );
 
-               if ( $moveOverRedirect ) {
-                       $newid = $nt->getArticleID();
-                       $newcontent = $newpage->getContent();
-
-                       # Delete the old redirect. We don't save it to history since
-                       # by definition if we've got here it's rather uninteresting.
-                       # We have to remove it so that the next step doesn't trigger
-                       # a conflict on the unique namespace+title index...
-                       $dbw->delete( 'page', [ 'page_id' => $newid ], __METHOD__ );
-
-                       $newpage->doDeleteUpdates( $newid, $newcontent );
-               }
-
                # Save a null revision in the page's history notifying of the move
                $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true, $user );
                if ( !is_object( $nullRevision ) ) {
@@ -542,9 +552,7 @@ class MovePage {
                        );
                }
 
-               if ( !$moveOverRedirect ) {
-                       WikiPage::onArticleCreate( $nt );
-               }
+               WikiPage::onArticleCreate( $nt );
 
                # Recreate the redirect, this time in the other direction.
                if ( $redirectContent ) {
index cc377bc..374e7af 100644 (file)
@@ -2671,7 +2671,7 @@ class OutputPage extends ContextSource {
                                'user.options',
                                'user.tokens',
                        ] );
-                       $rlClient = new ResourceLoaderClientHtml( $context );
+                       $rlClient = new ResourceLoaderClientHtml( $context, $this->getTarget() );
                        $rlClient->setConfig( $this->getJSVars() );
                        $rlClient->setModules( $this->getModules( /*filter*/ true ) );
                        $rlClient->setModuleStyles( $this->getModuleStyles( /*filter*/ true ) );
@@ -2790,9 +2790,12 @@ class OutputPage extends ContextSource {
         * @return string|WrappedStringList HTML
         */
        public function makeResourceLoaderLink( $modules, $only, array $extraQuery = [] ) {
+               // Apply 'target' and 'origin' filters
+               $modules = $this->filterModules( (array)$modules, null, $only );
+
                return ResourceLoaderClientHtml::makeLoad(
                        $this->getRlClientContext(),
-                       (array)$modules,
+                       $modules,
                        $only,
                        $extraQuery
                );
@@ -3810,9 +3813,6 @@ class OutputPage extends ContextSource {
                        'oojs-ui.styles.textures',
                        'mediawiki.widgets.styles',
                ] );
-               // Used by 'skipFunction' of the four 'oojs-ui.styles.*' modules. Please don't treat this as a
-               // public API or you'll be severely disappointed when T87871 is fixed and it disappears.
-               $this->addMeta( 'X-OOUI-PHP', '1' );
        }
 
        /**
index 0b4d048..0210ed9 100644 (file)
@@ -48,6 +48,9 @@ class StubObject {
        /** @var null|string */
        protected $class;
 
+       /** @var null|callable */
+       protected $factory;
+
        /** @var array */
        protected $params;
 
@@ -55,12 +58,17 @@ class StubObject {
         * Constructor.
         *
         * @param string $global Name of the global variable.
-        * @param string $class Name of the class of the real object.
+        * @param string|callable $class Name of the class of the real object
+        *                               or a factory function to call
         * @param array $params Parameters to pass to constructor of the real object.
         */
        public function __construct( $global = null, $class = null, $params = [] ) {
                $this->global = $global;
-               $this->class = $class;
+               if ( is_callable( $class ) ) {
+                       $this->factory = $class;
+               } else {
+                       $this->class = $class;
+               }
                $this->params = $params;
        }
 
@@ -110,8 +118,10 @@ class StubObject {
         * @return object
         */
        public function _newObject() {
-               return ObjectFactory::getObjectFromSpec( [
-                       'class' => $this->class,
+               $params = $this->factory
+                       ? [ 'factory' => $this->factory ]
+                       : [ 'class' => $this->class ];
+               return ObjectFactory::getObjectFromSpec( $params + [
                        'args' => $this->params,
                        'closure_expansion' => false,
                ] );
index 89ca50c..a13609b 100644 (file)
@@ -741,6 +741,8 @@ class WatchedItemStore implements StatsdAwareInterface {
                                        global $wgUpdateRowsPerQuery;
 
                                        $dbw = $this->getConnection( DB_MASTER );
+                                       $factory = wfGetLBFactory();
+                                       $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
 
                                        $watchersChunks = array_chunk( $watchers, $wgUpdateRowsPerQuery );
                                        foreach ( $watchersChunks as $watchersChunk ) {
@@ -754,14 +756,17 @@ class WatchedItemStore implements StatsdAwareInterface {
                                                        ], $fname
                                                );
                                                if ( count( $watchersChunks ) > 1 ) {
-                                                       $dbw->commit( __METHOD__, 'flush' );
-                                                       wfGetLBFactory()->waitForReplication( [ 'wiki' => $dbw->getWikiID() ] );
+                                                       $factory->commitAndWaitForReplication(
+                                                               __METHOD__, $ticket, [ 'wiki' => $dbw->getWikiID() ]
+                                                       );
                                                }
                                        }
                                        $this->uncacheLinkTarget( $target );
 
                                        $this->reuseConnection( $dbw );
-                               }
+                               },
+                               DeferredUpdates::POSTSEND,
+                               $dbw
                        );
                }
 
index 7be2aa7..ea66900 100644 (file)
@@ -671,7 +671,7 @@ class InfoAction extends FormlessAction {
 
                return ObjectCache::getMainWANInstance()->getWithSetCallback(
                        self::getCacheKey( $page->getTitle(), $page->getLatest() ),
-                       86400 * 7,
+                       WANObjectCache::TTL_WEEK,
                        function ( $oldValue, &$ttl, &$setOpts ) use ( $page, $config, $fname ) {
                                $title = $page->getTitle();
                                $id = $title->getArticleID();
index c970f93..a4f54ee 100644 (file)
@@ -157,8 +157,13 @@ class ApiAuthManagerHelper {
 
                // Collect the fields for all the requests
                $fields = [];
+               $sensitive = [];
                foreach ( $reqs as $req ) {
-                       $fields += (array)$req->getFieldInfo();
+                       $info = (array)$req->getFieldInfo();
+                       $fields += $info;
+                       $sensitive += array_filter( $info, function ( $opts ) {
+                               return !empty( $opts['sensitive'] );
+                       } );
                }
 
                // Extract the request data for the fields and mark those request
@@ -166,6 +171,16 @@ class ApiAuthManagerHelper {
                $data = array_intersect_key( $this->module->getRequest()->getValues(), $fields );
                $this->module->getMain()->markParamsUsed( array_keys( $data ) );
 
+               if ( $sensitive ) {
+                       try {
+                               $this->module->requirePostedParameters( array_keys( $sensitive ), 'noprefix' );
+                       } catch ( UsageException $ex ) {
+                               // Make this a warning for now, upgrade to an error in 1.29.
+                               $this->module->setWarning( $ex->getMessage() );
+                               $this->module->logFeatureUsage( $this->module->getModuleName() . '-params-in-query-string' );
+                       }
+               }
+
                return AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
        }
 
@@ -326,6 +341,7 @@ class ApiAuthManagerHelper {
                        $this->formatMessage( $ret, 'label', $field['label'] );
                        $this->formatMessage( $ret, 'help', $field['help'] );
                        $ret['optional'] = !empty( $field['optional'] );
+                       $ret['sensitive'] = !empty( $field['sensitive'] );
 
                        $retFields[$name] = $ret;
                }
index b45eacb..fcb748c 100644 (file)
@@ -776,6 +776,39 @@ abstract class ApiBase extends ContextSource {
                }
        }
 
+       /**
+        * Die if any of the specified parameters were found in the query part of
+        * the URL rather than the post body.
+        * @since 1.28
+        * @param string[] $params Parameters to check
+        * @param string $prefix Set to 'noprefix' to skip calling $this->encodeParamName()
+        */
+       public function requirePostedParameters( $params, $prefix = 'prefix' ) {
+               // Skip if $wgDebugAPI is set or we're in internal mode
+               if ( $this->getConfig()->get( 'DebugAPI' ) || $this->getMain()->isInternalMode() ) {
+                       return;
+               }
+
+               $queryValues = $this->getRequest()->getQueryValues();
+               $badParams = [];
+               foreach ( $params as $param ) {
+                       if ( $prefix !== 'noprefix' ) {
+                               $param = $this->encodeParamName( $param );
+                       }
+                       if ( array_key_exists( $param, $queryValues ) ) {
+                               $badParams[] = $param;
+                       }
+               }
+
+               if ( $badParams ) {
+                       $this->dieUsage(
+                               'The following parameters were found in the query string, but must be in the POST body: '
+                                       . join( ', ', $badParams ),
+                               'mustpostparams'
+                       );
+               }
+       }
+
        /**
         * Callback function used in requireOnlyOneParameter to check whether required parameters are set
         *
@@ -2197,7 +2230,7 @@ abstract class ApiBase extends ContextSource {
         * analysis.
         * @param string $feature Feature being used.
         */
-       protected function logFeatureUsage( $feature ) {
+       public function logFeatureUsage( $feature ) {
                $request = $this->getRequest();
                $s = '"' . addslashes( $feature ) . '"' .
                        ' "' . wfUrlencode( str_replace( ' ', '_', $this->getUser()->getName() ) ) . '"' .
@@ -2458,6 +2491,7 @@ abstract class ApiBase extends ContextSource {
 
                // Build map of extension directories to extension info
                if ( self::$extensionInfo === null ) {
+                       $extDir = $this->getConfig()->get( 'ExtensionDirectory' );
                        self::$extensionInfo = [
                                realpath( __DIR__ ) ?: __DIR__ => [
                                        'path' => $IP,
@@ -2465,6 +2499,7 @@ abstract class ApiBase extends ContextSource {
                                        'license-name' => 'GPL-2.0+',
                                ],
                                realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
+                               realpath( $extDir ) ?: $extDir => null,
                        ];
                        $keep = [
                                'path' => null,
index 851252c..9bc0b3a 100644 (file)
@@ -70,6 +70,14 @@ class ApiLogin extends ApiBase {
                        return;
                }
 
+               try {
+                       $this->requirePostedParameters( [ 'password', 'token' ] );
+               } catch ( UsageException $ex ) {
+                       // Make this a warning for now, upgrade to an error in 1.29.
+                       $this->setWarning( $ex->getMessage() );
+                       $this->logFeatureUsage( 'login-params-in-query-string' );
+               }
+
                $params = $this->extractRequestParams();
 
                $result = [];
@@ -155,10 +163,14 @@ class ApiLogin extends ApiBase {
                                        $authRes = 'Failed';
                                        $message = $res->message;
                                        \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
-                                               ->info( __METHOD__ . ': Authentication failed: ' . $message->plain() );
+                                               ->info( __METHOD__ . ': Authentication failed: '
+                                               . $message->inLanguage( 'en' )->plain() );
                                        break;
 
                                default:
+                                       \MediaWiki\Logger\LoggerFactory::getInstance( 'authentication' )
+                                               ->info( __METHOD__ . ': Authentication failed due to unsupported response type: '
+                                               . $res->status, $this->getAuthenticationResponseLogData( $res ) );
                                        $authRes = 'Aborted';
                                        break;
                        }
@@ -273,4 +285,32 @@ class ApiLogin extends ApiBase {
        public function getHelpUrls() {
                return 'https://www.mediawiki.org/wiki/API:Login';
        }
+
+       /**
+        * Turns an AuthenticationResponse into a hash suitable for passing to Logger
+        * @param AuthenticationResponse $response
+        * @return array
+        */
+       protected function getAuthenticationResponseLogData( AuthenticationResponse $response ) {
+               $ret = [
+                       'status' => $response->status,
+               ];
+               if ( $response->message ) {
+                       $ret['message'] = $response->message->inLanguage( 'en' )->plain();
+               };
+               $reqs = [
+                       'neededRequests' => $response->neededRequests,
+                       'createRequest' => $response->createRequest,
+                       'linkRequest' => $response->linkRequest,
+               ];
+               foreach ( $reqs as $k => $v ) {
+                       if ( $v ) {
+                               $v = is_array( $v ) ? $v : [ $v ];
+                               $reqClasses = array_unique( array_map( 'get_class', $v ) );
+                               sort( $reqClasses );
+                               $ret[$k] = implode( ', ', $reqClasses );
+                       }
+               }
+               return $ret;
+       }
 }
index 0478027..22b079d 100644 (file)
@@ -25,6 +25,8 @@
  * @defgroup API API
  */
 
+use MediaWiki\Logger\LoggerFactory;
+
 /**
  * This is the main API class, used for both external and internal processing.
  * When executed, it will create the requested formatter object,
@@ -206,7 +208,7 @@ class ApiMain extends ApiBase {
                                        $config->get( 'CrossSiteAJAXdomainExceptions' )
                                )
                        ) ) {
-                               MediaWiki\Logger\LoggerFactory::getInstance( 'cors' )->warning(
+                               LoggerFactory::getInstance( 'cors' )->warning(
                                        'Non-whitelisted CORS request with session cookies', [
                                                'origin' => $originHeader,
                                                'cookies' => $sessionCookies,
@@ -1101,18 +1103,7 @@ class ApiMain extends ApiBase {
                                $this->dieUsageMsg( [ 'missingparam', 'token' ] );
                        }
 
-                       if ( !$this->getConfig()->get( 'DebugAPI' ) &&
-                               array_key_exists(
-                                       $module->encodeParamName( 'token' ),
-                                       $this->getRequest()->getQueryValues()
-                               )
-                       ) {
-                               $this->dieUsage(
-                                       "The '{$module->encodeParamName( 'token' )}' parameter was " .
-                                               'found in the query string, but must be in the POST body',
-                                       'mustposttoken'
-                               );
-                       }
+                       $module->requirePostedParameters( [ 'token' ] );
 
                        if ( !$module->validateToken( $moduleParams['token'], $moduleParams ) ) {
                                $this->dieUsageMsg( 'sessionfailure' );
@@ -1453,6 +1444,7 @@ class ApiMain extends ApiBase {
        protected function setRequestExpectations( ApiBase $module ) {
                $limits = $this->getConfig()->get( 'TrxProfilerLimits' );
                $trxProfiler = Profiler::instance()->getTransactionProfiler();
+               $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
                if ( $this->getRequest()->hasSafeMethod() ) {
                        $trxProfiler->setExpectations( $limits['GET'], __METHOD__ );
                } elseif ( $this->getRequest()->wasPosted() && !$module->isWriteMode() ) {
index 3810e90..236fb9e 100644 (file)
@@ -53,6 +53,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                        'code' => 'lh',
                        'prefix' => 'pl',
                        'linktable' => 'pagelinks',
+                       'indexes' => [ 'pl_namespace', 'pl_backlinks_namespace' ],
                        'from_namespace' => true,
                        'showredirects' => true,
                ],
@@ -60,6 +61,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                        'code' => 'ti',
                        'prefix' => 'tl',
                        'linktable' => 'templatelinks',
+                       'indexes' => [ 'tl_namespace', 'tl_backlinks_namespace' ],
                        'from_namespace' => true,
                        'showredirects' => true,
                ],
@@ -67,6 +69,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                        'code' => 'fu',
                        'prefix' => 'il',
                        'linktable' => 'imagelinks',
+                       'indexes' => [ 'il_to', 'il_backlinks_namespace' ],
                        'from_namespace' => true,
                        'to_namespace' => NS_FILE,
                        'exampletitle' => 'File:Example.jpg',
@@ -249,6 +252,18 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                // Override any ORDER BY from above with what we calculated earlier.
                $this->addOption( 'ORDER BY', array_keys( $sortby ) );
 
+               // MySQL's optimizer chokes if we have too many values in "$bl_title IN
+               // (...)" and chooses the wrong index, so specify the correct index to
+               // use for the query. See T139056 for details.
+               if ( !empty( $settings['indexes'] ) ) {
+                       list( $idxNoFromNS, $idxWithFromNS ) = $settings['indexes'];
+                       if ( $params['namespace'] !== null && !empty( $settings['from_namespace'] ) ) {
+                               $this->addOption( 'USE INDEX', [ $settings['linktable'] => $idxWithFromNS ] );
+                       } else {
+                               $this->addOption( 'USE INDEX', [ $settings['linktable'] => $idxNoFromNS ] );
+                       }
+               }
+
                $this->addOption( 'LIMIT', $params['limit'] + 1 );
 
                $res = $this->select( __METHOD__ );
index 89d9af8..ac817ba 100644 (file)
@@ -240,7 +240,7 @@ class ApiUpload extends ApiBase {
                                        'offset' => $this->mUpload->getOffset(),
                                ];
 
-                               $this->dieUsage( $status->getWikiText( false, false, 'en' ), 'stashfailed', 0, $extradata );
+                               $this->dieStatusWithCode( $status, 'stashfailed', $extradata );
                        }
                }
 
@@ -271,14 +271,20 @@ class ApiUpload extends ApiBase {
                                                $filekey,
                                                [ 'result' => 'Failure', 'stage' => 'assembling', 'status' => $status ]
                                        );
-                                       $this->dieUsage( $status->getWikiText( false, false, 'en' ), 'stashfailed' );
+                                       $this->dieStatusWithCode( $status, 'stashfailed' );
+                               }
+
+                               // We can only get warnings like 'duplicate' after concatenating the chunks
+                               $warnings = $this->getApiWarnings();
+                               if ( $warnings ) {
+                                       $result['warnings'] = $warnings;
                                }
 
                                // The fully concatenated file has a new filekey. So remove
                                // the old filekey and fetch the new one.
                                UploadBase::setSessionStatus( $this->getUser(), $filekey, false );
                                $this->mUpload->stash->removeFile( $filekey );
-                               $filekey = $this->mUpload->getLocalFile()->getFileKey();
+                               $filekey = $this->mUpload->getStashFile()->getFileKey();
 
                                $result['result'] = 'Success';
                        }
@@ -315,8 +321,9 @@ class ApiUpload extends ApiBase {
         * @return string|null File key
         */
        private function performStash( $failureMode, &$data = null ) {
+               $isPartial = (bool)$this->mParams['chunk'];
                try {
-                       $status = $this->mUpload->tryStashFile( $this->getUser() );
+                       $status = $this->mUpload->tryStashFile( $this->getUser(), $isPartial );
 
                        if ( $status->isGood() && !$status->getValue() ) {
                                // Not actually a 'good' status...
@@ -381,6 +388,28 @@ class ApiUpload extends ApiBase {
                $this->dieUsage( $parsed['info'], $parsed['code'], 0, $data );
        }
 
+       /**
+        * Like dieStatus(), but always uses $overrideCode for the error code, unless the code comes from
+        * IApiMessage.
+        *
+        * @param Status $status
+        * @param string $overrideCode Error code to use if there isn't one from IApiMessage
+        * @param array|null $moreExtraData
+        * @throws UsageException
+        */
+       public function dieStatusWithCode( $status, $overrideCode, $moreExtraData = null ) {
+               $extraData = null;
+               list( $code, $msg ) = $this->getErrorFromStatus( $status, $extraData );
+               $errors = $status->getErrorsByType( 'error' ) ?: $status->getErrorsByType( 'warning' );
+               if ( !( $errors[0]['message'] instanceof IApiMessage ) ) {
+                       $code = $overrideCode;
+               }
+               if ( $moreExtraData ) {
+                       $extraData += $moreExtraData;
+               }
+               $this->dieUsage( $msg, $code, 0, $extraData );
+       }
+
        /**
         * Select an upload module and set it to mUpload. Dies on failure. If the
         * request was a status request and not a true upload, returns false;
@@ -403,11 +432,17 @@ class ApiUpload extends ApiBase {
                        if ( !$progress ) {
                                $this->dieUsage( 'No result in status data', 'missingresult' );
                        } elseif ( !$progress['status']->isGood() ) {
-                               $this->dieUsage( $progress['status']->getWikiText( false, false, 'en' ), 'stashfailed' );
+                               $this->dieStatusWithCode( $progress['status'], 'stashfailed' );
                        }
                        if ( isset( $progress['status']->value['verification'] ) ) {
                                $this->checkVerification( $progress['status']->value['verification'] );
                        }
+                       if ( isset( $progress['status']->value['warnings'] ) ) {
+                               $warnings = $this->transformWarnings( $progress['status']->value['warnings'] );
+                               if ( $warnings ) {
+                                       $progress['warnings'] = $warnings;
+                               }
+                       }
                        unset( $progress['status'] ); // remove Status object
                        $this->getResult()->addValue( null, $this->getModuleName(), $progress );
 
@@ -421,7 +456,7 @@ class ApiUpload extends ApiBase {
 
                if ( $this->mParams['chunk'] ) {
                        // Chunk upload
-                       $this->mUpload = new UploadFromChunks();
+                       $this->mUpload = new UploadFromChunks( $this->getUser() );
                        if ( isset( $this->mParams['filekey'] ) ) {
                                if ( $this->mParams['offset'] === 0 ) {
                                        $this->dieUsage( 'Cannot supply a filekey when offset is 0', 'badparams' );
@@ -712,7 +747,7 @@ class ApiUpload extends ApiBase {
                        $this->mParams['text'] = $this->mParams['comment'];
                }
 
-               /** @var $file File */
+               /** @var $file LocalFile */
                $file = $this->mUpload->getLocalFile();
 
                // For preferences mode, we want to watch if 'watchdefault' is set,
index eacc00d..4678504 100644 (file)
@@ -47,5 +47,6 @@
        "apihelp-move-param-ignorewarnings": "Пренебрегване на всякакви предупреждения.",
        "apihelp-protect-example-protect": "Защита на страница.",
        "apihelp-query+langlinks-paramvalue-prop-url": "Добавя пълният URL-адрес.",
-       "apihelp-query+linkshere-paramvalue-prop-title": "Заглавие на всяка страница."
+       "apihelp-query+linkshere-paramvalue-prop-title": "Заглавие на всяка страница.",
+       "apihelp-query+watchlist-paramvalue-type-log": "Записи в дневника."
 }
index b34131b..4b42964 100644 (file)
@@ -25,7 +25,8 @@
                        "Lbayle",
                        "Verdy p",
                        "Yasten",
-                       "Trial"
+                       "Trial",
+                       "Pols12"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentation]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Liste de diffusion]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annonces de l’API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bogues et demandes]\n</div>\n<strong>État :</strong> Toutes les fonctionnalités affichées sur cette page devraient fonctionner, mais l’API est encore en cours de développement et peut changer à tout moment. Inscrivez-vous à [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la liste de diffusion mediawiki-api-announce] pour être informé des mises à jour.\n\n<strong>Requêtes erronées :</strong> Si des requêtes erronées sont envoyées à l’API, un en-tête HTTP sera renvoyé avec la clé « MediaWiki-API-Error ». La valeur de cet en-tête et le code d’erreur renvoyé prendront la même valeur. Pour plus d’information, voyez [[mw:API:Errors_and_warnings|API: Errors and warnings]].\n\n<strong>Test :</strong> Pour faciliter le test des requêtes de l’API, voyez [[Special:ApiSandbox]].",
        "apihelp-stashedit-param-section": "Numéro de section. <kbd>0</kbd> pour la section du haut, <kbd>new</kbd> pour une nouvelle section.",
        "apihelp-stashedit-param-sectiontitle": "Le titre pour une nouvelle section.",
        "apihelp-stashedit-param-text": "Contenu de la page.",
-       "apihelp-stashedit-param-stashedtexthash": "Hachage du contenu de la page d’une réserve antérieure à utiliser à la place.",
+       "apihelp-stashedit-param-stashedtexthash": "Empreinte du contenu de la page venant d’une réserve préalable à utiliser à la place.",
        "apihelp-stashedit-param-contentmodel": "Modèle de contenu du nouveau contenu.",
        "apihelp-stashedit-param-contentformat": "Format de sérialisation de contenu utilisé pour le texte saisi.",
        "apihelp-stashedit-param-baserevid": "ID de révision de la révision de base.",
index d999a7f..b752751 100644 (file)
        "api-help-permissions-granted-to": "{{PLURAL:$1|Concedida a|Concedidas a}}: $2",
        "api-help-right-apihighlimits": "Usar os valores superiores das consultas da API (consultas lentas: $1; consultas rápidas: $2). Os límites para as consultas lentas tamén se aplican ós parámetros multivaluados.",
        "api-help-open-in-apisandbox": "<small>[abrir en zona de probas]</small>",
+       "api-help-authmanager-general-usage": "O procedemento xeral para usar este módulo é:\n# Buscar os campos dispoñibles dende <kbd>[[Special:ApiHelp/query+authmanagerinfo|\n\naction=query&meta=authmanagerinfo]]</kbd> con <kbd>amirequestsfor=$4</kbd>, e un identificador <kbd>$5</kbd> de <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.\n# Presentar os campos ó usuario, e obter o seu envío.\n# Enviar a este módulo, proporcionando <var>$1returnurl</var> e calquera campo relevante.\n# Comprobar o <samp>status</samp> na resposta.\n#* Se vostede recibe <samp>PASS</samp> ou <samp>FAIL</samp>, a acción rematou. A operación foi correcta ou non se fixo.\n#* Se vostede recibe <samp>UI</samp>, presenta os novos campos ó usuario e obtén o seu envío. Logo son enviados a este módulo con <var>$1continue</var> e o conxunto de campos relevantes, e repite o paso 4.\n#* Se vostede recibe <samp>REDIRECT</samp>, dirixe ó usuario a <samp>redirecttarget</samp> e espera pola resposta a <var>$1returnurl</var>. Logo envíaa a este módulo con <var>$1continue</var> e calquera campo pasado á URL de volta, e repite o paso 4.\n#* Se recibe <samp>RESTART</samp>, isto significa que a autenticación funcionou pero que non temos unha conta de usuario ligada. Debe tratar isto igual que <samp>UI</samp> ou como <samp>FAIL</samp>.",
        "api-help-authmanagerhelper-requests": "Só usar estas peticións de autenticación, co <samp>id</samp> devolto por <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> con <kbd>amirequestsfor=$1</kbd> ou dunha resposta previa deste módulo.",
        "api-help-authmanagerhelper-request": "Usar esta petición de autenticación, co <samp>id</samp> devolto por <kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd> con <kbd>amirequestsfor=$1</kbd>.",
        "api-help-authmanagerhelper-messageformat": "Formato a usar para devolver as mensaxes.",
index 08a27d6..a28cbda 100644 (file)
        "apihelp-linkaccount-example-link": "תחילת תהליך הקישור לחשבון מ־<kbd>Example</kbd>.",
        "apihelp-login-description": "להיכנס ולקבל עוגיות אימות.\n\nהפעולה הזאת צריכה לשמש רק בשילוב [[Special:BotPasswords]]; שימוש לכניסה לחשבון ראשי מיושן ועשוי להיכשל ללא אזהרה. כדי להיכנס בבטחה לחשבון הראשי, יש להשתמש ב־<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-description-nobotpasswords": "להיכנס ולקבל עוגיות אימות.\n\nהפעולה הזאת מיושנת ועשויה להיכשל ללא אזהרה. כדי להיכנס בבטחה, יש להשתמש ב־<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
-       "apihelp-login-description-nonauthmanager": "להיכנס ולקבל עוגיות אימות.\n\nבמקרה של כניסה מוצלחת, העוגיות המקוננות תיכללנה בכותרות תשובות ה־HTTP. במקרה של כניסה כושלת, הניסיונות הבאים יוגבלו למספר ניסויי ניחוש הססמה האוטומטיים.",
        "apihelp-login-param-name": "שם משתמש.",
        "apihelp-login-param-password": "ססמה.",
        "apihelp-login-param-domain": "שם מתחם (רשות).",
        "apihelp-stashedit-param-section": "מספר הפסקה. <kbd>0</kbd> עבור הפסקה הראשונה, <kbd>new</kbd> עבור פסקה חדשה.",
        "apihelp-stashedit-param-sectiontitle": "כותרת הפסקה החדשה.",
        "apihelp-stashedit-param-text": "תוכן הדף.",
+       "apihelp-stashedit-param-stashedtexthash": "גיבוב של תוכן דף מסליק קודם שישמש במקום זה.",
        "apihelp-stashedit-param-contentmodel": "מודל התוכן של התוכן החדש.",
        "apihelp-stashedit-param-contentformat": "תסדיר הסדרת תוכן עבור טקסט הקלט.",
        "apihelp-stashedit-param-baserevid": "מזהה גסה של גרסת הבסיס.",
index 7334fab..e0920f6 100644 (file)
@@ -6,7 +6,8 @@
                        "Tacsipacsi",
                        "ViDam",
                        "Macofe",
-                       "Wolf Rex"
+                       "Wolf Rex",
+                       "Dj"
                ]
        },
        "apihelp-main-param-action": "Milyen műveletet hajtson végre.",
@@ -42,6 +43,7 @@
        "apihelp-feedrecentchanges-param-hidepatrolled": "Ellenőrzött változtatások elrejtése.",
        "apihelp-login-param-name": "Szerkesztőnév.",
        "apihelp-login-param-password": "Jelszó.",
+       "apihelp-login-param-domain": "Tartomány (opcionális)",
        "apihelp-login-example-login": "Bejelentkezés.",
        "apihelp-logout-example-logout": "Aktuális felhasználó kijelentkeztetése.",
        "apihelp-mergehistory-description": "Laptörténetek egyesítése",
index 02e54c8..860b7a7 100644 (file)
        "apihelp-query+random-param-filterredir": "如何过滤重定向。",
        "apihelp-query+random-example-simple": "从主名字空间返回两个随机页面。",
        "apihelp-query+random-example-generator": "返回有关来自主名字空间的两个随机页面的页面信息。",
-       "apihelp-query+recentchanges-description": "举最近更改。",
+       "apihelp-query+recentchanges-description": "举最近更改。",
        "apihelp-query+recentchanges-param-start": "枚举的起始时间戳。",
        "apihelp-query+recentchanges-param-end": "枚举的结束时间戳。",
        "apihelp-query+recentchanges-param-namespace": "过滤更改为仅限这些名字空间。",
        "apihelp-query+recentchanges-paramvalue-prop-ids": "添加页面ID、最近更改ID和新旧修订的ID。",
        "apihelp-query+recentchanges-paramvalue-prop-sizes": "添加新旧页面长度(字节)。",
        "apihelp-query+recentchanges-paramvalue-prop-redirect": "如果页面是重定向的话,标记编辑。",
-       "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Tags patrollable edits as being patrolled or unpatrolled.",
+       "apihelp-query+recentchanges-paramvalue-prop-patrolled": "将可巡查编辑标记为已巡查或未巡查。",
        "apihelp-query+recentchanges-paramvalue-prop-loginfo": "添加日志信息(日志ID、日志类型等)至日志记录。",
        "apihelp-query+recentchanges-paramvalue-prop-tags": "列举条目的标签。",
        "apihelp-query+recentchanges-paramvalue-prop-sha1": "Adds the content checksum for entries associated with a revision.",
        "apihelp-query+search-paramvalue-prop-snippet": "Adds a parsed snippet of the page.",
        "apihelp-query+search-paramvalue-prop-titlesnippet": "Adds a parsed snippet of the page title.",
        "apihelp-query+search-paramvalue-prop-redirectsnippet": "添加被解析的重定向标题的片段。",
-       "apihelp-query+search-paramvalue-prop-redirecttitle": "Adds the title of the matching redirect.",
+       "apihelp-query+search-paramvalue-prop-redirecttitle": "添加匹配的重定向的标题。",
        "apihelp-query+search-paramvalue-prop-sectionsnippet": "Adds a parsed snippet of the matching section title.",
        "apihelp-query+search-paramvalue-prop-sectiontitle": "Adds the title of the matching section.",
        "apihelp-query+search-paramvalue-prop-categorysnippet": "Adds a parsed snippet of the matching category.",
        "apihelp-query+search-param-enablerewrites": "启用内部查询重写。一些搜索后端可以重写查询到它认为会给出更好结果的地方,例如纠正拼写错误。",
        "apihelp-query+search-example-simple": "搜索<kbd>meaning</kbd>。",
        "apihelp-query+search-example-text": "搜索文本<kbd>meaning</kbd>。",
-       "apihelp-query+search-example-generator": "è\8e·å¾\97有关搜索<kbd>meaning</kbd>返回页面的页面信息。",
+       "apihelp-query+search-example-generator": "è\8e·å\8f\96有关搜索<kbd>meaning</kbd>返回页面的页面信息。",
        "apihelp-query+siteinfo-description": "返回有关网站的一般信息。",
        "apihelp-query+siteinfo-param-prop": "要获取的信息:",
        "apihelp-query+siteinfo-paramvalue-prop-general": "全部系统信息。",
index eab5068..acdc01b 100644 (file)
@@ -1605,9 +1605,6 @@ class AuthManager implements LoggerAwareInterface {
                        }
                }
 
-               // Ignore warnings about master connections/writes...hard to avoid here
-               \Profiler::instance()->getTransactionProfiler()->resetExpectations();
-
                $backoffKey = wfMemcKey( 'AuthManager', 'autocreate-failed', md5( $username ) );
                if ( $cache->get( $backoffKey ) ) {
                        $this->logger->debug( __METHOD__ . ': {username} denied by prior creation attempt failures', [
@@ -1625,6 +1622,9 @@ class AuthManager implements LoggerAwareInterface {
                        'from' => $from,
                ] );
 
+               // Ignore warnings about master connections/writes...hard to avoid here
+               $trxProfiler = \Profiler::instance()->getTransactionProfiler();
+               $trxProfiler->setSilenced( true );
                try {
                        $status = $user->addToDatabase();
                        if ( !$status->isOk() ) {
@@ -1652,6 +1652,7 @@ class AuthManager implements LoggerAwareInterface {
                                return $status;
                        }
                } catch ( \Exception $ex ) {
+                       $trxProfiler->setSilenced( false );
                        $this->logger->error( __METHOD__ . ': {username} failed with exception {exception}', [
                                'username' => $username,
                                'exception' => $ex,
@@ -1673,9 +1674,10 @@ class AuthManager implements LoggerAwareInterface {
 
                // Update user count
                \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
-
                // Watch user's userpage and talk page
-               $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
+               \DeferredUpdates::addCallableUpdate( function () use ( $user ) {
+                       $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
+               } );
 
                // Log the creation
                if ( $this->config->get( 'NewUserLog' ) ) {
@@ -1686,12 +1688,10 @@ class AuthManager implements LoggerAwareInterface {
                        $logEntry->setParameters( [
                                '4::userid' => $user->getId(),
                        ] );
-                       $logid = $logEntry->insert();
+                       $logEntry->insert();
                }
 
-               // Commit database changes, so even if something else later blows up
-               // the newly-created user doesn't get lost.
-               wfGetLBFactory()->commitMasterChanges( __METHOD__ );
+               $trxProfiler->setSilenced( false );
 
                if ( $login ) {
                        $this->setSessionDataForUser( $user );
@@ -2022,37 +2022,26 @@ class AuthManager implements LoggerAwareInterface {
 
                // Query them and merge results
                $reqs = [];
-               $allPrimaryRequired = null;
                foreach ( $providers as $provider ) {
                        $isPrimary = $provider instanceof PrimaryAuthenticationProvider;
-                       $thisRequired = [];
                        foreach ( $provider->getAuthenticationRequests( $providerAction, $options ) as $req ) {
                                $id = $req->getUniqueId();
 
-                               // If it's from a Primary, mark it as "primary-required" but
-                               // track it for later.
+                               // If a required request if from a Primary, mark it as "primary-required" instead
                                if ( $isPrimary ) {
                                        if ( $req->required ) {
-                                               $thisRequired[$id] = true;
                                                $req->required = AuthenticationRequest::PRIMARY_REQUIRED;
                                        }
                                }
 
-                               if ( !isset( $reqs[$id] ) || $req->required === AuthenticationRequest::REQUIRED ) {
+                               if (
+                                       !isset( $reqs[$id] )
+                                       || $req->required === AuthenticationRequest::REQUIRED
+                                       || $reqs[$id] === AuthenticationRequest::OPTIONAL
+                               ) {
                                        $reqs[$id] = $req;
                                }
                        }
-
-                       // Track which requests are required by all primaries
-                       if ( $isPrimary ) {
-                               $allPrimaryRequired = $allPrimaryRequired === null
-                                       ? $thisRequired
-                                       : array_intersect_key( $allPrimaryRequired, $thisRequired );
-                       }
-               }
-               // Any requests that were required by all primaries are required.
-               foreach ( (array)$allPrimaryRequired as $id => $dummy ) {
-                       $reqs[$id]->required = AuthenticationRequest::REQUIRED;
                }
 
                // AuthManager has its own req for some actions
index ff4d52e..2474b8b 100644 (file)
@@ -43,7 +43,8 @@ abstract class AuthenticationRequest {
        const REQUIRED = 1;
 
        /** Indicates that the request is required by a primary authentication
-        * provdier, but other primary authentication providers do not require it. */
+        * provdier. Since the user can choose which primary to authenticate with,
+        * the request might or might not end up being actually required. */
        const PRIMARY_REQUIRED = 2;
 
        /** @var string|null The AuthManager::ACTION_* constant this request was
@@ -101,6 +102,8 @@ abstract class AuthenticationRequest {
         *  - label: (Message) Text suitable for a label in an HTML form
         *  - help: (Message) Text suitable as a description of what the field is
         *  - optional: (bool) If set and truthy, the field may be left empty
+        *  - sensitive: (bool) If set and truthy, the field is considered sensitive. Code using the
+        *      request should avoid exposing the value of the field.
         *
         * @return array As above
         */
@@ -314,6 +317,8 @@ abstract class AuthenticationRequest {
                                        $options['optional'] = !empty( $options['optional'] );
                                }
 
+                               $options['sensitive'] = !empty( $options['sensitive'] );
+
                                if ( !array_key_exists( $name, $merged ) ) {
                                        $merged[$name] = $options;
                                } elseif ( $merged[$name]['type'] !== $options['type'] ) {
@@ -332,6 +337,7 @@ abstract class AuthenticationRequest {
                                        }
 
                                        $merged[$name]['optional'] = $merged[$name]['optional'] && $options['optional'];
+                                       $merged[$name]['sensitive'] = $merged[$name]['sensitive'] || $options['sensitive'];
 
                                        // No way to merge 'value', 'image', 'help', or 'label', so just use
                                        // the value from the first request.
index 187c29a..8550f3e 100644 (file)
@@ -53,6 +53,7 @@ class PasswordAuthenticationRequest extends AuthenticationRequest {
                                'type' => 'password',
                                'label' => wfMessage( $passwordLabel ),
                                'help' => wfMessage( 'authmanager-password-help' ),
+                               'sensitive' => true,
                        ],
                ];
 
@@ -68,6 +69,7 @@ class PasswordAuthenticationRequest extends AuthenticationRequest {
                                'type' => 'password',
                                'label' => wfMessage( $retypeLabel ),
                                'help' => wfMessage( 'authmanager-retype-help' ),
+                               'sensitive' => true,
                        ];
                }
 
index c44c8fc..35f3287 100644 (file)
@@ -57,6 +57,14 @@ interface PrimaryAuthenticationProvider extends AuthenticationProvider {
        /** Provider cannot create or link to accounts */
        const TYPE_NONE = 'none';
 
+       /**
+        * {@inheritdoc}
+        *
+        * Of the requests returned by this method, exactly one should have
+        * {@link AuthenticationRequest::$required} set to REQUIRED.
+        */
+       public function getAuthenticationRequests( $action, array $options );
+
        /**
         * Start an authentication flow
         *
index 46cbab5..ed94c1a 100644 (file)
@@ -303,7 +303,11 @@ class TemporaryPasswordPrimaryAuthenticationProvider
                );
 
                if ( $sendMail ) {
-                       $this->sendPasswordResetEmail( $req );
+                       // Send email after DB commit
+                       $dbw->onTransactionIdle( function () use ( $req ) {
+                               /** @var TemporaryPasswordAuthenticationRequest $req */
+                               $this->sendPasswordResetEmail( $req );
+                       } );
                }
        }
 
@@ -370,7 +374,10 @@ class TemporaryPasswordPrimaryAuthenticationProvider
                $this->providerChangeAuthenticationData( $req );
 
                if ( $mailpassword ) {
-                       $this->sendNewAccountEmail( $user, $creator, $req->password );
+                       // Send email after DB commit
+                       wfGetDB( DB_MASTER )->onTransactionIdle( function () use ( $user, $creator, $req ) {
+                               $this->sendNewAccountEmail( $user, $creator, $req->password );
+                       } );
                }
 
                return $mailpassword ? 'byemail' : null;
index 361fe23..8c2a19e 100644 (file)
@@ -48,7 +48,7 @@ class BacklinkCache {
         *  > (string) links table name
         *   > (int) batch size
         *    > 'numRows' : Number of rows for this link table
-        *    > 'batches' : array( $start, $end )
+        *    > 'batches' : [ $start, $end ]
         *
         * @see BacklinkCache::partitionResult()
         *
index 159cfd9..daf76df 100644 (file)
@@ -589,16 +589,20 @@ class RecentChange {
                        'pageStatus' => 'changed'
                ];
 
-               DeferredUpdates::addCallableUpdate( function() use ( $rc, $tags ) {
-                       $rc->save();
-                       if ( $rc->mAttribs['rc_patrolled'] ) {
-                               PatrolLog::record( $rc, true, $rc->getPerformer() );
-                       }
-                       if ( count( $tags ) ) {
-                               ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
-                                       $rc->mAttribs['rc_this_oldid'], null, null );
-                       }
-               } );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $rc, $tags ) {
+                               $rc->save();
+                               if ( $rc->mAttribs['rc_patrolled'] ) {
+                                       PatrolLog::record( $rc, true, $rc->getPerformer() );
+                               }
+                               if ( count( $tags ) ) {
+                                       ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
+                                               $rc->mAttribs['rc_this_oldid'], null, null );
+                               }
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
 
                return $rc;
        }
@@ -661,16 +665,20 @@ class RecentChange {
                        'pageStatus' => 'created'
                ];
 
-               DeferredUpdates::addCallableUpdate( function() use ( $rc, $tags ) {
-                       $rc->save();
-                       if ( $rc->mAttribs['rc_patrolled'] ) {
-                               PatrolLog::record( $rc, true, $rc->getPerformer() );
-                       }
-                       if ( count( $tags ) ) {
-                               ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
-                                       $rc->mAttribs['rc_this_oldid'], null, null );
-                       }
-               } );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $rc, $tags ) {
+                               $rc->save();
+                               if ( $rc->mAttribs['rc_patrolled'] ) {
+                                       PatrolLog::record( $rc, true, $rc->getPerformer() );
+                               }
+                               if ( count( $tags ) ) {
+                                       ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
+                                               $rc->mAttribs['rc_this_oldid'], null, null );
+                               }
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
 
                return $rc;
        }
index 2bbf6ca..20893bb 100644 (file)
@@ -64,11 +64,4 @@ abstract class CodeContentHandler extends TextContentHandler {
                throw new MWException( 'Subclass must override' );
        }
 
-       /**
-        * @param SearchEngine $engine
-        * @return array
-        */
-       public function getFieldsForSearchIndex( SearchEngine $engine ) {
-               return [];
-       }
 }
index 7184980..5a5c0d8 100644 (file)
@@ -1156,62 +1156,19 @@ abstract class ContentHandler {
         *
         * @param string $event Event name
         * @param array $args Parameters passed to hook functions
-        * @param bool $warn Whether to log a warning.
-        *                    Default to self::$enableDeprecationWarnings.
-        *                    May be set to false for testing.
+        * @param string|null $deprecatedVersion Emit a deprecation notice
+        *   when the hook is run for the provided version
         *
         * @return bool True if no handler aborted the hook
-        *
-        * @see ContentHandler::$enableDeprecationWarnings
         */
        public static function runLegacyHooks( $event, $args = [],
-               $warn = null
+               $deprecatedVersion = null
        ) {
 
-               if ( $warn === null ) {
-                       $warn = self::$enableDeprecationWarnings;
-               }
-
                if ( !Hooks::isRegistered( $event ) ) {
                        return true; // nothing to do here
                }
 
-               if ( $warn ) {
-                       // Log information about which handlers are registered for the legacy hook,
-                       // so we can find and fix them.
-
-                       $handlers = Hooks::getHandlers( $event );
-                       $handlerInfo = [];
-
-                       MediaWiki\suppressWarnings();
-
-                       foreach ( $handlers as $handler ) {
-                               if ( is_array( $handler ) ) {
-                                       if ( is_object( $handler[0] ) ) {
-                                               $info = get_class( $handler[0] );
-                                       } else {
-                                               $info = $handler[0];
-                                       }
-
-                                       if ( isset( $handler[1] ) ) {
-                                               $info .= '::' . $handler[1];
-                                       }
-                               } elseif ( is_object( $handler ) ) {
-                                       $info = get_class( $handler[0] );
-                                       $info .= '::on' . $event;
-                               } else {
-                                       $info = $handler;
-                               }
-
-                               $handlerInfo[] = $info;
-                       }
-
-                       MediaWiki\restoreWarnings();
-
-                       wfWarn( "Using obsolete hook $event via ContentHandler::runLegacyHooks()! Handlers: " .
-                               implode( ', ', $handlerInfo ), 2 );
-               }
-
                // convert Content objects to text
                $contentObjects = [];
                $contentTexts = [];
@@ -1229,7 +1186,7 @@ abstract class ContentHandler {
                }
 
                // call the hook functions
-               $ok = Hooks::run( $event, $args );
+               $ok = Hooks::run( $event, $args, $deprecatedVersion );
 
                // see if the hook changed the text
                foreach ( $contentTexts as $k => $orig ) {
index 845e39c..9c11035 100644 (file)
@@ -37,7 +37,7 @@ class CssContentHandler extends CodeContentHandler {
        }
 
        protected function getContentClass() {
-               return 'CssContent';
+               return CssContent::class;
        }
 
        public function supportsRedirects() {
index b082b32..9abad3e 100644 (file)
@@ -39,7 +39,7 @@ class JavaScriptContentHandler extends CodeContentHandler {
         * @return string
         */
        protected function getContentClass() {
-               return 'JavaScriptContent';
+               return JavaScriptContent::class;
        }
 
        public function supportsRedirects() {
index f97eaa4..eb1c67d 100644 (file)
@@ -37,6 +37,6 @@ class JsonContentHandler extends CodeContentHandler {
         * @return string
         */
        protected function getContentClass() {
-               return 'JsonContent';
+               return JsonContent::class;
        }
 }
index 225522e..de650b9 100644 (file)
@@ -149,7 +149,7 @@ class TextContent extends AbstractContent {
 
        /**
         * Returns a Content object with pre-save transformations applied.
-        * This implementation just trims trailing whitespace.
+        * This implementation just trims trailing whitespace and normalizes newlines.
         *
         * @param Title $title
         * @param User $user
@@ -160,6 +160,7 @@ class TextContent extends AbstractContent {
        public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
                $text = $this->getNativeData();
                $pst = rtrim( $text );
+               $pst = str_replace( [ "\r\n", "\r" ], "\n", $pst );
 
                return ( $text === $pst ) ? $this : new static( $pst, $this->getModel() );
        }
index d4fad44..09cdcee 100644 (file)
@@ -101,7 +101,7 @@ class TextContentHandler extends ContentHandler {
         * @return string
         */
        protected function getContentClass() {
-               return 'TextContent';
+               return TextContent::class;
        }
 
        /**
@@ -143,9 +143,10 @@ class TextContentHandler extends ContentHandler {
        }
 
        public function getFieldsForSearchIndex( SearchEngine $engine ) {
-               $fields = [];
+               $fields = parent::getFieldsForSearchIndex( $engine );
                $fields['language'] =
                        $engine->makeSearchFieldMapping( 'language', SearchIndexField::INDEX_TYPE_KEYWORD );
+
                return $fields;
        }
 
index 5c0a9c8..3ad7665 100644 (file)
@@ -35,7 +35,7 @@ class WikitextContentHandler extends TextContentHandler {
        }
 
        protected function getContentClass() {
-               return 'WikitextContent';
+               return WikitextContent::class;
        }
 
        /**
@@ -109,7 +109,7 @@ class WikitextContentHandler extends TextContentHandler {
        }
 
        public function getFieldsForSearchIndex( SearchEngine $engine ) {
-               $fields = [];
+               $fields = parent::getFieldsForSearchIndex( $engine );
 
                $fields['category'] =
                        $engine->makeSearchFieldMapping( 'category', SearchIndexField::INDEX_TYPE_TEXT );
@@ -154,7 +154,11 @@ class WikitextContentHandler extends TextContentHandler {
        protected function getFileText( Title $title ) {
                $file = wfLocalFile( $title );
                if ( $file && $file->exists() ) {
-                       return $file->getHandler()->getEntireText( $file );
+                       $handler = $file->getHandler();
+                       if ( !$handler ) {
+                               return null;
+                       }
+                       return $handler->getEntireText( $file );
                }
 
                return null;
index 53862b9..4a78363 100644 (file)
@@ -445,7 +445,7 @@ class DBConnRef implements IDatabase {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
-       public function begin( $fname = __METHOD__ ) {
+       public function begin( $fname = __METHOD__, $mode = IDatabase::TRANSACTION_EXPLICIT ) {
                return $this->__call( __FUNCTION__, func_get_args() );
        }
 
index 4e358d4..933bea6 100644 (file)
@@ -703,7 +703,7 @@ abstract class DatabaseBase implements IDatabase {
                                                " performing implicit commit before closing connection!" );
                                }
 
-                               $this->commit( __METHOD__, 'flush' );
+                               $this->commit( __METHOD__, self::FLUSHING_INTERNAL );
                        }
 
                        $closed = $this->closeConnection();
@@ -815,7 +815,7 @@ abstract class DatabaseBase implements IDatabase {
                if ( !$this->mTrxLevel && $this->getFlag( DBO_TRX )
                        && $this->isTransactableQuery( $sql )
                ) {
-                       $this->begin( __METHOD__ . " ($fname)" );
+                       $this->begin( __METHOD__ . " ($fname)", self::TRANSACTION_INTERNAL );
                        $this->mTrxAutomatic = true;
                }
 
@@ -1864,7 +1864,7 @@ abstract class DatabaseBase implements IDatabase {
        /**
         * Gets an array of aliased table names
         *
-        * @param array $tables Array( [alias] => table )
+        * @param array $tables [ [alias] => table ]
         * @return string[] See tableNameWithAlias()
         */
        public function tableNamesWithAlias( $tables ) {
@@ -1898,7 +1898,7 @@ abstract class DatabaseBase implements IDatabase {
        /**
         * Gets an array of aliased field names
         *
-        * @param array $fields Array( [alias] => field )
+        * @param array $fields [ [alias] => field ]
         * @return string[] See fieldNameWithAlias()
         */
        public function fieldNamesWithAlias( $fields ) {
@@ -2203,7 +2203,7 @@ abstract class DatabaseBase implements IDatabase {
 
                $useTrx = !$this->mTrxLevel;
                if ( $useTrx ) {
-                       $this->begin( $fname );
+                       $this->begin( $fname, self::TRANSACTION_INTERNAL );
                }
                try {
                        # Update any existing conflicting row(s)
@@ -2221,7 +2221,7 @@ abstract class DatabaseBase implements IDatabase {
                        throw $e;
                }
                if ( $useTrx ) {
-                       $this->commit( $fname );
+                       $this->commit( $fname, self::TRANSACTION_INTERNAL );
                }
 
                return $ok;
@@ -2520,7 +2520,7 @@ abstract class DatabaseBase implements IDatabase {
                        $this->mTrxPreCommitCallbacks[] = [ $callback, wfGetCaller() ];
                } else {
                        // If no transaction is active, then make one for this callback
-                       $this->begin( __METHOD__ );
+                       $this->begin( __METHOD__, self::TRANSACTION_INTERNAL );
                        try {
                                call_user_func( $callback );
                                $this->commit( __METHOD__ );
@@ -2628,7 +2628,7 @@ abstract class DatabaseBase implements IDatabase {
 
        final public function startAtomic( $fname = __METHOD__ ) {
                if ( !$this->mTrxLevel ) {
-                       $this->begin( $fname );
+                       $this->begin( $fname, self::TRANSACTION_INTERNAL );
                        $this->mTrxAutomatic = true;
                        // If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
                        // in all changes being in one transaction to keep requests transactional.
@@ -2651,58 +2651,43 @@ abstract class DatabaseBase implements IDatabase {
                }
 
                if ( !$this->mTrxAtomicLevels && $this->mTrxAutomaticAtomic ) {
-                       $this->commit( $fname, 'flush' );
+                       $this->commit( $fname, self::FLUSHING_INTERNAL );
                }
        }
 
        final public function doAtomicSection( $fname, callable $callback ) {
                $this->startAtomic( $fname );
                try {
-                       call_user_func_array( $callback, [ $this, $fname ] );
+                       $res = call_user_func_array( $callback, [ $this, $fname ] );
                } catch ( Exception $e ) {
                        $this->rollback( $fname );
                        throw $e;
                }
                $this->endAtomic( $fname );
+
+               return $res;
        }
 
-       final public function begin( $fname = __METHOD__ ) {
-               if ( $this->mTrxLevel ) { // implicit commit
+       final public function begin( $fname = __METHOD__, $mode = self::TRANSACTION_EXPLICIT ) {
+               // Protect against mismatched atomic section, transaction nesting, and snapshot loss
+               if ( $this->mTrxLevel ) {
                        if ( $this->mTrxAtomicLevels ) {
-                               // If the current transaction was an automatic atomic one, then we definitely have
-                               // a problem. Same if there is any unclosed atomic level.
                                $levels = implode( ', ', $this->mTrxAtomicLevels );
-                               throw new DBUnexpectedError(
-                                       $this,
-                                       "Got explicit BEGIN from $fname while atomic section(s) $levels are open."
-                               );
+                               $msg = "$fname: Got explicit BEGIN while atomic section(s) $levels are open.";
+                               throw new DBUnexpectedError( $this, $msg );
                        } elseif ( !$this->mTrxAutomatic ) {
-                               // We want to warn about inadvertently nested begin/commit pairs, but not about
-                               // auto-committing implicit transactions that were started by query() via DBO_TRX
-                               throw new DBUnexpectedError(
-                                       $this,
-                                       "$fname: Transaction already in progress (from {$this->mTrxFname}), " .
-                                               " performing implicit commit!"
-                               );
-                       } elseif ( $this->mTrxDoneWrites ) {
-                               // The transaction was automatic and has done write operations
-                               throw new DBUnexpectedError(
-                                       $this,
-                                       "$fname: Automatic transaction with writes in progress" .
-                                               " (from {$this->mTrxFname}), performing implicit commit!\n"
-                               );
-                       }
-
-                       $this->runOnTransactionPreCommitCallbacks();
-                       $writeTime = $this->pendingWriteQueryDuration();
-                       $this->doCommit( $fname );
-                       if ( $this->mTrxDoneWrites ) {
-                               $this->mDoneWrites = microtime( true );
-                               $this->getTransactionProfiler()->transactionWritingOut(
-                                       $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
+                               $msg = "$fname: Explicit transaction already active (from {$this->mTrxFname}).";
+                               throw new DBUnexpectedError( $this, $msg );
+                       } else {
+                               // @TODO: make this an exception at some point
+                               $msg = "$fname: Implicit transaction already active (from {$this->mTrxFname}).";
+                               wfLogDBError( $msg );
+                               return; // join the main transaction set
                        }
-
-                       $this->runOnTransactionIdleCallbacks( self::TRIGGER_COMMIT );
+               } elseif ( $this->getFlag( DBO_TRX ) && $mode !== self::TRANSACTION_INTERNAL ) {
+                       // @TODO: make this an exception at some point
+                       wfLogDBError( "$fname: Implicit transaction expected (DBO_TRX set)." );
+                       return; // let any writes be in the main transaction
                }
 
                // Avoid fatals if close() was called
@@ -2742,28 +2727,27 @@ abstract class DatabaseBase implements IDatabase {
                        $levels = implode( ', ', $this->mTrxAtomicLevels );
                        throw new DBUnexpectedError(
                                $this,
-                               "Got COMMIT while atomic sections $levels are still open"
+                               "$fname: Got COMMIT while atomic sections $levels are still open."
                        );
                }
 
-               if ( $flush === 'flush' ) {
+               if ( $flush === self::FLUSHING_INTERNAL || $flush === self::FLUSHING_ALL_PEERS ) {
                        if ( !$this->mTrxLevel ) {
                                return; // nothing to do
                        } elseif ( !$this->mTrxAutomatic ) {
                                throw new DBUnexpectedError(
                                        $this,
-                                       "$fname: Flushing an explicit transaction, getting out of sync!"
+                                       "$fname: Flushing an explicit transaction, getting out of sync."
                                );
                        }
                } else {
                        if ( !$this->mTrxLevel ) {
-                               wfWarn( "$fname: No transaction to commit, something got out of sync!" );
+                               wfWarn( "$fname: No transaction to commit, something got out of sync." );
                                return; // nothing to do
                        } elseif ( $this->mTrxAutomatic ) {
-                               throw new DBUnexpectedError(
-                                       $this,
-                                       "$fname: Explicit commit of implicit transaction."
-                               );
+                               // @TODO: make this an exception at some point
+                               wfLogDBError( "$fname: Explicit commit of implicit transaction." );
+                               return; // wait for the main transaction set commit round
                        }
                }
 
@@ -2796,14 +2780,19 @@ abstract class DatabaseBase implements IDatabase {
        }
 
        final public function rollback( $fname = __METHOD__, $flush = '' ) {
-               if ( $flush !== 'flush' ) {
+               if ( $flush === self::FLUSHING_INTERNAL || $flush === self::FLUSHING_ALL_PEERS ) {
                        if ( !$this->mTrxLevel ) {
-                               wfWarn( "$fname: No transaction to rollback, something got out of sync!" );
                                return; // nothing to do
                        }
                } else {
                        if ( !$this->mTrxLevel ) {
+                               wfWarn( "$fname: No transaction to rollback, something got out of sync." );
                                return; // nothing to do
+                       } elseif ( $this->getFlag( DBO_TRX ) ) {
+                               throw new DBUnexpectedError(
+                                       $this,
+                                       "$fname: Expected mass rollback of all peer databases (DBO_TRX set)."
+                               );
                        }
                }
 
@@ -3297,16 +3286,32 @@ abstract class DatabaseBase implements IDatabase {
        }
 
        public function getScopedLockAndFlush( $lockKey, $fname, $timeout ) {
+               if ( $this->writesOrCallbacksPending() ) {
+                       // This only flushes transactions to clear snapshots, not to write data
+                       throw new DBUnexpectedError(
+                               $this,
+                               "$fname: Cannot COMMIT to clear snapshot because writes are pending."
+                       );
+               }
+
                if ( !$this->lock( $lockKey, $fname, $timeout ) ) {
                        return null;
                }
 
                $unlocker = new ScopedCallback( function () use ( $lockKey, $fname ) {
-                       $this->commit( __METHOD__, 'flush' );
-                       $this->unlock( $lockKey, $fname );
+                       if ( $this->trxLevel() ) {
+                               // There is a good chance an exception was thrown, causing any early return
+                               // from the caller. Let any error handler get a chance to issue rollback().
+                               // If there isn't one, let the error bubble up and trigger server-side rollback.
+                               $this->onTransactionResolution( function () use ( $lockKey, $fname ) {
+                                       $this->unlock( $lockKey, $fname );
+                               } );
+                       } else {
+                               $this->unlock( $lockKey, $fname );
+                       }
                } );
 
-               $this->commit( __METHOD__, 'flush' );
+               $this->commit( __METHOD__, self::FLUSHING_INTERNAL );
 
                return $unlocker;
        }
index 6380fe7..d1ebe62 100644 (file)
@@ -767,9 +767,6 @@ abstract class DatabaseMysqlBase extends Database {
                        return 0; // already reached this point for sure
                }
 
-               // Commit any open transactions
-               $this->commit( __METHOD__, 'flush' );
-
                // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
                if ( $this->useGTIDs && $pos->gtids ) {
                        // Wait on the GTID set (MariaDB only)
index 867aeb8..1ecdd26 100644 (file)
@@ -149,7 +149,7 @@ class SavepointPostgres {
                $this->didbegin = false;
                /* If we are not in a transaction, we need to be for savepoint trickery */
                if ( !$dbw->trxLevel() ) {
-                       $dbw->begin( "FOR SAVEPOINT" );
+                       $dbw->begin( "FOR SAVEPOINT", DatabasePostgres::TRANSACTION_INTERNAL );
                        $this->didbegin = true;
                }
        }
@@ -1207,7 +1207,7 @@ __INDEXATTR__;
         * @param string $desiredSchema
         */
        function determineCoreSchema( $desiredSchema ) {
-               $this->begin( __METHOD__ );
+               $this->begin( __METHOD__, self::TRANSACTION_INTERNAL );
                if ( $this->schemaExists( $desiredSchema ) ) {
                        if ( in_array( $desiredSchema, $this->getSchemas() ) ) {
                                $this->mCoreSchema = $desiredSchema;
index 9d0a0f7..5bbba88 100644 (file)
@@ -911,7 +911,7 @@ class DatabaseSqlite extends Database {
        public function lock( $lockName, $method, $timeout = 5 ) {
                if ( !is_dir( "{$this->dbDir}/locks" ) ) { // create dir as needed
                        if ( !is_writable( $this->dbDir ) || !mkdir( "{$this->dbDir}/locks" ) ) {
-                               throw new DBError( "Cannot create directory \"{$this->dbDir}/locks\"." );
+                               throw new DBError( $this, "Cannot create directory \"{$this->dbDir}/locks\"." );
                        }
                }
 
index 43592e2..bdab09e 100644 (file)
  * @ingroup Database
  */
 interface IDatabase {
-       /* Constants to onTransactionResolution() callbacks */
+       /** @var int Callback triggered immediately due to no active transaction */
        const TRIGGER_IDLE = 1;
+       /** @var int Callback triggered by commit */
        const TRIGGER_COMMIT = 2;
+       /** @var int Callback triggered by rollback */
        const TRIGGER_ROLLBACK = 3;
 
+       /** @var string Transaction is requested by regular caller outside of the DB layer */
+       const TRANSACTION_EXPLICIT = '';
+       /** @var string Transaction is requested interally via DBO_TRX/startAtomic() */
+       const TRANSACTION_INTERNAL = 'implicit';
+
+       /** @var string Transaction operation comes from service managing all DBs */
+       const FLUSHING_ALL_PEERS = 'flush';
+       /** @var string Transaction operation comes from the database class internally */
+       const FLUSHING_INTERNAL = 'flush';
+
        /**
         * A string describing the current software version, and possibly
         * other details in a user-friendly way. Will be listed on Special:Version, etc.
@@ -1335,6 +1347,7 @@ interface IDatabase {
         *
         * @param string $fname Caller name (usually __METHOD__)
         * @param callable $callback Callback that issues DB updates
+        * @return mixed $res Result of the callback (since 1.28)
         * @throws DBError
         * @throws RuntimeException
         * @throws UnexpectedValueException
@@ -1346,6 +1359,10 @@ interface IDatabase {
         * Begin a transaction. If a transaction is already in progress,
         * that transaction will be committed before the new transaction is started.
         *
+        * Only call this from code with outer transcation scope.
+        * See https://www.mediawiki.org/wiki/Database_transactions for details.
+        * Nesting of transactions is not supported.
+        *
         * Note that when the DBO_TRX flag is set (which is usually the case for web
         * requests, but not for maintenance scripts), any previous database query
         * will have started a transaction automatically.
@@ -1355,20 +1372,23 @@ interface IDatabase {
         * automatically because of the DBO_TRX flag.
         *
         * @param string $fname
+        * @param string $mode A situationally valid IDatabase::TRANSACTION_* constant [optional]
         * @throws DBError
         */
-       public function begin( $fname = __METHOD__ );
+       public function begin( $fname = __METHOD__, $mode = self::TRANSACTION_EXPLICIT );
 
        /**
         * Commits a transaction previously started using begin().
         * If no transaction is in progress, a warning is issued.
         *
+        * Only call this from code with outer transcation scope.
+        * See https://www.mediawiki.org/wiki/Database_transactions for details.
         * Nesting of transactions is not supported.
         *
         * @param string $fname
-        * @param string $flush Flush flag, set to 'flush' to disable warnings about
-        *   explicitly committing implicit transactions, or calling commit when no
-        *   transaction is in progress.
+        * @param string $flush Flush flag, set to situationally valid IDatabase::FLUSHING_*
+        *   constant to disable warnings about explicitly committing implicit transactions,
+        *   or calling commit when no transaction is in progress.
         *
         *   This will trigger an exception if there is an ongoing explicit transaction.
         *
@@ -1383,13 +1403,17 @@ interface IDatabase {
         * Rollback a transaction previously started using begin().
         * If no transaction is in progress, a warning is issued.
         *
-        * No-op on non-transactional databases.
+        * Only call this from code with outer transcation scope.
+        * See https://www.mediawiki.org/wiki/Database_transactions for details.
+        * Nesting of transactions is not supported. If a serious unexpected error occurs,
+        * throwing an Exception is preferrable, using a pre-installed error handler to trigger
+        * rollback (in any case, failure to issue COMMIT will cause rollback server-side).
         *
         * @param string $fname
-        * @param string $flush Flush flag, set to 'flush' to disable warnings about
-        *   calling rollback when no transaction is in progress. This will silently
-        *   break any ongoing explicit transaction. Only set the flush flag if you
-        *   are sure that it is safe to ignore these warnings in your context.
+        * @param string $flush Flush flag, set to a situationally valid IDatabase::FLUSHING_*
+        *   constant to disable warnings about calling rollback when no transaction is in
+        *   progress. This will silently break any ongoing explicit transaction. Only set the
+        *   flush flag if you are sure that it is safe to ignore these warnings in your context.
         * @throws DBUnexpectedError
         * @since 1.23 Added $flush parameter
         */
@@ -1554,10 +1578,14 @@ interface IDatabase {
        /**
         * Acquire a named lock, flush any transaction, and return an RAII style unlocker object
         *
+        * Only call this from outer transcation scope and when only one DB will be affected.
+        * See https://www.mediawiki.org/wiki/Database_transactions for details.
+        *
         * This is suitiable for transactions that need to be serialized using cooperative locks,
         * where each transaction can see each others' changes. Any transaction is flushed to clear
         * out stale REPEATABLE-READ snapshot data. Once the returned object falls out of PHP scope,
-        * any transaction will be committed and the lock will be released.
+        * the lock will be released unless a transaction is active. If one is active, then the lock
+        * will be released when it either commits or rolls back.
         *
         * If the lock acquisition failed, then no transaction flush happens, and null is returned.
         *
index 4078a39..efc6148 100644 (file)
@@ -42,6 +42,8 @@ abstract class LBFactory implements DestructibleService {
        /** @var WANObjectCache */
        protected $wanCache;
 
+       /** @var mixed */
+       protected $ticket;
        /** @var string|bool Reason all LBs are read-only or false if not */
        protected $readOnlyReason = false;
 
@@ -72,6 +74,7 @@ abstract class LBFactory implements DestructibleService {
                        $this->wanCache = WANObjectCache::newEmpty();
                }
                $this->trxLogger = LoggerFactory::getInstance( 'DBTransaction' );
+               $this->ticket = mt_rand();
        }
 
        /**
@@ -404,6 +407,44 @@ abstract class LBFactory implements DestructibleService {
                }
        }
 
+       /**
+        * Get a token asserting that no transaction writes are active
+        *
+        * @param string $fname Caller name (e.g. __METHOD__)
+        * @return mixed A value to pass to commitAndWaitForReplication()
+        * @since 1.28
+        */
+       public function getEmptyTransactionTicket( $fname ) {
+               if ( $this->hasMasterChanges() ) {
+                       $this->trxLogger->error( __METHOD__ . ": $fname does not have outer scope." );
+                       return null;
+               }
+
+               return $this->ticket;
+       }
+
+       /**
+        * Convenience method for safely running commitMasterChanges()/waitForReplication()
+        *
+        * This will commit and wait unless $ticket indicates it is unsafe to do so
+        *
+        * @param string $fname Caller name (e.g. __METHOD__)
+        * @param mixed $ticket Result of getOuterTransactionScopeTicket()
+        * @param array $opts Options to waitForReplication()
+        * @throws DBReplicationWaitError
+        * @since 1.28
+        */
+       public function commitAndWaitForReplication( $fname, $ticket, array $opts = [] ) {
+               if ( $ticket !== $this->ticket ) {
+                       $logger = LoggerFactory::getInstance( 'DBPerformance' );
+                       $logger->error( __METHOD__ . ": cannot commit; $fname does not have outer scope." );
+                       return;
+               }
+
+               $this->commitMasterChanges( $fname );
+               $this->waitForReplication( $opts );
+       }
+
        /**
         * Disable the ChronologyProtector for all load balancers
         *
index 0f3ca93..4b9cccc 100644 (file)
@@ -364,6 +364,8 @@ class LBFactoryMulti extends LBFactory {
                        }
                        $serverInfo['hostName'] = $serverName;
                        $serverInfo['load'] = $load;
+                       $serverInfo += [ 'flags' => DBO_DEFAULT ];
+
                        $servers[] = $serverInfo;
                }
 
index 14baf2e..3702c8b 100644 (file)
@@ -56,6 +56,7 @@ class LBFactorySimple extends LBFactory {
                                } else {
                                        $server['slave'] = true;
                                }
+                               $server += [ 'flags' => DBO_DEFAULT ];
                        }
                } else {
                        global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype, $wgDebugDumpSql;
index a7c486c..d08172a 100644 (file)
@@ -1062,7 +1062,7 @@ class LoadBalancer {
         */
        public function commitAll( $fname = __METHOD__ ) {
                $this->forEachOpenConnection( function ( DatabaseBase $conn ) use ( $fname ) {
-                       $conn->commit( $fname, 'flush' );
+                       $conn->commit( $fname, IDatabase::FLUSHING_ALL_PEERS );
                } );
        }
 
@@ -1109,7 +1109,7 @@ class LoadBalancer {
        public function commitMasterChanges( $fname = __METHOD__ ) {
                $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( $fname ) {
                        if ( $conn->writesOrCallbacksPending() ) {
-                               $conn->commit( $fname, 'flush' );
+                               $conn->commit( $fname, IDatabase::FLUSHING_ALL_PEERS );
                        }
                } );
        }
@@ -1143,7 +1143,7 @@ class LoadBalancer {
                        foreach ( $conns2[$masterIndex] as $conn ) {
                                if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
                                        try {
-                                               $conn->rollback( $fname, 'flush' );
+                                               $conn->rollback( $fname, IDatabase::FLUSHING_ALL_PEERS );
                                        } catch ( DBError $e ) {
                                                MWExceptionHandler::logException( $e );
                                                $failedServers[] = $conn->getServer();
index 0da5d7d..a348719 100644 (file)
@@ -9,7 +9,7 @@ class AtomicSectionUpdate implements DeferrableUpdate, DeferrableCallback {
        private $dbw;
        /** @var string */
        private $fname;
-       /** @var callable */
+       /** @var callable|null */
        private $callback;
 
        /**
index ef5903b..d26cf9d 100644 (file)
@@ -9,7 +9,7 @@ class AutoCommitUpdate implements DeferrableUpdate, DeferrableCallback {
        private $dbw;
        /** @var string */
        private $fname;
-       /** @var callable */
+       /** @var callable|null */
        private $callback;
 
        /**
index 2865461..5b84ca9 100644 (file)
  *       subclasses can override the beginTransaction() and commitTransaction() methods.
  */
 abstract class DataUpdate implements DeferrableUpdate {
+       /** @var mixed Result from LBFactory::getEmptyTransactionTicket() */
+       protected $ticket;
+
        public function __construct() {
                // noop
        }
 
+       /**
+        * @param mixed $ticket Result of getEmptyTransactionTicket()
+        * @since 1.28
+        */
+       public function setTransactionTicket( $ticket ) {
+               $this->ticket = $ticket;
+       }
+
        /**
         * Begin an appropriate transaction, if any.
         * This default implementation does nothing.
index 9768838..ee14e1a 100644 (file)
@@ -68,9 +68,12 @@ class DeferredUpdates {
         *
         * @param callable $callable
         * @param integer $type DeferredUpdates constant (PRESEND or POSTSEND) (since 1.27)
+        * @param IDatabase|null $dbw Abort if this DB is rolled back [optional] (since 1.28)
         */
-       public static function addCallableUpdate( $callable, $type = self::POSTSEND ) {
-               self::addUpdate( new MWCallableUpdate( $callable, wfGetCaller() ), $type );
+       public static function addCallableUpdate(
+               $callable, $type = self::POSTSEND, IDatabase $dbw = null
+       ) {
+               self::addUpdate( new MWCallableUpdate( $callable, wfGetCaller(), $dbw ), $type );
        }
 
        /**
index 0009781..47f2b21 100644 (file)
@@ -54,6 +54,7 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate
        public function doUpdate() {
                $config = RequestContext::getMain()->getConfig();
                $batchSize = $config->get( 'UpdateRowsPerQuery' );
+               $factory = wfGetLBFactory();
 
                // Page may already be deleted, so don't just getId()
                $id = $this->pageId;
@@ -77,8 +78,9 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate
                foreach ( $catBatches as $catBatch ) {
                        $this->page->updateCategoryCounts( [], $catBatch, $id );
                        if ( count( $catBatches ) > 1 ) {
-                               $this->mDb->commit( __METHOD__, 'flush' );
-                               wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+                               $factory->commitAndWaitForReplication(
+                                       __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ]
+                               );
                        }
                }
 
@@ -173,8 +175,9 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate
                        foreach ( $rcIdBatches as $rcIdBatch ) {
                                $this->mDb->delete( 'recentchanges', [ 'rc_id' => $rcIdBatch ], __METHOD__ );
                                if ( count( $rcIdBatches ) > 1 ) {
-                                       $this->mDb->commit( __METHOD__, 'flush' );
-                                       wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+                                       $factory->commitAndWaitForReplication(
+                                               __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ]
+                                       );
                                }
                        }
                }
@@ -185,6 +188,7 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate
 
        private function batchDeleteByPK( $table, array $conds, array $pk, $bSize ) {
                $dbw = $this->mDb; // convenience
+               $factory = wfGetLBFactory();
                $res = $dbw->select( $table, $pk, $conds, __METHOD__ );
 
                $pkDeleteConds = [];
@@ -192,8 +196,9 @@ class LinksDeletionUpdate extends SqlDataUpdate implements EnqueueableDataUpdate
                        $pkDeleteConds[] = $this->mDb->makeList( (array)$row, LIST_AND );
                        if ( count( $pkDeleteConds ) >= $bSize ) {
                                $dbw->delete( $table, $dbw->makeList( $pkDeleteConds, LIST_OR ), __METHOD__ );
-                               $dbw->commit( __METHOD__, 'flush' );
-                               wfGetLBFactory()->waitForReplication( [ 'wiki' => $dbw->getWikiID() ] );
+                               $factory->commitAndWaitForReplication(
+                                       __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ]
+                               );
                                $pkDeleteConds = [];
                        }
                }
index 22944eb..4f40c38 100644 (file)
@@ -335,6 +335,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate {
         */
        private function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {
                $bSize = RequestContext::getMain()->getConfig()->get( 'UpdateRowsPerQuery' );
+               $factory = wfGetLBFactory();
 
                if ( $table === 'page_props' ) {
                        $fromField = 'pp_page';
@@ -386,15 +387,17 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate {
 
                foreach ( $deleteWheres as $deleteWhere ) {
                        $this->mDb->delete( $table, $deleteWhere, __METHOD__ );
-                       $this->mDb->commit( __METHOD__, 'flush' );
-                       wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+                       $factory->commitAndWaitForReplication(
+                               __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ]
+                       );
                }
 
                $insertBatches = array_chunk( $insertions, $bSize );
                foreach ( $insertBatches as $insertBatch ) {
                        $this->mDb->insert( $table, $insertBatch, __METHOD__, 'IGNORE' );
-                       $this->mDb->commit( __METHOD__, 'flush' );
-                       wfGetLBFactory()->waitForReplication( [ 'wiki' => $this->mDb->getWikiID() ] );
+                       $factory->commitAndWaitForReplication(
+                               __METHOD__, $this->ticket, [ 'wiki' => $this->mDb->getWikiID() ]
+                       );
                }
 
                if ( count( $insertions ) ) {
index d63c292..47b162c 100644 (file)
@@ -4,7 +4,7 @@
  * Deferrable Update for closure/callback
  */
 class MWCallableUpdate implements DeferrableUpdate, DeferrableCallback {
-       /** @var callable */
+       /** @var callable|null */
        private $callback;
        /** @var string */
        private $fname;
@@ -12,14 +12,27 @@ class MWCallableUpdate implements DeferrableUpdate, DeferrableCallback {
        /**
         * @param callable $callback
         * @param string $fname Calling method
+        * @param IDatabase|null $dbw Abort if this DB is rolled back [optional] (since 1.28)
         */
-       public function __construct( callable $callback, $fname = 'unknown' ) {
+       public function __construct( callable $callback, $fname = 'unknown', IDatabase $dbw = null ) {
                $this->callback = $callback;
                $this->fname = $fname;
+
+               if ( $dbw && $dbw->trxLevel() ) {
+                       $dbw->onTransactionResolution( [ $this, 'cancelOnRollback' ] );
+               }
        }
 
        public function doUpdate() {
-               call_user_func( $this->callback );
+               if ( $this->callback ) {
+                       call_user_func( $this->callback );
+               }
+       }
+
+       public function cancelOnRollback( $trigger ) {
+               if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
+                       $this->callback = null;
+               }
        }
 
        public function getOrigin() {
index bebd915..0a174fe 100644 (file)
@@ -91,7 +91,7 @@ class MWException extends Exception {
                                is_string( $hook ) ||
                                ( is_array( $hook ) && count( $hook ) >= 2 && is_string( $hook[0] ) )
                        ) {
-                               // 'function' or array( 'class', hook' )
+                               // 'function' or [ 'class', 'hook' ]
                                $result = call_user_func_array( $hook, $callargs );
                        } else {
                                $result = null;
index b61b08d..c9aad43 100644 (file)
@@ -26,9 +26,8 @@
  *
  * This is meant for multi-wiki systems that may share files.
  *
- * All lock requests for a resource, identified by a hash string, will map
- * to one bucket. Each bucket maps to one or several peer DBs, each on their
- * own server, all having the filelocks.sql tables (with row-level locking).
+ * All lock requests for a resource, identified by a hash string, will map to one bucket.
+ * Each bucket maps to one or several peer DBs, each on their own server.
  * A majority of peer DBs must agree for a lock to be acquired.
  *
  * Caching is used to avoid hitting servers that are down.
@@ -243,6 +242,8 @@ abstract class DBLockManager extends QuorumLockManager {
 
 /**
  * MySQL version of DBLockManager that supports shared locks.
+ *
+ * All lock servers must have the innodb table defined in locking/filelocks.sql.
  * All locks are non-blocking, which avoids deadlocks.
  *
  * @ingroup LockManager
index 08a40eb..d515b05 100644 (file)
@@ -177,8 +177,8 @@ class RepoGroup {
         * @param array $inputItems An array of titles, or an array of findFile() options with
         *    the "title" option giving the title. Example:
         *
-        *     $findItem = array( 'title' => $title, 'private' => true );
-        *     $findBatch = array( $findItem );
+        *     $findItem = [ 'title' => $title, 'private' => true ];
+        *     $findBatch = [ $findItem ];
         *     $repo->findFiles( $findBatch );
         *
         *    No title should appear in $items twice, as the result use titles as keys
index b8be4ea..91d628c 100644 (file)
@@ -117,6 +117,9 @@ class LocalFile extends File {
        /** @var bool Whether the row was upgraded on load */
        private $upgraded;
 
+       /** @var bool Whether the row was scheduled to upgrade on load */
+       private $upgrading;
+
        /** @var bool True if the image row is locked */
        private $locked;
 
@@ -559,37 +562,43 @@ class LocalFile extends File {
         */
        function maybeUpgradeRow() {
                global $wgUpdateCompatibleMetadata;
-               if ( wfReadOnly() ) {
+
+               if ( wfReadOnly() || $this->upgrading ) {
                        return;
                }
 
                $upgrade = false;
-               if ( is_null( $this->media_type ) ||
-                       $this->mime == 'image/svg'
-               ) {
+               if ( is_null( $this->media_type ) || $this->mime == 'image/svg' ) {
                        $upgrade = true;
                } else {
                        $handler = $this->getHandler();
                        if ( $handler ) {
                                $validity = $handler->isMetadataValid( $this, $this->getMetadata() );
-                               if ( $validity === MediaHandler::METADATA_BAD
-                                       || ( $validity === MediaHandler::METADATA_COMPATIBLE && $wgUpdateCompatibleMetadata )
-                               ) {
+                               if ( $validity === MediaHandler::METADATA_BAD ) {
                                        $upgrade = true;
+                               } elseif ( $validity === MediaHandler::METADATA_COMPATIBLE ) {
+                                       $upgrade = $wgUpdateCompatibleMetadata;
                                }
                        }
                }
 
                if ( $upgrade ) {
-                       try {
-                               $this->upgradeRow();
-                       } catch ( LocalFileLockError $e ) {
-                               // let the other process handle it (or do it next time)
-                       }
-                       $this->upgraded = true; // avoid rework/retries
+                       $this->upgrading = true;
+                       // Defer updates unless in auto-commit CLI mode
+                       DeferredUpdates::addCallableUpdate( function() {
+                               $this->upgrading = false; // avoid duplicate updates
+                               try {
+                                       $this->upgradeRow();
+                               } catch ( LocalFileLockError $e ) {
+                                       // let the other process handle it (or do it next time)
+                               }
+                       } );
                }
        }
 
+       /**
+        * @return bool Whether upgradeRow() ran for this object
+        */
        function getUpgraded() {
                return $this->upgraded;
        }
@@ -639,7 +648,7 @@ class LocalFile extends File {
                $this->invalidateCache();
 
                $this->unlock(); // done
-
+               $this->upgraded = true; // avoid rework/retries
        }
 
        /**
@@ -964,6 +973,33 @@ class LocalFile extends File {
                DeferredUpdates::addUpdate( new CdnCacheUpdate( $urls ), DeferredUpdates::PRESEND );
        }
 
+       /**
+        * Prerenders a configurable set of thumbnails
+        *
+        * @since 1.28
+        */
+       public function prerenderThumbnails() {
+               global $wgUploadThumbnailRenderMap;
+
+               $jobs = [];
+
+               $sizes = $wgUploadThumbnailRenderMap;
+               rsort( $sizes );
+
+               foreach ( $sizes as $size ) {
+                       if ( $this->isVectorized() || $this->getWidth() > $size ) {
+                               $jobs[] = new ThumbnailRenderJob(
+                                       $this->getTitle(),
+                                       [ 'transformParams' => [ 'width' => $size ] ]
+                               );
+                       }
+               }
+
+               if ( $jobs ) {
+                       JobQueueGroup::singleton()->lazyPush( $jobs );
+               }
+       }
+
        /**
         * Delete a list of thumbnails visible at urls
         * @param string $dir Base dir of the files.
@@ -1516,6 +1552,8 @@ class LocalFile extends File {
                                                # Update backlink pages pointing to this title if created
                                                LinksUpdate::queueRecursiveJobsForTable( $this->getTitle(), 'imagelinks' );
                                        }
+
+                                       $this->prerenderThumbnails();
                                }
                        ),
                        DeferredUpdates::PRESEND
index a7acd8b..ff37e24 100644 (file)
@@ -275,14 +275,12 @@ class HTMLForm extends ContextSource {
 
                switch ( $displayFormat ) {
                        case 'vform':
-                               $reflector = new ReflectionClass( 'VFormHTMLForm' );
-                               return $reflector->newInstanceArgs( $arguments );
+                               return ObjectFactory::constructClassInstance( VFormHTMLForm::class, $arguments );
                        case 'ooui':
-                               $reflector = new ReflectionClass( 'OOUIHTMLForm' );
-                               return $reflector->newInstanceArgs( $arguments );
+                               return ObjectFactory::constructClassInstance( OOUIHTMLForm::class, $arguments );
                        default:
-                               $reflector = new ReflectionClass( 'HTMLForm' );
-                               $form = $reflector->newInstanceArgs( $arguments );
+                               /** @var HTMLForm $form */
+                               $form = ObjectFactory::constructClassInstance( HTMLForm::class, $arguments );
                                $form->setDisplayFormat( $displayFormat );
                                return $form;
                }
index ec1bd84..5d8f491 100644 (file)
@@ -257,7 +257,7 @@ class HTMLFormFieldCloner extends HTMLFormField {
         * @param array $values
         * @return string
         */
-       protected function getInputHTMLForKey( $key, $values ) {
+       protected function getInputHTMLForKey( $key, array $values ) {
                $displayFormat = isset( $this->mParams['format'] )
                        ? $this->mParams['format']
                        : $this->mParent->getDisplayFormat();
@@ -354,7 +354,7 @@ class HTMLFormFieldCloner extends HTMLFormField {
                        );
                }
 
-               $template = $this->getInputHTMLForKey( $this->uniqueId, null );
+               $template = $this->getInputHTMLForKey( $this->uniqueId, [] );
                $html = Html::rawElement( 'ul', [
                        'id' => "mw-htmlform-cloner-list-{$this->mID}",
                        'class' => 'mw-htmlform-cloner-ul',
index 5e3758d..d508d76 100644 (file)
@@ -294,10 +294,6 @@ abstract class Installer {
                        'url' => 'https://creativecommons.org/publicdomain/zero/1.0/',
                        'icon' => '$wgResourceBasePath/resources/assets/licenses/cc-0.png',
                ],
-               'pd' => [
-                       'url' => '',
-                       'icon' => '$wgResourceBasePath/resources/assets/licenses/public-domain.png',
-               ],
                'gfdl' => [
                        'url' => 'https://www.gnu.org/copyleft/fdl.html',
                        'icon' => '$wgResourceBasePath/resources/assets/licenses/gnu-fdl.png',
index e1931dd..20ebf9b 100644 (file)
        "config-subscribe-help": "Detta är en e-postlista med låg volym vilken används för meddelanden om nya versionssläpp, inklusive viktiga säkerhetsmeddelanden.\nDu bör prenumerera på den och uppdatera din MediaWiki-installation när nya versioner kommer ut.",
        "config-subscribe-noemail": "Du försökte att prenumerera på e-postlistan för versionssläppsmeddelanden utan att tillhandahålla en e-postadress.\nAnge en e-postadress om du vill prenumerera på e-postlistan.",
        "config-pingback": "Dela data om denna installation med MediaWikis utvecklare.",
+       "config-pingback-help": "Om du väljer det här alternativet kommer MediaWiki periodvis pinga https://www.mediawiki.org med grundläggande data om den här MediaWiki-instansen. Denna data innehåller exempelvis typen av system, PHP-version och valde databas. Wikimedia Foundation delar denna data med MediaWiki-utvecklare för att hjälpa till att guida framtida utvecklingsarbete. Följande data kommer att skickas till ditt system: <pre>$1</pre>",
        "config-almost-done": "Du är nästan färdig!\nDu kan nu hoppa över återstående konfigurationer och installera wikin direkt.",
        "config-optional-continue": "Ställ fler frågor till mig.",
        "config-optional-skip": "Jag är redan uttråkad, bara installera wiki.",
index a132dc5..4b906a7 100644 (file)
@@ -522,10 +522,10 @@ class JobRunner implements LoggerAwareInterface {
                        // This will trigger a rollback in the main loop
                        throw new DBError( $dbwSerial, "Timed out waiting on commit queue." );
                }
-               // Wait for the generic slave to catch up
+               // Wait for the slave DBs to catch up
                $pos = $lb->getMasterPos();
                if ( $pos ) {
-                       $lb->waitForOne( $pos );
+                       $lb->waitForAll( $pos );
                }
 
                $fname = __METHOD__;
index 1e804c4..060cabb 100644 (file)
@@ -73,8 +73,12 @@ class AssembleUploadChunksJob extends Job {
                                return false;
                        }
 
+                       // We can only get warnings like 'duplicate' after concatenating the chunks
+                       $status = Status::newGood();
+                       $status->value = [ 'warnings' => $upload->checkWarnings() ];
+
                        // We have a new filekey for the fully concatenated file
-                       $newFileKey = $upload->getLocalFile()->getFileKey();
+                       $newFileKey = $upload->getStashFile()->getFileKey();
 
                        // Remove the old stash file row and first chunk file
                        $upload->stash->removeFileNoAuth( $this->params['filekey'] );
@@ -95,7 +99,7 @@ class AssembleUploadChunksJob extends Job {
                                        'stage' => 'assembling',
                                        'filekey' => $newFileKey,
                                        'imageinfo' => $imageInfo,
-                                       'status' => Status::newGood()
+                                       'status' => $status
                                ]
                        );
                } catch ( Exception $e ) {
index 57e69b4..b561021 100644 (file)
@@ -64,7 +64,7 @@ class CategoryMembershipChangeJob extends Job {
                        return false;
                }
                // Clear any stale REPEATABLE-READ snapshot
-               $dbr->commit( __METHOD__, 'flush' );
+               wfGetLBFactory()->commitAll( __METHOD__ );
 
                $cutoffUnix = wfTimestamp( TS_UNIX, $this->params['revTimestamp'] );
                // Using ENQUEUE_FUDGE_SEC handles jobs inserted out of revision order due to the delay
@@ -157,6 +157,9 @@ class CategoryMembershipChangeJob extends Job {
                }
 
                $dbw = wfGetDB( DB_MASTER );
+               $factory = wfGetLBFactory();
+               $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
+
                $catMembChange = new CategoryMembershipChange( $title, $newRev );
                $catMembChange->checkTemplateLinks();
 
@@ -167,8 +170,7 @@ class CategoryMembershipChangeJob extends Job {
                        $categoryTitle = Title::makeTitle( NS_CATEGORY, $categoryName );
                        $catMembChange->triggerCategoryAddedNotification( $categoryTitle );
                        if ( $insertCount++ && ( $insertCount % $batchSize ) == 0 ) {
-                               $dbw->commit( __METHOD__, 'flush' );
-                               wfGetLBFactory()->waitForReplication();
+                               $factory->commitAndWaitForReplication( __METHOD__, $ticket );
                        }
                }
 
@@ -176,8 +178,7 @@ class CategoryMembershipChangeJob extends Job {
                        $categoryTitle = Title::makeTitle( NS_CATEGORY, $categoryName );
                        $catMembChange->triggerCategoryRemovedNotification( $categoryTitle );
                        if ( $insertCount++ && ( $insertCount++ % $batchSize ) == 0 ) {
-                               $dbw->commit( __METHOD__, 'flush' );
-                               wfGetLBFactory()->waitForReplication();
+                               $factory->commitAndWaitForReplication( __METHOD__, $ticket );
                        }
                }
        }
index f39f8fd..8d565bd 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup JobQueue
  */
+use \MediaWiki\MediaWikiServices;
 
 /**
  * Job to prune link tables for pages that were deleted
@@ -52,10 +53,12 @@ class DeleteLinksJob extends Job {
                        return false;
                }
 
+               $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
                $timestamp = isset( $this->params['timestamp'] ) ? $this->params['timestamp'] : null;
-
                $page = WikiPage::factory( $this->title ); // title when deleted
+
                $update = new LinksDeletionUpdate( $page, $pageId, $timestamp );
+               $update->setTransactionTicket( $factory->getEmptyTransactionTicket( __METHOD__ ) );
                DataUpdate::runUpdates( [ $update ] );
 
                return true;
index a14cdd7..f09ba57 100644 (file)
@@ -113,11 +113,12 @@ class HTMLCacheUpdateJob extends Job {
                $touchTimestamp = wfTimestampNow();
 
                $dbw = wfGetDB( DB_MASTER );
+               $factory = wfGetLBFactory();
+               $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
                // Update page_touched (skipping pages already touched since the root job).
                // Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already.
                foreach ( array_chunk( $pageIds, $wgUpdateRowsPerQuery ) as $batch ) {
-                       $dbw->commit( __METHOD__, 'flush' );
-                       wfGetLBFactory()->waitForReplication();
+                       $factory->commitAndWaitForReplication( __METHOD__, $ticket );
 
                        $dbw->update( 'page',
                                [ 'page_touched' => $dbw->timestamp( $touchTimestamp ) ],
index fbc1572..2fd3899 100644 (file)
@@ -81,6 +81,8 @@ class RecentChangesUpdateJob extends Job {
                        return; // already in progress
                }
 
+               $factory = wfGetLBFactory();
+               $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
                $cutoff = $dbw->timestamp( time() - $wgRCMaxAge );
                do {
                        $rcIds = $dbw->selectFieldValues( 'recentchanges',
@@ -91,14 +93,11 @@ class RecentChangesUpdateJob extends Job {
                        );
                        if ( $rcIds ) {
                                $dbw->delete( 'recentchanges', [ 'rc_id' => $rcIds ], __METHOD__ );
-                       }
-                       // Commit in chunks to avoid slave lag
-                       $dbw->commit( __METHOD__, 'flush' );
-
-                       if ( count( $rcIds ) === $wgUpdateRowsPerQuery ) {
                                // There might be more, so try waiting for slaves
                                try {
-                                       wfGetLBFactory()->waitForReplication( [ 'timeout' => 3 ] );
+                                       $factory->commitAndWaitForReplication(
+                                               __METHOD__, $ticket, [ 'timeout' => 3 ]
+                                       );
                                } catch ( DBReplicationWaitError $e ) {
                                        // Another job will continue anyway
                                        break;
@@ -121,6 +120,8 @@ class RecentChangesUpdateJob extends Job {
                // JobRunner uses DBO_TRX, but doesn't call begin/commit itself;
                // onTransactionIdle() will run immediately since there is no trx.
                $dbw->onTransactionIdle( function() use ( $dbw, $days, $window ) {
+                       $factory = wfGetLBFactory();
+                       $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
                        // Avoid disconnect/ping() cycle that makes locks fall off
                        $dbw->setSessionOptions( [ 'connTimeout' => 900 ] );
 
@@ -204,7 +205,7 @@ class RecentChangesUpdateJob extends Job {
                                }
                                foreach ( array_chunk( $newRows, 500 ) as $rowBatch ) {
                                        $dbw->insert( 'querycachetwo', $rowBatch, __METHOD__ );
-                                       wfGetLBFactory()->waitForReplication();
+                                       $factory->commitAndWaitForReplication( __METHOD__, $ticket );
                                }
                        }
 
index 8fba728..9cdb161 100644 (file)
@@ -241,7 +241,10 @@ class RefreshLinksJob extends Job {
                        $parserOutput
                );
 
+               $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+               $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
                foreach ( $updates as $key => $update ) {
+                       $update->setTransactionTicket( $ticket );
                        // FIXME: This code probably shouldn't be here?
                        // Needed by things like Echo notifications which need
                        // to know which user caused the links update
index e3d50c6..552c661 100644 (file)
@@ -474,7 +474,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *
         * Example usage:
         * @code
-        *     $dbw->begin( __METHOD__ ); // start of request
+        *     $dbw->startAtomic( __METHOD__ ); // start of request
         *     ... <execute some stuff> ...
         *     // Update the row in the DB
         *     $dbw->update( ... );
@@ -484,7 +484,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *         $cache->delete( $key );
         *     } );
         *     ... <execute some stuff> ...
-        *     $dbw->commit( __METHOD__ ); // end of request
+        *     $dbw->endAtomic( __METHOD__ ); // end of request
         * @endcode
         *
         * The $ttl parameter can be used when purging values that have not actually changed
@@ -686,7 +686,9 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *             // Calling touchCheckKey() on this key invalidates the cache
         *             'checkKeys' => [ $cache->makeKey( 'site-cat-config' ) ],
         *             // Try to only let one datacenter thread manage cache updates at a time
-        *             'lockTSE' => 30
+        *             'lockTSE' => 30,
+        *             // Avoid querying cache servers multiple times in a web request
+        *             'pcTTL' => $cache::TTL_PROC_LONG
         *         ]
         *     );
         * @endcode
@@ -740,8 +742,12 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         *             // Merge them and get the new "last 100" rows
         *             return array_slice( array_merge( $new, $list ), 0, 100 );
         *        },
-        *        // Try to only let one datacenter thread manage cache updates at a time
-        *        [ 'lockTSE' => 30 ]
+        *        [
+        *             // Try to only let one datacenter thread manage cache updates at a time
+        *             'lockTSE' => 30,
+        *             // Use a magic value when no cache value is ready rather than stampeding
+        *             'busyValue' => 'computing'
+        *        ]
         *     );
         * @endcode
         *
index 1083393..bcdf62f 100644 (file)
@@ -249,7 +249,7 @@ class ObjectCache {
         *     ObjectCache::getLocalServerInstance( $fallbackType );
         *
         *     // From $wgObjectCaches via newFromParams()
-        *     ObjectCache::getLocalServerInstance( array( 'fallback' => $fallbackType ) );
+        *     ObjectCache::getLocalServerInstance( [ 'fallback' => $fallbackType ] );
         *
         * @param int|string|array $fallback Fallback cache or parameter map with 'fallback'
         * @return BagOStuff
index c48880f..5556dd8 100644 (file)
@@ -471,6 +471,27 @@ class SqlBagOStuff extends BagOStuff {
                return $ok;
        }
 
+       public function changeTTL( $key, $expiry = 0 ) {
+               list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
+               try {
+                       $db = $this->getDB( $serverIndex );
+                       $db->update(
+                               $tableName,
+                               [ 'exptime' => $db->timestamp( $this->convertExpiry( $expiry ) ) ],
+                               [ 'keyname' => $key, 'exptime > ' . $db->addQuotes( $db->timestamp( time() ) ) ],
+                               __METHOD__
+                       );
+                       if ( $db->affectedRows() == 0 ) {
+                               return false;
+                       }
+               } catch ( DBError $e ) {
+                       $this->handleWriteError( $e, $serverIndex );
+                       return false;
+               }
+
+               return true;
+       }
+
        /**
         * @param IDatabase $db
         * @param string $exptime
index bded84d..0344756 100644 (file)
@@ -90,6 +90,14 @@ class WikiPage implements Page, IDBAccessObject {
                $this->mTitle = $title;
        }
 
+       /**
+        * Makes sure that the mTitle object is cloned
+        * to the newly cloned WikiPage.
+        */
+       public function __clone() {
+               $this->mTitle = clone $this->mTitle;
+       }
+
        /**
         * Create a WikiPage object of the appropriate class for the given title.
         *
@@ -887,9 +895,13 @@ class WikiPage implements Page, IDBAccessObject {
                // Update the DB post-send if the page has not cached since now
                $that = $this;
                $latest = $this->getLatest();
-               DeferredUpdates::addCallableUpdate( function() use ( $that, $retval, $latest ) {
-                       $that->insertRedirectEntry( $retval, $latest );
-               } );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $that, $retval, $latest ) {
+                               $that->insertRedirectEntry( $retval, $latest );
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
 
                return $retval;
        }
@@ -1048,9 +1060,9 @@ class WikiPage implements Page, IDBAccessObject {
         * @param bool          $forceParse Force reindexing, regardless of cache settings
         * @return bool|ParserOutput ParserOutput or false if the revision was not found
         */
-       public function getParserOutput( ParserOptions $parserOptions, $oldid = null,
-                                        $forceParse = false ) {
-
+       public function getParserOutput(
+               ParserOptions $parserOptions, $oldid = null, $forceParse = false
+       ) {
                $useParserCache =
                        ( !$forceParse ) && $this->shouldCheckParserCache( $parserOptions, $oldid );
                wfDebug( __METHOD__ .
@@ -1144,7 +1156,9 @@ class WikiPage implements Page, IDBAccessObject {
         * @param IDatabase $dbw
         * @param int|null $pageId Custom page ID that will be used for the insert statement
         *
-        * @return bool|int The newly created page_id key; false if the title already existed
+        * @return bool|int The newly created page_id key; false if the row was not
+        *   inserted, e.g. because the title already existed or because the specified
+        *   page ID is already in use.
         */
        public function insertOn( $dbw, $pageId = null ) {
                $pageIdForInsert = $pageId ?: $dbw->nextSequenceValue( 'page_page_id_seq' );
@@ -2932,6 +2946,11 @@ class WikiPage implements Page, IDBAccessObject {
                // Save this so we can pass it to the ArticleDeleteComplete hook.
                $archivedRevisionCount = $dbw->affectedRows();
 
+               // Clone the title and wikiPage, so we have the information we need when
+               // we log and run the ArticleDeleteComplete hook.
+               $logTitle = clone $this->mTitle;
+               $wikiPageBeforeDelete = clone $this;
+
                // Now that it's safely backed up, delete it
                $dbw->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
 
@@ -2939,9 +2958,6 @@ class WikiPage implements Page, IDBAccessObject {
                        $dbw->delete( 'revision', [ 'rev_page' => $id ], __METHOD__ );
                }
 
-               // Clone the title, so we have the information we need when we log
-               $logTitle = clone $this->mTitle;
-
                // Log the deletion, if the page was suppressed, put it in the suppression log instead
                $logtype = $suppress ? 'suppress' : 'delete';
 
@@ -2960,8 +2976,15 @@ class WikiPage implements Page, IDBAccessObject {
 
                $this->doDeleteUpdates( $id, $content );
 
-               Hooks::run( 'ArticleDeleteComplete',
-                       [ &$this, &$user, $reason, $id, $content, $logEntry, $archivedRevisionCount ] );
+               Hooks::run( 'ArticleDeleteComplete', [
+                       &$wikiPageBeforeDelete,
+                       &$user,
+                       $reason,
+                       $id,
+                       $content,
+                       $logEntry,
+                       $archivedRevisionCount
+               ] );
                $status->value = $logid;
 
                // Show log excerpt on 404 pages rather than just a link
index 393644f..a96ca87 100644 (file)
@@ -700,8 +700,8 @@ abstract class IndexPager extends ContextSource implements Pager {
         * not be used in the pager offset or in any links for users.
         *
         * If getIndexField() returns an array of 'querykey' => 'indexfield' pairs then
-        * this must return a corresponding array of 'querykey' => array( fields...) pairs
-        * in order for a request with &count=querykey to use array( fields...) to sort.
+        * this must return a corresponding array of 'querykey' => [ fields... ] pairs
+        * in order for a request with &count=querykey to use [ fields... ] to sort.
         *
         * This is useful for pagers that GROUP BY a unique column (say page_id)
         * and ORDER BY another (say page_len). Using GROUP BY and ORDER BY both on
index 206ad00..4f579a9 100644 (file)
@@ -4364,11 +4364,7 @@ class Parser {
                $this->startParse( $title, $options, self::OT_WIKI, $clearState );
                $this->setUser( $user );
 
-               $pairs = [
-                       "\r\n" => "\n",
-                       "\r" => "\n",
-               ];
-               $text = str_replace( array_keys( $pairs ), array_values( $pairs ), $text );
+               $text = str_replace( [ "\r\n", "\r" ], "\n", $text );
                if ( $options->getPreSaveTransform() ) {
                        $text = $this->pstPass2( $text, $user );
                }
index a28c0aa..5da7cd7 100644 (file)
@@ -539,7 +539,7 @@ class Preprocessor_DOM extends Preprocessor {
                        } elseif ( $found == 'line-end' ) {
                                $piece = $stack->top;
                                // A heading must be open, otherwise \n wouldn't have been in the search list
-                               assert( '$piece->open == "\n"' );
+                               assert( $piece->open === "\n" );
                                $part = $piece->getCurrentPart();
                                // Search back through the input to see if it has a proper close.
                                // Do this using the reversed string since the other solutions
index 012288f..8a4637e 100644 (file)
@@ -475,7 +475,7 @@ class Preprocessor_Hash extends Preprocessor {
                        } elseif ( $found == 'line-end' ) {
                                $piece = $stack->top;
                                // A heading must be open, otherwise \n wouldn't have been in the search list
-                               assert( '$piece->open == "\n"' );
+                               assert( $piece->open === "\n" );
                                $part = $piece->getCurrentPart();
                                // Search back through the input to see if it has a proper close.
                                // Do this using the reversed string since the other solutions
index d145566..6426fea 100644 (file)
@@ -60,13 +60,13 @@ class ResourceLoader implements LoggerAwareInterface {
 
        /**
         * Associative array mapping framework ids to a list of names of test suite modules
-        * like array( 'qunit' => array( 'mediawiki.tests.qunit.suites', 'ext.foo.tests', .. ), .. )
+        * like [ 'qunit' => [ 'mediawiki.tests.qunit.suites', 'ext.foo.tests', ... ], ... ]
         * @var array
         */
        protected $testModuleNames = [];
 
        /**
-        * E.g. array( 'source-id' => 'http://.../load.php' )
+        * E.g. [ 'source-id' => 'http://.../load.php' ]
         * @var array
         */
        protected $sources = [];
@@ -433,7 +433,7 @@ class ResourceLoader implements LoggerAwareInterface {
         *
         * Source IDs are typically the same as the Wiki ID or database name (e.g. lowercase a-z).
         *
-        * @param array|string $id Source ID (string), or array( id1 => loadUrl, id2 => loadUrl, ... )
+        * @param array|string $id Source ID (string), or [ id1 => loadUrl, id2 => loadUrl, ... ]
         * @param string|array $loadUrl load.php url (string), or array with loadUrl key for
         *  backwards-compatibility.
         * @throws MWException
@@ -573,7 +573,7 @@ class ResourceLoader implements LoggerAwareInterface {
        /**
         * Get the list of sources.
         *
-        * @return array Like array( id => load.php url, .. )
+        * @return array Like [ id => load.php url, ... ]
         */
        public function getSources() {
                return $this->sources;
@@ -1173,7 +1173,7 @@ MESSAGE;
         *    - ResourceLoader::makeLoaderStateScript( $name, $state ):
         *         Set the state of a single module called $name to $state
         *
-        *    - ResourceLoader::makeLoaderStateScript( array( $name => $state, ... ) ):
+        *    - ResourceLoader::makeLoaderStateScript( [ $name => $state, ... ] ):
         *         Set the state of modules with the given names to the given states
         *
         * @param string $name
@@ -1264,14 +1264,14 @@ MESSAGE;
         *     ):
         *        Register a single module.
         *
-        *   - ResourceLoader::makeLoaderRegisterScript( array( $name1, $name2 ) ):
+        *   - ResourceLoader::makeLoaderRegisterScript( [ $name1, $name2 ] ):
         *        Register modules with the given names.
         *
-        *   - ResourceLoader::makeLoaderRegisterScript( array(
-        *        array( $name1, $version1, $dependencies1, $group1, $source1, $skip1 ),
-        *        array( $name2, $version2, $dependencies1, $group2, $source2, $skip2 ),
+        *   - ResourceLoader::makeLoaderRegisterScript( [
+        *        [ $name1, $version1, $dependencies1, $group1, $source1, $skip1 ],
+        *        [ $name2, $version2, $dependencies1, $group2, $source2, $skip2 ],
         *        ...
-        *     ) ):
+        *     ] ):
         *        Registers modules with the given names and parameters.
         *
         * @param string $name Module name
@@ -1329,7 +1329,7 @@ MESSAGE;
         *   - ResourceLoader::makeLoaderSourcesScript( $id, $properties ):
         *       Register a single source
         *
-        *   - ResourceLoader::makeLoaderSourcesScript( array( $id1 => $loadUrl, $id2 => $loadUrl, ... ) );
+        *   - ResourceLoader::makeLoaderSourcesScript( [ $id1 => $loadUrl, $id2 => $loadUrl, ... ] );
         *       Register sources with the given IDs and properties.
         *
         * @param string $id Source ID
@@ -1402,13 +1402,13 @@ MESSAGE;
        /**
         * Convert an array of module names to a packed query string.
         *
-        * For example, array( 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' )
+        * For example, [ 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' ]
         * becomes 'foo.bar,baz|bar.baz,quux'
         * @param array $modules List of module names (strings)
         * @return string Packed query string
         */
        public static function makePackedModulesString( $modules ) {
-               $groups = []; // array( prefix => array( suffixes ) )
+               $groups = []; // [ prefix => [ suffixes ] ]
                foreach ( $modules as $module ) {
                        $pos = strrpos( $module, '.' );
                        $prefix = $pos === false ? '' : substr( $module, 0, $pos );
index 3093cde..dc70af4 100644 (file)
@@ -33,6 +33,9 @@ class ResourceLoaderClientHtml {
        /** @var ResourceLoader */
        private $resourceLoader;
 
+       /** @var string|null */
+       private $target;
+
        /** @var array */
        private $config = [];
 
@@ -53,10 +56,12 @@ class ResourceLoaderClientHtml {
 
        /**
         * @param ResourceLoaderContext $context
+        * @param aray $target [optional] Custom 'target' parameter for the startup module
         */
-       public function __construct( ResourceLoaderContext $context ) {
+       public function __construct( ResourceLoaderContext $context, $target = null ) {
                $this->context = $context;
                $this->resourceLoader = $context->getResourceLoader();
+               $this->target = $target;
        }
 
        /**
@@ -316,7 +321,13 @@ class ResourceLoaderClientHtml {
                }
 
                // Async scripts. Once the startup is loaded, inline RLQ scripts will run.
-               $chunks[] = $this->getLoad( 'startup', ResourceLoaderModule::TYPE_SCRIPTS );
+               // Pass-through a custom target from OutputPage (T143066).
+               $startupQuery = $this->target ? [ 'target' => $this->target ] : [];
+               $chunks[] = $this->getLoad(
+                       'startup',
+                       ResourceLoaderModule::TYPE_SCRIPTS,
+                       $startupQuery
+               );
 
                return WrappedStringList::join( "\n", $chunks );
        }
@@ -358,8 +369,8 @@ class ResourceLoaderClientHtml {
                return self::makeContext( $this->context, $group, $type );
        }
 
-       private function getLoad( $modules, $only ) {
-               return self::makeLoad( $this->context, (array)$modules, $only );
+       private function getLoad( $modules, $only, array $extraQuery = [] ) {
+               return self::makeLoad( $this->context, (array)$modules, $only, $extraQuery );
        }
 
        private static function makeContext( ResourceLoaderContext $mainContext, $group, $type,
index 8fa0411..79b71df 100644 (file)
@@ -91,8 +91,8 @@ class ResourceLoaderContext {
 
        /**
         * Expand a string of the form jquery.foo,bar|jquery.ui.baz,quux to
-        * an array of module names like array( 'jquery.foo', 'jquery.bar',
-        * 'jquery.ui.baz', 'jquery.ui.quux' )
+        * an array of module names like [ 'jquery.foo', 'jquery.bar',
+        * 'jquery.ui.baz', 'jquery.ui.quux' ]
         * @param string $modules Packed module name list
         * @return array Array of module names
         */
@@ -113,7 +113,7 @@ class ResourceLoaderContext {
                                } else {
                                        // We have a prefix and a bunch of suffixes
                                        $prefix = substr( $group, 0, $pos ); // 'foo'
-                                       $suffixes = explode( ',', substr( $group, $pos + 1 ) ); // array( 'bar', 'baz' )
+                                       $suffixes = explode( ',', substr( $group, $pos + 1 ) ); // [ 'bar', 'baz' ]
                                        foreach ( $suffixes as $suffix ) {
                                                $retval[] = "$prefix.$suffix";
                                        }
index 2816126..574e535 100644 (file)
@@ -41,7 +41,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of paths to JavaScript files to always include
         * @par Usage:
         * @code
-        * array( [file-path], [file-path], ... )
+        * [ [file-path], [file-path], ... ]
         * @endcode
         */
        protected $scripts = [];
@@ -50,7 +50,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of JavaScript files to include when using a specific language
         * @par Usage:
         * @code
-        * array( [language-code] => array( [file-path], [file-path], ... ), ... )
+        * [ [language-code] => [ [file-path], [file-path], ... ], ... ]
         * @endcode
         */
        protected $languageScripts = [];
@@ -59,7 +59,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of JavaScript files to include when using a specific skin
         * @par Usage:
         * @code
-        * array( [skin-name] => array( [file-path], [file-path], ... ), ... )
+        * [ [skin-name] => [ [file-path], [file-path], ... ], ... ]
         * @endcode
         */
        protected $skinScripts = [];
@@ -68,7 +68,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of paths to JavaScript files to include in debug mode
         * @par Usage:
         * @code
-        * array( [skin-name] => array( [file-path], [file-path], ... ), ... )
+        * [ [skin-name] => [ [file-path], [file-path], ... ], ... ]
         * @endcode
         */
        protected $debugScripts = [];
@@ -77,7 +77,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of paths to CSS files to always include
         * @par Usage:
         * @code
-        * array( [file-path], [file-path], ... )
+        * [ [file-path], [file-path], ... ]
         * @endcode
         */
        protected $styles = [];
@@ -86,7 +86,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of paths to CSS files to include when using specific skins
         * @par Usage:
         * @code
-        * array( [file-path], [file-path], ... )
+        * [ [file-path], [file-path], ... ]
         * @endcode
         */
        protected $skinStyles = [];
@@ -95,7 +95,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of modules this module depends on
         * @par Usage:
         * @code
-        * array( [file-path], [file-path], ... )
+        * [ [file-path], [file-path], ... ]
         * @endcode
         */
        protected $dependencies = [];
@@ -109,7 +109,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array List of message keys used by this module
         * @par Usage:
         * @code
-        * array( [message-key], [message-key], ... )
+        * [ [message-key], [message-key], ... ]
         * @endcode
         */
        protected $messages = [];
@@ -138,7 +138,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @var array Place where readStyleFile() tracks file dependencies
         * @par Usage:
         * @code
-        * array( [file-path], [file-path], ... )
+        * [ [file-path], [file-path], ... ]
         * @endcode
         */
        protected $localFileRefs = [];
@@ -165,7 +165,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         * @throws InvalidArgumentException
         * @par Construction options:
         * @code
-        *     array(
+        *     [
         *         // Base path to prepend to all local paths in $options. Defaults to $IP
         *         'localBasePath' => [base path],
         *         // Base path to prepend to all remote paths in $options. Defaults to $wgResourceBasePath
@@ -207,7 +207,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         *         // The file must contain valid JavaScript for execution in a private function.
         *         // The file must not contain the "function () {" and "}" wrapper though.
         *         'skipFunction' => [file path]
-        *     )
+        *     ]
         * @endcode
         */
        public function __construct(
index 87e5fd7..2503b22 100644 (file)
@@ -54,8 +54,8 @@ class ResourceLoaderImage {
                $this->variants = $variants;
 
                // Expand shorthands:
-               // array( "en,de,fr" => "foo.svg" )
-               // → array( "en" => "foo.svg", "de" => "foo.svg", "fr" => "foo.svg" )
+               // [ "en,de,fr" => "foo.svg" ]
+               // → [ "en" => "foo.svg", "de" => "foo.svg", "fr" => "foo.svg" ]
                if ( is_array( $this->descriptor ) && isset( $this->descriptor['lang'] ) ) {
                        foreach ( array_keys( $this->descriptor['lang'] ) as $langList ) {
                                if ( strpos( $langList, ',' ) !== false ) {
index 3b3bdf7..43327c9 100644 (file)
@@ -393,6 +393,8 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
        public function getDefinitionSummary( ResourceLoaderContext $context ) {
                $this->loadFromDefinition();
                $summary = parent::getDefinitionSummary( $context );
+
+               $options = [];
                foreach ( [
                        'localBasePath',
                        'images',
@@ -401,29 +403,27 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                        'selectorWithoutVariant',
                        'selectorWithVariant',
                ] as $member ) {
-                       $summary[$member] = $this->{$member};
+                       $options[$member] = $this->{$member};
                };
+
+               $summary[] = [
+                       'options' => $options,
+                       'fileHashes' => $this->getFileHashes( $context ),
+               ];
                return $summary;
        }
 
        /**
-        * Get the last modified timestamp of this module.
-        *
-        * @param ResourceLoaderContext $context Context in which to calculate
-        *     the modified time
-        * @return int UNIX timestamp
+        * Helper method for getDefinitionSummary.
         */
-       public function getModifiedTime( ResourceLoaderContext $context ) {
+       protected function getFileHashes( ResourceLoaderContext $context ) {
                $this->loadFromDefinition();
                $files = [];
                foreach ( $this->getImages( $context ) as $name => $image ) {
                        $files[] = $image->getPath( $context );
                }
-
                $files = array_values( array_unique( $files ) );
-               $filesMtime = max( array_map( [ __CLASS__, 'safeFilemtime' ], $files ) );
-
-               return $filesMtime;
+               return array_map( [ __CLASS__, 'safeFileHash' ], $files );
        }
 
        /**
@@ -455,4 +455,11 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                $this->loadFromDefinition();
                return $this->position;
        }
+
+       /**
+        * @return string
+        */
+       public function getType() {
+               return self::LOAD_STYLES;
+       }
 }
index d365bf6..48604e1 100644 (file)
@@ -275,7 +275,8 @@ abstract class RevDelList extends RevisionListBase {
                        function () use ( $visibilityChangeMap ) {
                                $this->doPostCommitUpdates( $visibilityChangeMap );
                        },
-                       DeferredUpdates::PRESEND
+                       DeferredUpdates::PRESEND,
+                       $dbw
                );
 
                $dbw->endAtomic( __METHOD__ );
index 22413b9..b4be461 100644 (file)
@@ -456,7 +456,6 @@ class SkinTemplate extends Skin {
                $tpl->set( 'indicators', $out->getIndicators() );
 
                $tpl->set( 'sitenotice', $this->getSiteNotice() );
-               $tpl->set( 'bottomscripts', $this->bottomScripts() );
                $tpl->set( 'printfooter', $this->printSource() );
                // Wrap the bodyText with #mw-content-text element
                $out->mBodytext = $this->wrapHTML( $title, $out->mBodytext );
@@ -479,6 +478,9 @@ class SkinTemplate extends Skin {
                $tpl->set( 'sidebar', $this->buildSidebar() );
                $tpl->set( 'nav_urls', $this->buildNavUrls() );
 
+               // Do this last in case hooks above add bottom scripts
+               $tpl->set( 'bottomscripts', $this->bottomScripts() );
+
                // Set the head scripts near the end, in case the above actions resulted in added scripts
                $tpl->set( 'headelement', $out->headElement( $this ) );
 
index a656c2e..7b4e9db 100644 (file)
@@ -49,10 +49,9 @@ class EmailConfirmation extends UnlistedSpecialPage {
        function execute( $code ) {
                // Ignore things like master queries/connections on GET requests.
                // It's very convenient to just allow formless link usage.
-               Profiler::instance()->getTransactionProfiler()->resetExpectations();
+               $trxProfiler = Profiler::instance()->getTransactionProfiler();
 
                $this->setHeaders();
-
                $this->checkReadOnly();
                $this->checkPermissions();
 
@@ -70,7 +69,9 @@ class EmailConfirmation extends UnlistedSpecialPage {
                                $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
                        }
                } else {
+                       $trxProfiler->setSilenced( true );
                        $this->attemptConfirm( $code );
+                       $trxProfiler->setSilenced( false );
                }
        }
 
@@ -146,7 +147,7 @@ class EmailConfirmation extends UnlistedSpecialPage {
         *
         * @param string $code Confirmation code
         */
-       function attemptConfirm( $code ) {
+       private function attemptConfirm( $code ) {
                $user = User::newFromConfirmationCode( $code, User::READ_LATEST );
                if ( !is_object( $user ) ) {
                        $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
index 0a98721..6aeb2c3 100644 (file)
@@ -363,7 +363,7 @@ class SpecialContributions extends IncludableSpecialPage {
                        if ( $sp->getUser()->isAllowed( 'suppressionlog' ) ) {
                                $tools['log-suppression'] = $linkRenderer->makeKnownLink(
                                        SpecialPage::getTitleFor( 'Log', 'suppress' ),
-                                       $sp->msg( 'sp-contributions-suppresslog' )->text(),
+                                       $sp->msg( 'sp-contributions-suppresslog', $username )->text(),
                                        [],
                                        [ 'offender' => $username ]
                                );
@@ -385,7 +385,7 @@ class SpecialContributions extends IncludableSpecialPage {
                if ( $sp->getUser()->isAllowed( 'deletedhistory' ) ) {
                        $tools['deletedcontribs'] = $linkRenderer->makeKnownLink(
                                SpecialPage::getTitleFor( 'DeletedContributions', $username ),
-                               $sp->msg( 'sp-contributions-deleted' )->text()
+                               $sp->msg( 'sp-contributions-deleted', $username )->text()
                        );
                }
 
index b5c66ff..d2e3e7f 100644 (file)
@@ -39,12 +39,15 @@ class EmailInvalidation extends UnlistedSpecialPage {
        function execute( $code ) {
                // Ignore things like master queries/connections on GET requests.
                // It's very convenient to just allow formless link usage.
-               Profiler::instance()->getTransactionProfiler()->resetExpectations();
+               $trxProfiler = Profiler::instance()->getTransactionProfiler();
 
                $this->setHeaders();
                $this->checkReadOnly();
                $this->checkPermissions();
+
+               $trxProfiler->setSilenced( true );
                $this->attemptInvalidate( $code );
+               $trxProfiler->setSilenced( false );
        }
 
        /**
@@ -53,7 +56,7 @@ class EmailInvalidation extends UnlistedSpecialPage {
         *
         * @param string $code Confirmation code
         */
-       function attemptInvalidate( $code ) {
+       private function attemptInvalidate( $code ) {
                $user = User::newFromConfirmationCode( $code, User::READ_LATEST );
                if ( !is_object( $user ) ) {
                        $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
index 9690d45..26b86f9 100644 (file)
@@ -100,6 +100,25 @@ class SpecialSearch extends SpecialPage {
         * @param string $par
         */
        public function execute( $par ) {
+               $request = $this->getRequest();
+
+               // Fetch the search term
+               $search = str_replace( "\n", " ", $request->getText( 'search' ) );
+
+               // Historically search terms have been accepted not only in the search query
+               // parameter, but also as part of the primary url. This can have PII implications
+               // in releasing page view data. As such issue a 301 redirect to the correct
+               // URL.
+               if ( strlen( $par ) && !strlen( $search ) ) {
+                       $query = $request->getValues();
+                       unset( $query['title'] );
+                       // Strip underscores from title parameter; most of the time we'll want
+                       // text form here. But don't strip underscores from actual text params!
+                       $query['search'] = str_replace( '_', ' ', $par );
+                       $this->getOutput()->redirect( $this->getPageTitle()->getFullURL( $query ), 301 );
+                       return;
+               }
+
                $this->setHeaders();
                $this->outputHeader();
                $out = $this->getOutput();
@@ -110,15 +129,6 @@ class SpecialSearch extends SpecialPage {
                ] );
                $this->addHelpLink( 'Help:Searching' );
 
-               // Strip underscores from title parameter; most of the time we'll want
-               // text form here. But don't strip underscores from actual text params!
-               $titleParam = str_replace( '_', ' ', $par );
-
-               $request = $this->getRequest();
-
-               // Fetch the search term
-               $search = str_replace( "\n", " ", $request->getText( 'search', $titleParam ) );
-
                $this->load();
                if ( !is_null( $request->getVal( 'nsRemember' ) ) ) {
                        $this->saveNamespaces();
index e957b3c..47bed62 100644 (file)
@@ -142,7 +142,7 @@ class SpecialTags extends SpecialPage {
                        Xml::tags( 'th', null, $this->msg( 'tags-source-header' )->parse() ) .
                        Xml::tags( 'th', null, $this->msg( 'tags-active-header' )->parse() ) .
                        Xml::tags( 'th', null, $this->msg( 'tags-hitcount-header' )->parse() ) .
-                       ( $userCanManage ?
+                       ( ( $userCanManage || $userCanDelete ) ?
                                Xml::tags( 'th', [ 'class' => 'unsortable' ],
                                        $this->msg( 'tags-actions-header' )->parse() ) :
                                '' )
@@ -266,7 +266,7 @@ class SpecialTags extends SpecialPage {
 
                }
 
-               if ( $actionLinks ) {
+               if ( $showDeleteActions || $showManageActions ) {
                        $newRow .= Xml::tags( 'td', null, $this->getLanguage()->pipeList( $actionLinks ) );
                }
 
index 5d230c0..65f0680 100644 (file)
@@ -354,6 +354,9 @@ class PageArchive {
         * Once restored, the items will be removed from the archive tables.
         * The deletion log will be updated with an undeletion notice.
         *
+        * This also sets Status objects, $this->fileStatus and $this->revisionStatus
+        * (depending what operations are attempted).
+        *
         * @param array $timestamps Pass an empty array to restore all revisions,
         *   otherwise list the ones to undelete.
         * @param string $comment
@@ -439,9 +442,8 @@ class PageArchive {
        }
 
        /**
-        * This is the meaty bit -- restores archived revisions of the given page
-        * to the cur/old tables. If the page currently exists, all revisions will
-        * be stuffed into old, otherwise the most recent will go into cur.
+        * This is the meaty bit -- It restores archived revisions of the given page
+        * to the revision table.
         *
         * @param array $timestamps Pass an empty array to restore all revisions,
         *   otherwise list the ones to undelete.
@@ -455,8 +457,10 @@ class PageArchive {
                        throw new ReadOnlyError();
                }
 
-               $restoreAll = empty( $timestamps );
                $dbw = wfGetDB( DB_MASTER );
+               $dbw->startAtomic( __METHOD__ );
+
+               $restoreAll = empty( $timestamps );
 
                # Does this page already exist? We'll have to update it...
                $article = WikiPage::factory( $this->title );
@@ -477,11 +481,9 @@ class PageArchive {
                        # Page already exists. Import the history, and if necessary
                        # we'll update the latest revision field in the record.
 
-                       $previousRevId = $page->page_latest;
-
                        # Get the time span of this page
                        $previousTimestamp = $dbw->selectField( 'revision', 'rev_timestamp',
-                               [ 'rev_id' => $previousRevId ],
+                               [ 'rev_id' => $page->page_latest ],
                                __METHOD__ );
 
                        if ( $previousTimestamp === false ) {
@@ -489,13 +491,13 @@ class PageArchive {
 
                                $status = Status::newGood( 0 );
                                $status->warning( 'undeleterevision-missing' );
+                               $dbw->endAtomic( __METHOD__ );
 
                                return $status;
                        }
                } else {
                        # Have to create a new article...
                        $makepage = true;
-                       $previousRevId = 0;
                        $previousTimestamp = 0;
                }
 
@@ -508,7 +510,9 @@ class PageArchive {
                }
 
                $fields = [
+                       'ar_id',
                        'ar_rev_id',
+                       'rev_id',
                        'ar_text',
                        'ar_comment',
                        'ar_user',
@@ -531,11 +535,14 @@ class PageArchive {
                /**
                 * Select each archived revision...
                 */
-               $result = $dbw->select( 'archive',
+               $result = $dbw->select(
+                       [ 'archive', 'revision' ],
                        $fields,
                        $oldWhere,
                        __METHOD__,
-                       /* options */ [ 'ORDER BY' => 'ar_timestamp' ]
+                       /* options */
+                       [ 'ORDER BY' => 'ar_timestamp' ],
+                       [ 'revision' => [ 'LEFT JOIN', 'ar_rev_id=rev_id' ] ]
                );
 
                $rev_count = $result->numRows();
@@ -544,116 +551,182 @@ class PageArchive {
 
                        $status = Status::newGood( 0 );
                        $status->warning( "undelete-no-results" );
+                       $dbw->endAtomic( __METHOD__ );
 
                        return $status;
                }
 
-               $result->seek( $rev_count - 1 ); // move to last
-               $row = $result->fetchObject(); // get newest archived rev
-               $oldPageId = (int)$row->ar_page_id; // pass this to ArticleUndelete hook
-               $result->seek( 0 ); // move back
+               // We use ar_id because there can be duplicate ar_rev_id even for the same
+               // page.  In this case, we may be able to restore the first one.
+               $restoreFailedArIds = [];
 
-               // grab the content to check consistency with global state before restoring the page.
-               $revision = Revision::newFromArchiveRow( $row,
-                       [
-                               'title' => $article->getTitle(), // used to derive default content model
-                       ]
-               );
-               $user = User::newFromName( $revision->getUserText( Revision::RAW ), false );
-               $content = $revision->getContent( Revision::RAW );
+               // Map rev_id to the ar_id that is allowed to use it.  When checking later,
+               // if it doesn't match, the current ar_id can not be restored.
 
-               // NOTE: article ID may not be known yet. prepareSave() should not modify the database.
-               $status = $content->prepareSave( $article, 0, -1, $user );
+               // Value can be an ar_id or -1 (-1 means no ar_id can use it, since the
+               // rev_id is taken before we even start the restore).
+               $allowedRevIdToArIdMap = [];
 
-               if ( !$status->isOK() ) {
-                       return $status;
-               }
+               $latestRestorableRow = null;
 
-               if ( $makepage ) {
-                       // Check the state of the newest to-be version...
-                       if ( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
-                               return Status::newFatal( "undeleterevdel" );
+               foreach ( $result as $row ) {
+                       if ( $row->ar_rev_id ) {
+                               // rev_id is taken even before we start restoring.
+                               if ( $row->ar_rev_id === $row->rev_id ) {
+                                       $restoreFailedArIds[] = $row->ar_id;
+                                       $allowedRevIdToArIdMap[$row->ar_rev_id] = -1;
+                               } else {
+                                       // rev_id is not taken yet in the DB, but it might be taken
+                                       // by a prior revision in the same restore operation. If
+                                       // not, we need to reserve it.
+                                       if ( isset( $allowedRevIdToArIdMap[$row->ar_rev_id] ) ) {
+                                               $restoreFailedArIds[] = $row->ar_id;
+                                       } else {
+                                               $allowedRevIdToArIdMap[$row->ar_rev_id] = $row->ar_id;
+                                               $latestRestorableRow = $row;
+                                       }
+                               }
+                       } else {
+                               // If ar_rev_id is null, there can't be a collision, and a
+                               // rev_id will be chosen automatically.
+                               $latestRestorableRow = $row;
                        }
-                       // Safe to insert now...
-                       $newid = $article->insertOn( $dbw, $row->ar_page_id );
-                       if ( $newid === false ) {
-                               // The old ID is reserved; let's pick another
-                               $newid = $article->insertOn( $dbw );
+               }
+
+               $result->seek( 0 ); // move back
+
+               $oldPageId = 0;
+               if ( $latestRestorableRow !== null ) {
+                       $oldPageId = (int)$latestRestorableRow->ar_page_id; // pass this to ArticleUndelete hook
+
+                       // grab the content to check consistency with global state before restoring the page.
+                       $revision = Revision::newFromArchiveRow( $latestRestorableRow,
+                               [
+                                       'title' => $article->getTitle(), // used to derive default content model
+                               ]
+                       );
+                       $user = User::newFromName( $revision->getUserText( Revision::RAW ), false );
+                       $content = $revision->getContent( Revision::RAW );
+
+                       // NOTE: article ID may not be known yet. prepareSave() should not modify the database.
+                       $status = $content->prepareSave( $article, 0, -1, $user );
+                       if ( !$status->isOK() ) {
+                               $dbw->endAtomic( __METHOD__ );
+
+                               return $status;
                        }
-                       $pageId = $newid;
+               }
+
+               $newid = false; // newly created page ID
+               $restored = 0; // number of revisions restored
+               /** @var Revision $revision */
+               $revision = null;
+
+               // If there are no restorable revisions, we can skip most of the steps.
+               if ( $latestRestorableRow === null ) {
+                       $failedRevisionCount = $rev_count;
                } else {
-                       // Check if a deleted revision will become the current revision...
-                       if ( $row->ar_timestamp > $previousTimestamp ) {
+                       if ( $makepage ) {
                                // Check the state of the newest to-be version...
-                               if ( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
+                               if ( !$unsuppress
+                                       && ( $latestRestorableRow->ar_deleted & Revision::DELETED_TEXT )
+                               ) {
+                                       $dbw->endAtomic( __METHOD__ );
+
                                        return Status::newFatal( "undeleterevdel" );
                                }
+                               // Safe to insert now...
+                               $newid = $article->insertOn( $dbw, $latestRestorableRow->ar_page_id );
+                               if ( $newid === false ) {
+                                       // The old ID is reserved; let's pick another
+                                       $newid = $article->insertOn( $dbw );
+                               }
+                               $pageId = $newid;
+                       } else {
+                               // Check if a deleted revision will become the current revision...
+                               if ( $latestRestorableRow->ar_timestamp > $previousTimestamp ) {
+                                       // Check the state of the newest to-be version...
+                                       if ( !$unsuppress
+                                               && ( $latestRestorableRow->ar_deleted & Revision::DELETED_TEXT )
+                                       ) {
+                                               $dbw->endAtomic( __METHOD__ );
+
+                                               return Status::newFatal( "undeleterevdel" );
+                                       }
+                               }
+
+                               $newid = false;
+                               $pageId = $article->getId();
                        }
 
-                       $newid = false;
-                       $pageId = $article->getId();
-               }
+                       foreach ( $result as $row ) {
+                               // Check for key dupes due to needed archive integrity.
+                               if ( $row->ar_rev_id && $allowedRevIdToArIdMap[$row->ar_rev_id] !== $row->ar_id ) {
+                                       continue;
+                               }
+                               // Insert one revision at a time...maintaining deletion status
+                               // unless we are specifically removing all restrictions...
+                               $revision = Revision::newFromArchiveRow( $row,
+                                       [
+                                               'page' => $pageId,
+                                               'title' => $this->title,
+                                               'deleted' => $unsuppress ? 0 : $row->ar_deleted
+                                       ] );
 
-               $revision = null;
-               $restored = 0;
+                               $revision->insertOn( $dbw );
+                               $restored++;
 
-               foreach ( $result as $row ) {
-                       // Check for key dupes due to needed archive integrity.
-                       if ( $row->ar_rev_id ) {
-                               $exists = $dbw->selectField( 'revision', '1',
-                                       [ 'rev_id' => $row->ar_rev_id ], __METHOD__ );
-                               if ( $exists ) {
-                                       continue; // don't throw DB errors
-                               }
+                               Hooks::run( 'ArticleRevisionUndeleted',
+                                       [ &$this->title, $revision, $row->ar_page_id ] );
                        }
-                       // Insert one revision at a time...maintaining deletion status
-                       // unless we are specifically removing all restrictions...
-                       $revision = Revision::newFromArchiveRow( $row,
-                               [
-                                       'page' => $pageId,
-                                       'title' => $this->title,
-                                       'deleted' => $unsuppress ? 0 : $row->ar_deleted
-                               ] );
-
-                       $revision->insertOn( $dbw );
-                       $restored++;
 
-                       Hooks::run( 'ArticleRevisionUndeleted', [ &$this->title, $revision, $row->ar_page_id ] );
-               }
-               # Now that it's safely stored, take it out of the archive
-               $dbw->delete( 'archive',
-                       $oldWhere,
-                       __METHOD__ );
+                       // Now that it's safely stored, take it out of the archive
+                       // Don't delete rows that we failed to restore
+                       $toDeleteConds = $oldWhere;
+                       $failedRevisionCount = count( $restoreFailedArIds );
+                       if ( $failedRevisionCount > 0 ) {
+                               $toDeleteConds[] = 'ar_id NOT IN ( ' . $dbw->makeList( $restoreFailedArIds ) . ' )';
+                       }
 
-               // Was anything restored at all?
-               if ( $restored == 0 ) {
-                       return Status::newGood( 0 );
+                       $dbw->delete( 'archive',
+                               $toDeleteConds,
+                               __METHOD__ );
                }
 
-               $created = (bool)$newid;
+               $status = Status::newGood( $restored );
 
-               // Attach the latest revision to the page...
-               $wasnew = $article->updateIfNewerOn( $dbw, $revision, $previousRevId );
-               if ( $created || $wasnew ) {
-                       // Update site stats, link tables, etc
-                       $article->doEditUpdates(
-                               $revision,
-                               User::newFromName( $revision->getUserText( Revision::RAW ), false ),
-                               [
-                                       'created' => $created,
-                                       'oldcountable' => $oldcountable,
-                                       'restored' => true
-                               ]
-                       );
+               if ( $failedRevisionCount > 0 ) {
+                       $status->warning(
+                               wfMessage( 'undeleterevision-duplicate-revid', $failedRevisionCount ) );
                }
 
-               Hooks::run( 'ArticleUndelete', [ &$this->title, $created, $comment, $oldPageId ] );
+               // Was anything restored at all?
+               if ( $restored ) {
+                       $created = (bool)$newid;
+                       // Attach the latest revision to the page...
+                       $wasnew = $article->updateIfNewerOn( $dbw, $revision );
+                       if ( $created || $wasnew ) {
+                               // Update site stats, link tables, etc
+                               $article->doEditUpdates(
+                                       $revision,
+                                       User::newFromName( $revision->getUserText( Revision::RAW ), false ),
+                                       [
+                                               'created' => $created,
+                                               'oldcountable' => $oldcountable,
+                                               'restored' => true
+                                       ]
+                               );
+                       }
 
-               if ( $this->title->getNamespace() == NS_FILE ) {
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->title, 'imagelinks' ) );
+                       Hooks::run( 'ArticleUndelete', [ &$this->title, $created, $comment, $oldPageId ] );
+                       if ( $this->title->getNamespace() == NS_FILE ) {
+                               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->title, 'imagelinks' ) );
+                       }
                }
 
-               return Status::newGood( $restored );
+               $dbw->endAtomic( __METHOD__ );
+
+               return $status;
        }
 
        /**
index 03c864a..e2f7763 100644 (file)
@@ -44,7 +44,7 @@ abstract class UploadBase {
        protected $mDesiredDestName, $mDestName, $mRemoveTempFile, $mSourceType;
        protected $mTitle = false, $mTitleError = 0;
        protected $mFilteredName, $mFinalExtension;
-       protected $mLocalFile, $mFileSize, $mFileProps;
+       protected $mLocalFile, $mStashFile, $mFileSize, $mFileProps;
        protected $mBlackListedExtensions;
        protected $mJavaDetected, $mSVGNSError;
 
@@ -774,27 +774,6 @@ abstract class UploadBase {
         * @since  1.25
         */
        public function postProcessUpload() {
-               global $wgUploadThumbnailRenderMap;
-
-               $jobs = [];
-
-               $sizes = $wgUploadThumbnailRenderMap;
-               rsort( $sizes );
-
-               $file = $this->getLocalFile();
-
-               foreach ( $sizes as $size ) {
-                       if ( $file->isVectorized() || $file->getWidth() > $size ) {
-                               $jobs[] = new ThumbnailRenderJob(
-                                       $file->getTitle(),
-                                       [ 'transformParams' => [ 'width' => $size ] ]
-                               );
-                       }
-               }
-
-               if ( $jobs ) {
-                       JobQueueGroup::singleton()->push( $jobs );
-               }
        }
 
        /**
@@ -933,7 +912,7 @@ abstract class UploadBase {
        /**
         * Return the local file and initializes if necessary.
         *
-        * @return LocalFile|UploadStashFile|null
+        * @return LocalFile|null
         */
        public function getLocalFile() {
                if ( is_null( $this->mLocalFile ) ) {
@@ -945,23 +924,29 @@ abstract class UploadBase {
        }
 
        /**
-        * Like stashFile(), but respects extensions' wishes to prevent the stashing.
+        * @return UploadStashFile|null
+        */
+       public function getStashFile() {
+               return $this->mStashFile;
+       }
+
+       /**
+        * Like stashFile(), but respects extensions' wishes to prevent the stashing. verifyUpload() must
+        * be called before calling this method (unless $isPartial is true).
         *
         * Upload stash exceptions are also caught and converted to an error status.
         *
         * @since 1.28
         * @param User $user
+        * @param bool $isPartial Pass `true` if this is a part of a chunked upload (not a complete file).
         * @return Status If successful, value is an UploadStashFile instance
         */
-       public function tryStashFile( User $user ) {
-               $props = $this->mFileProps;
-               $error = null;
-               Hooks::run( 'UploadStashFile', [ $this, $user, $props, &$error ] );
-               if ( $error ) {
-                       if ( !is_array( $error ) ) {
-                               $error = [ $error ];
+       public function tryStashFile( User $user, $isPartial = false ) {
+               if ( !$isPartial ) {
+                       $error = $this->runUploadStashFileHook( $user );
+                       if ( $error ) {
+                               return call_user_func_array( 'Status::newFatal', $error );
                        }
-                       return call_user_func_array( 'Status::newFatal', $error );
                }
                try {
                        $file = $this->doStashFile( $user );
@@ -971,6 +956,22 @@ abstract class UploadBase {
                }
        }
 
+       /**
+        * @param User $user
+        * @return array|null Error message and parameters, null if there's no error
+        */
+       protected function runUploadStashFileHook( User $user ) {
+               $props = $this->mFileProps;
+               $error = null;
+               Hooks::run( 'UploadStashFile', [ $this, $user, $props, &$error ] );
+               if ( $error ) {
+                       if ( !is_array( $error ) ) {
+                               $error = [ $error ];
+                       }
+               }
+               return $error;
+       }
+
        /**
         * If the user does not supply all necessary information in the first upload
         * form submission (either by accident or by design) then we may want to
@@ -1003,7 +1004,7 @@ abstract class UploadBase {
        protected function doStashFile( User $user = null ) {
                $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $user );
                $file = $stash->stashFile( $this->mTempPath, $this->getSourceType() );
-               $this->mLocalFile = $file;
+               $this->mStashFile = $file;
 
                return $file;
        }
@@ -1981,18 +1982,16 @@ abstract class UploadBase {
         * @return array Image info
         */
        public function getImageInfo( $result ) {
-               $file = $this->getLocalFile();
-               /** @todo This cries out for refactoring.
-                *  We really want to say $file->getAllInfo(); here.
-                * Perhaps "info" methods should be moved into files, and the API should
-                * just wrap them in queries.
-                */
-               if ( $file instanceof UploadStashFile ) {
+               $localFile = $this->getLocalFile();
+               $stashFile = $this->getStashFile();
+               // Calling a different API module depending on whether the file was stashed is less than optimal.
+               // In fact, calling API modules here at all is less than optimal. Maybe it should be refactored.
+               if ( $stashFile ) {
                        $imParam = ApiQueryStashImageInfo::getPropertyNames();
-                       $info = ApiQueryStashImageInfo::getInfo( $file, array_flip( $imParam ), $result );
+                       $info = ApiQueryStashImageInfo::getInfo( $stashFile, array_flip( $imParam ), $result );
                } else {
                        $imParam = ApiQueryImageInfo::getPropertyNames();
-                       $info = ApiQueryImageInfo::getInfo( $file, array_flip( $imParam ), $result );
+                       $info = ApiQueryImageInfo::getInfo( $localFile, array_flip( $imParam ), $result );
                }
 
                return $info;
index cc1d698..9145a85 100644 (file)
@@ -38,12 +38,11 @@ class UploadFromChunks extends UploadFromFile {
        /**
         * Setup local pointers to stash, repo and user (similar to UploadFromStash)
         *
-        * @param User|null $user Default: null
+        * @param User $user
         * @param UploadStash|bool $stash Default: false
         * @param FileRepo|bool $repo Default: false
         */
-       public function __construct( $user = null, $stash = false, $repo = false ) {
-               // user object. sometimes this won't exist, as when running from cron.
+       public function __construct( User $user, $stash = false, $repo = false ) {
                $this->user = $user;
 
                if ( $repo ) {
@@ -77,18 +76,18 @@ class UploadFromChunks extends UploadFromFile {
 
                $this->verifyChunk();
                // Create a local stash target
-               $this->mLocalFile = parent::doStashFile( $user );
+               $this->mStashFile = parent::doStashFile( $user );
                // Update the initial file offset (based on file size)
-               $this->mOffset = $this->mLocalFile->getSize();
-               $this->mFileKey = $this->mLocalFile->getFileKey();
+               $this->mOffset = $this->mStashFile->getSize();
+               $this->mFileKey = $this->mStashFile->getFileKey();
 
                // Output a copy of this first to chunk 0 location:
-               $this->outputChunk( $this->mLocalFile->getPath() );
+               $this->outputChunk( $this->mStashFile->getPath() );
 
                // Update db table to reflect initial "chunk" state
                $this->updateChunkStatus();
 
-               return $this->mLocalFile;
+               return $this->mStashFile;
        }
 
        /**
@@ -159,12 +158,25 @@ class UploadFromChunks extends UploadFromFile {
                        return $status;
                }
 
-               // Update the mTempPath and mLocalFile
+               // Update the mTempPath and mStashFile
                // (for FileUpload or normal Stash to take over)
                $tStart = microtime( true );
-               $this->mLocalFile = parent::doStashFile( $this->user );
+               // This is a re-implementation of UploadBase::tryStashFile(), we can't call it because we
+               // override doStashFile() with completely different functionality in this class...
+               $error = $this->runUploadStashFileHook( $this->user );
+               if ( $error ) {
+                       call_user_func_array( [ $status, 'fatal' ], $error );
+                       return $status;
+               }
+               try {
+                       $this->mStashFile = parent::doStashFile( $this->user );
+               } catch ( UploadStashException $e ) {
+                       $status->fatal( 'uploadstash-exception', get_class( $e ), $e->getMessage() );
+                       return $status;
+               }
+
                $tAmount = microtime( true ) - $tStart;
-               $this->mLocalFile->setLocalReference( $tmpFile ); // reuse (e.g. for getImageInfo())
+               $this->mStashFile->setLocalReference( $tmpFile ); // reuse (e.g. for getImageInfo())
                wfDebugLog( 'fileconcatenate', "Stashed combined file ($i chunks) in $tAmount seconds." );
 
                return $status;
@@ -235,8 +247,6 @@ class UploadFromChunks extends UploadFromFile {
                        $this->getOffset() . ' inx:' . $this->getChunkIndex() . "\n" );
 
                $dbw = $this->repo->getMasterDB();
-               // Use a quick transaction since we will upload the full temp file into shared
-               // storage, which takes time for large files. We don't want to hold locks then.
                $dbw->update(
                        'uploadstash',
                        [
@@ -247,7 +257,6 @@ class UploadFromChunks extends UploadFromFile {
                        [ 'us_key' => $this->mFileKey ],
                        __METHOD__
                );
-               $dbw->commit( __METHOD__, 'flush' );
        }
 
        /**
index 50bcbc4..1fbdb7d 100644 (file)
@@ -143,24 +143,6 @@ class UploadFromStash extends UploadBase {
                return $this->mFileProps['sha1'];
        }
 
-       /*
-        * protected function verifyFile() inherited
-        */
-
-       /**
-        * Stash the file.
-        *
-        * @param User $user
-        * @return UploadStashFile
-        */
-       protected function doStashFile( User $user = null ) {
-               // replace mLocalFile with an instance of UploadStashFile, which adds some methods
-               // that are useful for stashed files.
-               $this->mLocalFile = parent::doStashFile( $user );
-
-               return $this->mLocalFile;
-       }
-
        /**
         * Remove a temporarily kept file stashed by saveTempUploadedFile().
         * @return bool Success
index 7ba1d91..83cfa40 100644 (file)
@@ -1537,9 +1537,12 @@ class User implements IDBAccessObject {
                foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
                        $defOpt[$langCode == $wgContLang->getCode() ? 'variant' : "variant-$langCode"] = $langCode;
                }
-               $namespaces = MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
-               foreach ( $namespaces as $nsnum => $nsname ) {
-                       $defOpt['searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
+
+               // NOTE: don't use SearchEngineConfig::getSearchableNamespaces here,
+               // since extensions may change the set of searchable namespaces depending
+               // on user groups/permissions.
+               foreach ( $wgNamespacesToBeSearchedDefault as $nsnum => $val ) {
+                       $defOpt['searchNs' . $nsnum] = (boolean)$val;
                }
                $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
 
@@ -4187,6 +4190,8 @@ class User implements IDBAccessObject {
         * login credentials aren't being hijacked with a foreign form
         * submission.
         *
+        * The $salt for 'edit' and 'csrf' tokens is the default (empty string).
+        *
         * @since 1.19
         * @param string|array $salt Array of Strings Optional function-specific data for hashing
         * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
index d96710a..8b39d77 100644 (file)
  * @defgroup Language Language
  */
 
-if ( !defined( 'MEDIAWIKI' ) ) {
-       echo "This file is part of MediaWiki, it is not a valid entry point.\n";
-       exit( 1 );
-}
-
 use CLDRPluralRuleParser\Evaluator;
 
 /**
index b414d5e..0646f21 100644 (file)
                        "Wōdenhelm",
                        "아라",
                        "Dpk",
-                       "Macofe"
+                       "Macofe",
+                       "WhatamIdoing",
+                       "Hogweard",
+                       "Amire80"
                ]
        },
        "tog-underline": "Mearc under hlencan:",
        "october-date": "$1. Winterfylleðes",
        "november-date": "$1. Blōtmōnaðes",
        "december-date": "$1. Ǣrran Gēolan",
+       "period-am": "on undernmǣl",
+       "period-pm": "on ofernōn",
        "pagecategories": "{{PLURAL:$1|Flocc|Floccas}}",
        "category_header": "Trametas in \"$1\" flocce",
        "subcategories": "Underfloccas",
        "jumptonavigation": "þurhfōr",
        "jumptosearch": "sēcan",
        "view-pool-error": "Wālā, þā þegntōlas nū oferlīce wyrcaþ.\nTō mænige brūcendas gesēcaþ tō sēonne þisne tramet.\nWē biddaþ þæt þū abīde scortne tīman ǣr þū gesēce to sēonne þisne tramet eft.\n\n$1",
+       "pool-queuefull": "Pundfaldes forepenn is full",
        "pool-errorunknown": "Uncūþ wōh",
+       "pool-servererror": "Seo pundaldgetalere þēgnung nis gearo",
        "aboutsite": "Gecȳþness ymbe {{GRAMMAR:wrēgendlīc|{{SITENAME}}}}",
        "aboutpage": "Project:Gefrǣge",
        "copyright": "Man mæg innunge under $1 findan, būton þǣr hit is elles amearcod.",
        "minoredit": "Þēos is lytel adihtung",
        "watchthis": "Behealdan þisne tramet",
        "savearticle": "Hordian tramet",
+       "publishpage": "Geswutele tramet",
+       "publishchanges": "Geswutele wrixlung",
        "preview": "Forebysen",
        "showpreview": "Īwan forebysene",
        "showdiff": "Īwan andwendunga",
        "watchlisttools-view": "Sēon andwendunga",
        "watchlisttools-edit": "Sēon and adihtan behealdungtæl",
        "watchlisttools-raw": "Adihtan hrēaw behealdungtæl",
-       "signature": "[[{{ns:user}}:$1|$2]]\n([[{{ns:user_talk}}:$1|mōtung]])",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|mōtung]])",
        "version": "Fadung",
        "version-specialpages": "Syndrige trametas",
        "version-other": "Ōðer",
index 80df33f..5e8b4b2 100644 (file)
        "undeletedrevisions-files": "أسترجعت {{PLURAL:$1||مراجعة واحدة|مراجعتان|$1 مراجعات|$1 مراجعة}}  و{{PLURAL:$2||ملف واحد|ملفان|$2 ملفات|$2 ملفًا|$2 ملف}}",
        "undeletedfiles": "أسترجع {{PLURAL:$1||ملف واحد|ملفان|$1 ملفات|$1 ملفًا|$1 ملف}}",
        "cannotundelete": "فشل الاسترجاع؛\n$1",
-       "undeletedpage": "'''تÙ\85 Ø§Ø³ØªØ±Ø¬Ø§Ø¹ $1'''\n\nراجع [[Special:Log/delete|سجÙ\84 Ø§Ù\84حدف]] لمعاينة عمليات الحذف والاسترجاعات الحديثة.",
+       "undeletedpage": "'''تÙ\85 Ø§Ø³ØªØ±Ø¬Ø§Ø¹ $1'''\n\nراجع [[Special:Log/delete|سجÙ\84 Ø§Ù\84حذف]] لمعاينة عمليات الحذف والاسترجاعات الحديثة.",
        "undelete-header": "انظر الصفحات المحذوفة حديثا في [[Special:Log/delete|سجل الحذف]].",
        "undelete-search-title": "البحث في الصفحات المحذوفة",
        "undelete-search-box": "ابحث في الصفحات المحذوفة",
index 4c8c6d0..bd5035f 100644 (file)
        "action-applychangetags": "aplicar etiquetes xunto colos cambios",
        "action-changetags": "amestar y desaniciar etiquetes arbitraries en revisiones individuales y entraes del rexistru",
        "action-deletechangetags": "desaniciar etiquetes de la base de datos",
+       "action-purge": "purgar esta páxina",
        "nchanges": "{{PLURAL:$1|un cambiu|$1 cambios}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|dende la última visita}}",
        "enhancedrc-history": "historial",
        "uploadstash-errclear": "Falló'l desaniciu de los ficheros.",
        "uploadstash-refresh": "Anovar la llista de ficheros",
        "uploadstash-thumbnail": "ver miniatura",
+       "uploadstash-exception": "Nun pudo guardase la subida nel almacén ($1): «$2».",
        "invalid-chunk-offset": "Allugamientu inválidu del fragmentu",
        "img-auth-accessdenied": "Accesu denegáu",
        "img-auth-nopathinfo": "Falta PATH_INFO.\nEl to sirvidor nun ta configuráu pa pasar esta información.\nPue tar basáu en CGI y nun tener sofitu pa img_auth.\nVer https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "watchnologin": "Non identificáu",
        "addwatch": "Amestar a la llista de siguimientu",
        "addedwatchtext": "«[[:$1]]» y la so páxina d'alderique amestáronse a la to [[Special:Watchlist|llista de siguimientu]].",
+       "addedwatchtext-talk": "«[[:$1]]» y la so páxina asociada amestáronse a la to [[Special:Watchlist|llista de siguimientu]].",
        "addedwatchtext-short": "Amestóse la páxina «$1» a la to llista de siguimientu.",
        "removewatch": "Desaniciar de la llista de siguimientu",
        "removedwatchtext": "«[[:$1]]» y la so páxina d'alderique desaniciáronse de la to [[Special:Watchlist|llista de siguimientu]].",
+       "removedwatchtext-talk": "«[[:$1]]» y la so páxina asociada desaniciáronse de la to [[Special:Watchlist|llista de siguimientu]].",
        "removedwatchtext-short": "Desanicióse la páxina «$1» de la to llista de siguimientu.",
        "watch": "Vixilar",
        "watchthispage": "Vixilar esta páxina",
        "undeletehistorynoadmin": "Esta páxina foi esborrada. El motivu del esborráu amuésase\nnel resume d'embaxo, amás de detalles de los usuarios qu'editaron esta páxina enantes\nde ser esborrada. El testu actual d'estes revisiones esborraes ta disponible namái pa los alministradores.",
        "undelete-revision": "Revisión esborrada de $1 ($4, a les $5) fecha por $3:",
        "undeleterevision-missing": "Falta la revisión o nun ye válida. Sieque l'enllaz nun seya correutu, o que la\nrevisión fuera restaurada o eliminada del archivu.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Una revisión nun pudo|$1 revisiones nun pudieron}} restaurase porque {{PLURAL:$1|taba usándose la so|taben usándose les sos}} <code>rev_id</code>.",
        "undelete-nodiff": "Nun s'atopó revisión previa.",
        "undeletebtn": "Restaurar",
        "undeletelink": "ver/restaurar",
        "undeletedrevisions": "{{PLURAL:$1|1 revisión restaurada|$1 revisiones restauraes}}",
        "undeletedrevisions-files": "{{PLURAL:$1|1 revisión|$1 revisiones}} y {{PLURAL:$2|1 archivu|$2 archivos}} restauraos",
        "undeletedfiles": "{{PLURAL:$1|1 archivu restauráu|$1 archivos restauraos}}",
-       "cannotundelete": "Falló la restauración:\n$1",
+       "cannotundelete": "Falló total o parcialmente la restauración:\n$1",
        "undeletedpage": "'''Restauróse $1'''\n\nConsulta'l [[Special:Log/delete|rexistru d'esborraos]] pa ver los esborraos y restauraciones de recién.",
        "undelete-header": "Mira nel [[Special:Log/delete|rexistru d'esborraos]] les páxines esborraes recién.",
        "undelete-search-title": "Buscar páxines desaniciaes",
        "sp-contributions-newbies-sub": "Namái les cuentes nueves",
        "sp-contributions-newbies-title": "Contribuciones d'usuariu pa cuentes nueves",
        "sp-contributions-blocklog": "rexistru de bloqueos",
-       "sp-contributions-suppresslog": "collaboraciones del usuariu desaniciaes",
-       "sp-contributions-deleted": "Contribuciones d'usuariu desaniciaes",
+       "sp-contributions-suppresslog": "collaboraciones {{GENDER:$1|del usuariu|de la usuaria}} suprimíes",
+       "sp-contributions-deleted": "collaboraciones {{GENDER:$1|del usuariu|de la usuaria}} desaniciaes",
        "sp-contributions-uploads": "xubes",
        "sp-contributions-logs": "rexistros",
        "sp-contributions-talk": "alderique",
        "authform-notoken": "Falta token",
        "authform-wrongtoken": "Token incorreutu",
        "specialpage-securitylevel-not-allowed-title": "Nun ta permitío",
+       "specialpage-securitylevel-not-allowed": "Sentímoslo, nun tienes permisu pa usar esta páxina porque nun pudo comprobase la to identidá.",
+       "authpage-cannot-login": "Nun pudo empecipiase l'aniciu de sesión.",
+       "authpage-cannot-login-continue": "Nun pudo siguise col aniciu de sesión. Probablemente la sesión caducó.",
+       "authpage-cannot-create": "Nun pudo empecipiase la creación de la cuenta.",
+       "authpage-cannot-create-continue": "Nun pudo siguise la creación de cuenta. Probablemente la sesión caducó.",
+       "authpage-cannot-link": "Nun pudo empecipiase l'enllazáu de la cuenta.",
+       "authpage-cannot-link-continue": "Nun pudo siguise col enllazáu de cuenta. Probablemente la sesión caducó.",
        "cannotauth-not-allowed-title": "Permisu refugáu",
        "cannotauth-not-allowed": "Nun tienes permisu pa usar esta páxina",
+       "changecredentials": "Camudar les credenciales",
+       "changecredentials-submit": "Camudar credenciales",
+       "changecredentials-invalidsubpage": "$1 nun ye un tipu de credencial válidu.",
+       "changecredentials-success": "Camudáronse les tos credenciales.",
+       "removecredentials": "Desaniciar credenciales",
+       "removecredentials-submit": "Desaniciar credenciales",
+       "removecredentials-invalidsubpage": "$1 nun ye un tipu de credencial válidu.",
+       "removecredentials-success": "Desaniciáronse les tos credenciales.",
+       "credentialsform-provider": "Tipu de credenciales:",
        "credentialsform-account": "Nome de la cuenta:",
        "cannotlink-no-provider-title": "Nun hai cuentes enllazables",
        "cannotlink-no-provider": "Nun hai cuentes enllazables.",
        "linkaccounts-success-text": "Enllazóse la cuenta.",
        "linkaccounts-submit": "Enllazar cuentes",
        "unlinkaccounts": "Desenllazar cuentes",
-       "unlinkaccounts-success": "Desenllazóse la cuenta."
+       "unlinkaccounts-success": "Desenllazóse la cuenta.",
+       "authenticationdatachange-ignored": "Nun se xestionó'l cambéu de los datos d'autentificacion. ¿Seique, nun se configuró un fornidor?"
 }
index 026c3f8..3432c23 100644 (file)
        "alllogstext": "{{SITENAME}} üçün bütün mövcud qeydlərin birgə göstərişi.\nQeyd növü, istifadəçi adı və ya təsir edilmiş səhifəni seçməklə daha spesifik ola bilərsiniz.",
        "logempty": "Jurnalda uyğun qeyd tapılmadı.",
        "log-title-wildcard": "Bu mətnlə başlayan başlıqları axtar",
+       "checkbox-select": "Seçin: $1",
+       "checkbox-all": "Hamısı",
+       "checkbox-none": "Heç biri",
+       "checkbox-invert": "Çevir",
        "allpages": "Bütün səhifələr",
        "nextpage": "Sonrakı səhifə ($1)",
        "prevpage": "Əvvəlki səhifə ($1)",
index c6a1dba..c2a09db 100644 (file)
        "emailuser": "بو ایستیفاده‌چی‌یه ایمیل گؤندر",
        "emailuser-title-target": "بو {{GENDER:$1|ایستیفاده‌چی}}‌یه ایمیل گؤندر",
        "emailuser-title-notarget": "ایستیفاده‌چی‌یه ایمیل گؤندر",
-       "emailpagetext": "آشغÛ\8cداکÛ\8c Ù\81Ù\88رÙ\85â\80\8cداÙ\86Ø\8c Ø¨Ù\88 {{GENDER:$1|اÛ\8cستÛ\8cÙ\81ادÙ\87â\80\8cÚ\86Û\8c}}â\80\8cÛ\8cÙ\87 Ø§Û\8cÙ\85Û\8cÙ\84 Ú¯Ø¤Ù\86درÙ\85Ú© Ø§Ù\88Ú\86Ù\88Ù\86 Ø§Û\8cستÛ\8cÙ\81ادÙ\87 Ø§Ø¦Ø¯Ù\87 Ø¨Û\8cÙ\84رسÛ\8cÙ\86Û\8cز.\n[[Special:Preferences|اؤز ØªØ±Ø¬Û\8cØ­Ù\84رÛ\8cÙ\86Û\8cز]]دÙ\87 Ù\88ئرÙ\86 Ø§Û\8cÙ\85Û\8cÙ\84 Ø¢Ø¯Ø±Ø³Û\8cØ\8c Ø¨Ù\88 Ø§Û\8cÙ\85Û\8cÙ\84Û\8cÙ\86 \"From\" Û\8cئرÛ\8cÙ\86دÙ\87 Ú¯Ø¤Ø³ØªØ±Û\8cÙ\84Ù\87â\80\8cجکâ\80\8cدÛ\8cر Ù\88 Ø¨Ù\88Ù\86ا Ú¯Ø¤Ø±Ù\87 Ø§Û\8cÙ\85یلی آلان سیزه موستقیم جاواب گؤندره بیلر.",
+       "emailpagetext": "آشاغÛ\8cداکÛ\8c Ù\81Ù\88رÙ\85داÙ\86Ø\8c Ø¨Ù\88 {{GENDER:$1|اÛ\8cستÛ\8cÙ\81ادÙ\87â\80\8cÚ\86Û\8c}}â\80\8cÛ\8cÙ\87 Ø§Û\8cÙ\85ئÛ\8cÙ\84 Ú¯Ø¤Ù\86درÙ\85Ú© Ø§Û\86Ú\86Ù\88Ù\86 Ø§Û\8cستÛ\8cÙ\81ادÙ\87 Ø§Ø¦Ø¯Ù\87 Ø¨Û\8cÙ\84رسÛ\8cÙ\86Û\8cز.\n[[Special:Preferences|اؤز ØªØ±Ø¬Û\8cØ­Ù\84رÛ\8cÙ\86Û\8cز]]دÙ\87 Ù\88ئرÙ\86 Ø§Û\8cÙ\85ئÛ\8cÙ\84 Ø¢Ø¯Ø±Ø³Û\8cØ\8c Ø¨Ù\88 Ø§Û\8cÙ\85ئÛ\8cÙ\84Û\8cÙ\86 \"From\" Û\8cئرÛ\8cÙ\86دÙ\87 Ú¯Ø¤Ø³ØªØ±Û\8cÙ\84Ù\87â\80\8cرک Ø§Û\8cÙ\85ئیلی آلان سیزه موستقیم جاواب گؤندره بیلر.",
        "defemailsubject": "«$1» آدلی ایستیفاده‌چی‌دن، {{SITENAME}} ایمیلی",
        "usermaildisabled": "ایستیفاده‌چی ایمیلی باغلی‌دیر",
        "usermaildisabledtext": "بو ویکی‌ده باشقا ایستیفاده‌چیلره ایمیل گؤندره بیلنمه‌سینیز",
index 0980639..1dd05c7 100644 (file)
        "tagline": "{{SITENAME}} проектынан",
        "help": "Белешмә",
        "search": "Эҙләү",
-       "search-ignored-headings": " #<!-- был юлды нисек бар шулай ҡалдырығыҙ --> <pre>\n# Эҙләүҙәр инҡар иткән атамалар.\n# Атамаһы булған бит индексланғас та үҙгәртмәләр үҙ көсөнә инәсәк.\n# Буш төҙәтеү менән һеҙ битте яңынан индекслата алаһығыҙ\n# Синтаксис шулай күренә:\n#   * Ошо символға «#» башланған юлдың аҙағына тиклем комментарий була\n#   * Һәр буш булмаған юл - инҡар ителгәндең атамаһы, быға регистр ҙа инә\nИҫкәрмәләр\nҺылтанмалар\nҠарағыҙ шулай уҡ\n#</pre> <!-- был юлды шул көйө ҡалдырығыҙ -->",
+       "search-ignored-headings": " #<!-- был юлды нисек бар шулай ҡалдырығыҙ --> <pre>\n# Эҙләүҙәр инҡар иткән атамалар.\n# Атамаһы булған бит индексланғас та, үҙгәртмәләр үҙ көсөнә инәсәк.\n# Буш төҙәтеү менән һеҙ битте яңынан индекслата алаһығыҙ\n# Синтаксис шулай күренә:\n#   * Ошо символға «#» башланған юлдың аҙағына тиклем комментарий була\n#   * Һәр буш булмаған юл - инҡар ителгәндең атамаһы, быға регистр ҙа инә\nИҫкәрмәләр\nҺылтанмалар\nҠарағыҙ шулай уҡ\n#</pre> <!-- был юлды шул көйө ҡалдырығыҙ -->",
        "searchbutton": "Эҙләү",
        "go": "Күсеү",
        "searcharticle": "Күсеү",
index fdb5b84..f89f294 100644 (file)
        "passwordreset-emailelement": "Імя ўдзельніка: \n$1\n\nЧасовы пароль: \n$2",
        "passwordreset-emailsentemail": "Калі гэты адрас электроннай пошты злучаны з вашым уліковым запісам, будзе адпраўлены ліст пра скід пароля.",
        "passwordreset-emailsentusername": "Калі ёсць адрас электроннай пошты, злучаны з гэтым імем удзельніка, то будзе дасланы ліст пра скід пароля.",
-       "passwordreset-emailsent-capture": "Ніжэй прыведзены адпраўлены ліст пра скід пароля.",
-       "passwordreset-emailerror-capture": "Ніжэй прыведзены створаны ліст пра скід пароля, яго адпраўка не атрымалася па прычыне: $1",
        "passwordreset-invalideamil": "Няслушны адрас электроннай пошты",
        "passwordreset-nodata": "Не былі пададзены ні імя ўдзельніка, ні адрас электроннай пошты",
        "changeemail": "Змяніць або выдаліць адрас электроннай пошты",
        "changeemail-header": "Запоўніце гэтую форму, каб змяніць свой адрас электроннай пошты. Калі хочаце выдаліць адрас электроннай пошты, злучаны з вашым уліковым запісам, пакіньце поле новага адраса электроннай пошты пустым пры адпраўцы формы.",
-       "changeemail-passwordrequired": "Вам трэба будзе ўвесці свой пароль, каб пацвердзіць гэта змяненне.",
        "changeemail-no-info": "Каб звяртацца непасрэдна да гэтай старонкі, вам варта прадставіцца сістэме.",
        "changeemail-oldemail": "Бягучы адрас электроннай пошты:",
        "changeemail-newemail": "Новы адрас электроннай пошты:",
        "undo-nochange": "Выглядае на тое, што праўка ўжо была адкочаная.",
        "undo-summary": "Адкат версіі $1 аўтарства [[Special:Contributions/$2|$2]] ([[User talk:$2|размова]])",
        "undo-summary-username-hidden": "Адкат версіі $1 схаванага ўдзельніка",
-       "cantcreateaccounttitle": "Немагчыма стварыць рахунак",
        "cantcreateaccount-text": "Стварэнне рахункаў было забаронена для гэтага адрасу IP ('''$1''').\n\nЗабарона зроблена ўдзельнікам [[User:$3|$3]], з такім тлумачэннем: ''$2''",
        "cantcreateaccount-range-text": "Стварэнне ўліковага запісу ўдзельніка з IP-адрасоў у дыяпазоне <strong>$1</strong>, што ўключае ваш адрас IP (<strong>$4</strong>), было забаронена {{GENDER:$3|ўдзельнікам|ўдзельніцай}} [[User:$3|$3]].\n\n$3 {{GENDER:$3|патлумачыў|патлумачыла}} гэта так: <em>$2</em>",
        "viewpagelogs": "Паказаць журналы для гэтай старонкі",
        "special-characters-title-endash": "кароткі працяжнік",
        "special-characters-title-emdash": "доўгі працяжнік",
        "special-characters-title-minus": "мінус",
+       "mw-widgets-dateinput-no-date": "Дата не выбрана",
+       "mw-widgets-titleinput-description-new-page": "старонка яшчэ не існуе",
+       "mw-widgets-titleinput-description-redirect": "перанакіраванне на $1",
        "log-action-filter-all": "Усе",
        "log-action-filter-block-block": "заблакаваць",
        "log-action-filter-block-reblock": "Змена блакіроўкі",
index 525091e..80279a5 100644 (file)
        "recentchanges-legend-heading": "<strong>Легенда:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (вижте също [[Special:NewPages|списъка с нови страници]])",
        "recentchanges-submit": "Покажи",
-       "rcnotefrom": "Дадени са промените от <strong>$2</strong> (до <strong>$1</strong> показани).",
+       "rcnotefrom": "{{PLURAL:$5|Дадена е промяната|Дадени са промените}} от <strong>$3, $4</strong> (до <strong>$1</strong> показани).",
        "rclistfrom": "Показване на промени, като се започва от $3 $2",
        "rcshowhideminor": "$1 на малки промени",
        "rcshowhideminor-show": "Показване",
        "uploadstash-summary": "Тази страница предоставя достъп до файловете, които са качени (или са в процес на качване), но все още не са публикувани в уикито. Тези файлове не са достъпни само за потребителя, който ги е качил.",
        "uploadstash-clear": "Изчистване на скритите качвания",
        "uploadstash-nofiles": "Нямате скрити файлове",
-       "uploadstash-badtoken": "Ð\98звÑ\8aÑ\80Ñ\88ване Ð½Ð° Ñ\82ова Ð´ÐµÐ¹Ñ\81Ñ\82вие Ðµ Ð½ÐµÑ\83Ñ\81пеÑ\88но, Ð²ÐµÑ\80оÑ\8fÑ\82но Ð·Ð°Ñ\80ади Ð¸Ð·Ñ\82екла Ñ\81еÑ\81иÑ\8f. Ð\9eпитайте отново.",
+       "uploadstash-badtoken": "Ð\98звÑ\8aÑ\80Ñ\88ване Ð½Ð° Ñ\82ова Ð´ÐµÐ¹Ñ\81Ñ\82вие Ðµ Ð½ÐµÑ\83Ñ\81пеÑ\88но, Ð²ÐµÑ\80оÑ\8fÑ\82но Ð·Ð°Ñ\80ади Ð¸Ð·Ñ\82екла Ñ\81еÑ\81иÑ\8f. Ð\9cолÑ\8f, Ð¾питайте отново.",
        "uploadstash-errclear": "Изчистването на файловете беше неуспешно.",
        "uploadstash-refresh": "Обновяване на списъка с файлове",
        "img-auth-accessdenied": "Достъпът е отказан",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 страница беше добавена|$1 страници бяха добавени}}:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|Една страница беше премахната|$1 страници бяха премахнати}}:",
        "watchlistedit-clear-legend": "Изчистване на списъка за наблюдение",
+       "watchlistedit-clear-explain": "Всички заглавия ще бъдат премахнати от списъка ви за наблюдение",
        "watchlistedit-clear-titles": "Заглавия:",
        "watchlistedit-clear-submit": "Изчистване на списъка за наблюдение (Необратимо!)",
        "watchlistedit-clear-done": "Списъкът за наблюдение беше изчистен.",
index 6f85ebb..5b12678 100644 (file)
        "passwordreset-emailtext-user": "{{SITENAME}} ($4) पर सदस्य $1 राउर {{PLURAL:$3|खाता}} के गुप्तशब्द के पुनर्स्थापित करे के अनुरोध कइले बानी। इ ई-मेल पता से निम्न {{PLURAL:$3|खाता जुड़ल बा}}:\n\n$2\n\n{{PLURAL:$3|इ}} अस्थायी गुप्तशब्द {{PLURAL:$5|एक दिन|$5 दिन}} के बाद काम ना करी।\nरउआ खाता में प्रवेश करके एगो नया गुप्तशब्द अभीये चुन लेवे के चाहीं। यदि इ अनुरोध केहु अउर कइले बा, या फिर रउआ आपन मूल गुप्तशब्द याद आ गईल बा, अउर रउआ {{PLURAL:$3|आपन}} गुप्तशब्द नईखीं बदले के चाहत त, रउआ इ संदेश के अनदेखा कर के आपन पुरनका गुप्तशब्द के प्रयोग जारी रख सकत बानीं।",
        "passwordreset-emailelement": "सदस्यनाम: \n$1\n\nअस्थायी गुप्तशब्द: \n$2",
        "passwordreset-emailsentemail": "एगो गुप्तशब्द रिसेट ई-मेल भेजल जा चुकल बा।",
-       "passwordreset-emailsent-capture": "नीचे दिखावल गईल गुप्तशब्द पुनर्स्थापना ई-मेल भेज दिहल गईल बा।",
-       "passwordreset-emailerror-capture": "नीचे दिखावल गईल गुप्तशब्द पुनर्स्थापना ई-मेल उत्पन्न करल गईल रहल, परंतु उ के {{GENDER:$2|सदस्य}} के भेजे के क्रिया असफल रहल।\nत्रुटि: $1",
        "changeemail": "ई-मेल पता बदलीं",
        "changeemail-header": "खाता के ई-मेल पता बदलीं",
        "changeemail-no-info": "इ पन्ना के सिधे प्रयोग करे खातिर रउआ पहिले खाता में प्रवेश करे के पड़ी।",
        "newarticle": "(नया)",
        "newarticletext": "रउआ एगो अइसन कड़ी के पन्ना के अनुसरण कइले बानी जवन अभी तक उपलब्ध नइखे।\nपन्ना बनावे खातिर, नीचे के बाकस में टाइप करे के शुरु करीं (ज्यादा जानकारी खातिर देखीं [$1 मदद पन्ना])।\nयदि रउआ अहिजा गलती से आ गइल बानी त, आपन ब्राउजर के '''बैक''' (Back) बटन दबाईं!",
        "anontalkpagetext": "----''इ वार्ता पन्ना उन अनाम सदस्यन खातिर बा जिन्हन के या त खाता नइखे खोलल गइल या खाता के प्रयोग नइखन करत।\nएहि खातिर उन्हन के पहिचान खातिर हमनी के उनकर आइ॰पी पता के प्रयोग करे के पड़ेला।\nआइ॰पी पता कई सदस्यन खातिर साझा हो सकत बा।\nयदि आप एगो अनाम सदस्य बानी अउर आपके लागत बा कि आपके बारे में अप्रासंगिक टीका टिप्पणी करल गइल बा त कृपया [[Special:CreateAccount|सदस्यता लिहीं]] या [[Special:UserLogin|सत्रारंभ करीं]] ताकि अन्य अनाम सदस्यन में से आपके अलग से पहिचानल जा सके।''",
-       "noarticletext": "à¤\8f à¤ªà¤¨à¥\8dना à¤®à¥\87 à¤\85भà¥\80 à¤²à¥\87 à¤\95à¥\8cनà¥\8bà¤\82 à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 à¤¨à¤\87à¤\96à¥\87। \nरà¤\89à¤\86 à¤¦à¥\81सरा à¤ªà¤¨à¥\8dना à¤®à¥\87à¤\82 [[Special:Search/{{PAGENAME}}|à¤\8f à¤\9fाà¤\87à¤\9fिल à¤\95à¥\87 à¤\96à¥\8bà¤\9c]] à¤\95र à¤¸à¤\95त à¤¬à¤¾à¤¨à¥\80à¤\82।",
+       "noarticletext": "à¤\8f à¤ªà¤¨à¥\8dना à¤®à¥\87 à¤\85भà¥\80 à¤\95à¥\8cनà¥\8bà¤\82 à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 à¤¨à¤\87à¤\96à¥\87।\nरà¤\89à¤\86à¤\81 à¤¦à¥\81सरा à¤ªà¤¨à¥\8dना à¤®à¥\87à¤\82 [[Special:Search/{{PAGENAME}}|à¤\8f à¤\9fाà¤\87à¤\9fिल à¤\95à¥\87 à¤\96à¥\8bà¤\9c]] à¤\95र à¤¸à¤\95त à¤¬à¤¾à¤¨à¥\80à¤\82,\nया <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} à¤¯à¤¾ à¤¸à¤\82बà¤\82धित à¤²à¥\89à¤\97 à¤\96à¥\8bà¤\9c à¤¸à¤\95त à¤¬à¤¾à¤¨à¥\80]</span>, à¤¬à¤¾à¤\95à¥\80 à¤°à¤\89à¤\86 à¤\95à¥\87 à¤\88 à¤ªà¤¨à¥\8dना à¤¬à¤¨à¤¾à¤µà¥\87 à¤\95à¥\87 à¤ªà¤°à¤®à¥\80शन à¤¨à¤\87à¤\96à¥\87।",
        "noarticletext-nopermission": "ए पन्ना मे अभी कौनों सामग्री नइखे।\nरउआँ दुसरा पन्ना में [[Special:Search/{{PAGENAME}}|ए टाइटिल के खोज]] कर सकत बानीं,\nया <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} या संबंधित लॉग खोज सकत बानी]</span>, बाकी रउआ के ई पन्ना बनावे के परमीशन नइखे।",
        "missing-revision": "\"{{FULLPAGENAME}}\" पन्ना के संशोधन #$1 उपलब्ध नइखे।\n\nसाधारण रुप से इ एगो हटावल गइल पन्ना के पुरान लिंक पर क्लिक कइला से होखेला।\nअधिक जानकारी खातिर आप [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटावे के लॉग] देख सकत बानी।",
        "userpage-userdoesnotexist": "सदस्य खाता \"$1\" पंजीकृत नइखे।\nकृपया जाँच लीं कि आप इ पन्ना संपादित अथवा निर्मित करे के चाहत बानी कि ना।",
        "undo-nochange": "लागत बा की ई संपादन पहिलहीं वापस लिहल जा चुकल बाटे।",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|वार्ता]]) के द्वारा कइल $1 बदलाव के वापस कइल गइल",
        "undo-summary-username-hidden": "एगो छिपल सदस्य द्वारा कइल बदलाव $1 वापस कइल गइल",
-       "cantcreateaccounttitle": "खाता खुल नईखे सकत",
        "cantcreateaccount-text": "एह आइपी पता (IP address)(<strong>$1</strong>) द्वारा नया खाता बनावे पर  [[User:$3|$3]] द्वारा रोक लगावल गइल बा।\n\nएकरा खातिर $3 के दिहल कारण:<em>$2</em>",
        "cantcreateaccount-range-text": "आइपी पता बिस्तार (IP address range) <strong>$1</strong> पर, जेवना में आपके आइपी (<strong>$4</strong>) भी बा, नया खाता बनावे पर [[User:$3|$3]] द्वारा रोक लगावल गइल बा।\n\nएकरा खातिर $3 के दिहल कारण बा:<em>$2</em>",
        "viewpagelogs": "ए पन्ना खातिर लॉग कुल देखीं",
        "revisionasof": "$1 ले भइल नया बदलाव",
        "revision-info": "{{GENDER:$6|$2}}$7 के द्वारा $1 के संशोधन",
        "previousrevision": "← पुरान संशोधन",
-       "nextrevision": "नया à¤¸à¤\82à¤ोधन →",
-       "currentrevisionlink": "हाल à¤\95à¥\87 à¤¸à¤\82à¤ोधन",
+       "nextrevision": "नया à¤¸à¤\82सोधन →",
+       "currentrevisionlink": "हाल à¤\95à¥\87 à¤¸à¤\82सोधन",
        "cur": "हाल",
        "next": "अगिला",
        "last": "पछिला",
        "contributions": "{{GENDER:$1|सदस्य}} योगदान",
        "contributions-title": " $1 खातिर प्रयोगकर्ता योगदान",
        "mycontris": "हमार योगदान",
+       "anoncontribs": "योगदान",
        "nocontribs": "ई मानदंड से मिलत जुलत कौनो बदलाव ना मिलल।",
        "uctop": "(हाल के)",
        "month": "महीना से (आ ओ से पहिले):",
        "whatlinkshere-next": "{{PLURAL:$1|अगिला|अगिला $1}}",
        "whatlinkshere-links": "← कड़ी",
        "whatlinkshere-hideredirs": "$1 अनुप्रेषण",
-       "whatlinkshere-hidetrans": "$1 à¤\9fà¥\8dरानà¥\8dसà¥\8dà¤\95à¥\8dलà¥\8dयà¥\81à¤\9cनà¥\8dस",
+       "whatlinkshere-hidetrans": "$1 à¤\9fà¥\8dराà¤\82सà¤\95à¥\8dलà¥\82à¤\9cन",
        "whatlinkshere-hidelinks": "$1 कड़ी",
        "whatlinkshere-hideimages": "$1 फ़ाइल लिंक",
        "whatlinkshere-filters": "छननी",
        "importbadinterwiki": "खराब इंटरविकि कड़ी",
        "importsuccess": "आयात पूरा भइल!",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|संशोधन|संशोधनसभ}} लावल गइल",
-       "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-ca-talk": "सामग्री पन्ना की बारे में बात-चीत",
-       "tooltip-ca-edit": "रà¤\89à¤\86 à¤\8f à¤ªà¤¨à¥\8dना à¤\95à¥\87 à¤¸à¤\82पादन à¤\95र à¤¸à¤\95त à¤¬à¤¾à¤¨à¥\80। à¤ªà¤¨à¥\8dना à¤¸à¤¹à¥\87à¤\9cà¥\87 à¤¸à¥\87 à¤ªà¤¹à¤¿à¤²à¥\87 à¤¨à¤®à¥\82ना  à¤¦à¥\87à¤\96ाà¤\88à¤\82 à¤¬à¤\9fन à¤\95à¥\87 à¤\87सà¥\8dतà¥\87माल à¤\95रà¥\80à¤\82।",
+       "tooltip-ca-edit": "à¤\8f à¤ªà¤¨à¥\8dना à¤\95à¥\87 à¤¸à¤\82पादन à¤\95रà¥\80à¤\82",
        "tooltip-ca-addsection": "एगो नया खंड शुरु करीं",
        "tooltip-ca-viewsource": "ए पन्ना के सुरक्षित कइ दिहल गइल बा। आप एकर स्रोत देख सकत बानी।",
        "tooltip-ca-history": "ए पन्ना के पछिला संशोधन",
        "tooltip-t-whatlinkshere": "इहाँ जुड़े वाला सब विकि पन्नवन के लिस्ट",
        "tooltip-t-recentchangeslinked": "ए पन्ना से जुड़ल पन्नवन पर तुरंत भइल बदलाव",
        "tooltip-feed-atom": "ए पन्ना खातिर एटम फीड",
-       "tooltip-t-contributions": "ए सदस्य के कुल योगदान के लिस्ट",
+       "tooltip-t-contributions": "{{GENDER:$1|एह सदस्य}} के योगदान के एक ठो लिस्ट",
        "tooltip-t-upload": "फाइल अपलोड करीं",
        "tooltip-t-specialpages": "खास पन्नवन के लिस्ट",
        "tooltip-t-print": "ए पन्ना के छापे लायक संस्करण",
        "tooltip-t-permalink": "ए पन्ना के संशोधन खातिर स्थायी कड़ी।",
        "tooltip-ca-nstab-main": "सामग्री पन्ना देखीं",
        "tooltip-ca-nstab-user": "सदस्य-पन्ना देखीं",
-       "tooltip-ca-nstab-special": "à¤\88 à¤\8fà¤\97à¥\8b à¤\96ास à¤ªà¤¨à¥\8dना à¤¹, à¤°à¤\89à¤\86à¤\81 à¤\8f à¤ªà¤¨à¥\8dना à¤\95à¥\87 à¤¸à¤\82पादन à¤¨à¤\87à¤\96à¥\80à¤\82 à¤\95र à¤¸à¤\95त",
+       "tooltip-ca-nstab-special": "à¤\88 à¤\8fà¤\97à¥\8b à¤\96ास à¤ªà¤¨à¥\8dना à¤¹, à¤\8fà¤\95र à¤¸à¤\82पादन à¤¨à¤¾ à¤¹à¥\8b à¤¸à¤\95à¥\87ला",
        "tooltip-ca-nstab-image": "फाइल के पन्ना देखीं",
-       "tooltip-ca-nstab-template": "साà¤\81à¤\9aा देखीं",
+       "tooltip-ca-nstab-template": "à¤\9fà¥\87मà¥\8dपलà¥\87à¤\9f देखीं",
        "tooltip-ca-nstab-category": "श्रेणी के पन्ना देखीं",
        "tooltip-save": "बदलाव के सहेजीं",
        "tooltip-preview": "आपन द्वारा कियल गइल बदलाव के देखीं, संजोये से पहले ईका इस्तेमाल करीं!",
        "logentry-delete-delete": "$1 द्वारा पन्ना $3 {{GENDER:$2|हटा}} दिहल गइल",
        "revdelete-restricted": "प्रबंधक पर प्रतिबंध लागू",
        "revdelete-unrestricted": "प्रबंधक पर से प्रतिबंध समाप्त",
+       "logentry-move-move": "$1 पन्ना $3 के $4 पर {{GENDER:$2|स्थानांतरण कइलें}}",
        "logentry-newusers-create": "खाता $1 {{GENDER:$2|बनावल गइल}}",
        "revdelete-summary": "सारांश संपादन",
        "searchsuggest-search": "खोजीं",
index 97596c4..aa81ac2 100644 (file)
        "right-changetags": "নির্দিষ্ট সংস্করণ এবং দীর্ঘ সম্পাদনাগুলোতে [[Special:Tags|ট্যাগ]] সংযোজন ও অপসারণ করুন",
        "right-deletechangetags": "ডাটাবেজ থেকে [[Special:Tags|ট্যাগ]] অপসারণ করা",
        "grant-group-email": "ইমেইল পাঠান",
+       "grant-group-private-information": "আপনার সম্পর্কিত ব্যক্তিগত তথ্যে প্রবেশাধিকার পায়",
        "grant-group-other": "বিবিধ কার্যকলাপ",
        "grant-createaccount": "অ্যাকাউন্ট তৈরি করুন",
        "grant-createeditmovepage": "পাতা তৈরি, সম্পাদনা এবং স্থানান্তর করুন",
        "grant-editmyoptions": "আপনার ব্যবহারকারী পছন্দসমূহ সম্পাদনা করুন",
        "grant-editmywatchlist": "আপনার নজরতালিকা সম্পাদনা করুন",
        "grant-editprotected": "সংরক্ষিত পাতা সম্পাদনা করুন",
+       "grant-privateinfo": "ব্যক্তিগত তথ্যে প্রবেশাধিকার",
        "grant-sendemail": "অন্য ব্যবহারকারীকে ইমেইল পাঠান",
        "grant-uploadfile": "নতুন ফাইল আপলোড করুন",
        "grant-basic": "মৌলিক অধিকার",
        "log-action-filter-rights-autopromote": "স্বয়ংক্রিয় পরিবর্তন",
        "log-action-filter-upload-upload": "নতুন আপলোড",
        "log-action-filter-upload-overwrite": "পুনঃআপলোড",
+       "authmanager-create-from-login": "আপনার একাউন্ট তৈরি করতে, নীচের ক্ষেত্রগুলি পূরণ করুন।",
        "authmanager-authplugin-setpass-failed-title": "পাসওয়ার্ড পরিবর্তন ব্যর্থ হয়েছে",
        "authmanager-authplugin-setpass-bad-domain": "অবৈধ ডোমেইন।",
        "authmanager-autocreate-noperm": "স্বয়ংক্রিয় অ্যাকাউন্ট সৃষ্টি মঞ্জুরিপ্রাপ্ত নয়।",
index 8a05f0f..8e71647 100644 (file)
        "action-applychangetags": "aplica les etiquetes juntament amb els canvis",
        "action-changetags": "afegeix i elimina etiquetes a les revisions i les entrades de registre individuals",
        "action-deletechangetags": "eliminar etiquetes des de la base de dades",
+       "action-purge": "purga la pàgina",
        "nchanges": "$1 {{PLURAL:$1|canvi|canvis}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|des de la darrera visita}}",
        "enhancedrc-history": "historial",
index 4d14e83..1fb2401 100644 (file)
        "about": "سەبارەت",
        "article": "بابەت",
        "newwindow": "(لە پەڕەیەکی نوێدا دەکرێتەوە)",
-       "cancel": "ھەڵیوەشێنەوە",
+       "cancel": "ھەڵوەشاندنەوە",
        "moredotdotdot": "زیاتر",
        "morenotlisted": "ئەم لیستەیە تەواو نییە",
        "mypage": "پەڕە",
        "aboutpage": "Project:سەبارەت",
        "copyright": "ناوەرۆک لە ژێر $1 لەبەردەستدایە، مەگەر بێجگە لەمە وترابێ.",
        "copyrightpage": "{{ns:project}}:مافەکانی لەبەرگرتنەوە",
-       "currentevents": "ڕووداوە تازەکان",
+       "currentevents": "ڕووداوە ھەنووکەییەکان",
        "currentevents-url": "Project:ڕووداوە بەردەوامەکان",
        "disclaimers": "نابەرپرسییەکان",
        "disclaimerpage": "Project:بەرپرسنەبوون",
        "youhavenewmessagesmulti": "لە $1 دا پەیامی نوێت ھەیە",
        "editsection": "دەستکاری",
        "editold": "دەستکاری",
-       "viewsourceold": "سÛ\95رÚ\86اÙ\88Û\95Ú©Û\95Û\8c Ø¨Ø¨Û\8cÙ\86ە",
+       "viewsourceold": "بÛ\8cÙ\86Û\8cÙ\86Û\8c Ø³Û\95رÚ\86اÙ\88ە",
        "editlink": "دەستکاری",
-       "viewsourcelink": "سÛ\95رÚ\86اÙ\88Û\95Ú©Û\95Û\8c Ø¨Ø¨Û\8cÙ\86ە",
+       "viewsourcelink": "بÛ\8cÙ\86Û\8cÙ\86Û\8c Ø³Û\95رÚ\86اÙ\88ە",
        "editsectionhint": "دەستکاریکردنی بەش: $1",
        "toc": "پێرست",
        "showtoc": "نیشانیبدە",
        "nstab-user": "پەڕەی بەکارھێنەر",
        "nstab-media": "میدیا",
        "nstab-special": "پەڕەی تایبەت",
-       "nstab-project": "پەڕەی پرۆژە",
+       "nstab-project": "پەڕەی پڕۆژە",
        "nstab-image": "پەڕگە",
        "nstab-mediawiki": "پەیام",
        "nstab-template": "داڕێژە",
        "perfcached": "داتای خوارەوە پاشەکەوتکراوەیە و لەوانەیە بەڕۆژنەکرابێتەوە. لانی زۆر {{PLURAL:$1|یەک ئەنجام|$1 ئەنجام}} لە cacheدا لەبەردەستدایە.",
        "perfcachedts": "داتای خوارەوە cacheکراوە و دوایین جار لە $1 نوێ کراوەتەوە. لە cacheدا لانی زۆر {{PLURAL:$4|یەک ئەنجام|$4 ئەنجام}} لەبەردەستە.",
        "querypage-no-updates": "تازەکردنەوەکان بۆ ئەم پەڕە لە حاڵی ئێستادا ناچالاک کراوەتەوە.\nداتای ئێرە دەسبەجێ تازە ناکرێتەوە.",
-       "viewsource": "سÛ\95رÚ\86اÙ\88Û\95Ú©Û\95Û\8c Ø¨Ø¨Û\8cÙ\86ە",
+       "viewsource": "بÛ\8cÙ\86Û\8cÙ\86Û\8c Ø³Û\95رÚ\86اÙ\88ە",
        "viewsource-title": "سەرچاوەی $1 ببینە",
        "actionthrottled": "چالاکی پێشی پێ گیرا",
        "actionthrottledtext": "بە مەبەستی پێشگریی لە سپەم، ڕێگە نادرێت تۆ لە ماوەیەکی کورت دا لە سەر یەک ئەمە زۆر جار ئەنجام بدەی، وە ئیستا تۆ لە ڕادە بەدەرت کردووە.\nتکایە پاش چەند خولەک دووبارە تاقی بکەوە.",
        "image_tip": "وێنەی نێو دەق",
        "media_sample": "نموونە.ogg",
        "media_tip": "لینکی پەڕگە",
-       "sig_tip": "ئیمزاکەت بە مۆری ڕێکەوتەوە",
+       "sig_tip": "واژووەکەت بە مۆری ڕێکەوتەوە",
        "hr_tip": "هێڵی ئاسۆیی (دەگمەن بەکاری بێنە)",
        "summary": "کورتەی دەستکاری:",
        "subject": "بابەت/سەردێڕ:",
        "hide": "بشارەوە",
        "show": "نیشان بدە",
        "minoreditletter": "ب",
-       "newpageletter": "نوێ",
+       "newpageletter": "ن",
        "boteditletter": "بۆت",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|بەکارھێنەر}}ی چاودێر]",
        "rc_categories": "بەرتەسک‌کردنەوە بە هاوپۆلەکان (به «|» جیای بکەوە‌)",
        "upload-misc-error-text": "هەڵەیەکی نەناسراو لە کاتی بارکردن ڕووی‌دا.\nتکایە لە درووست‌بوون و دەست‌پێ گەیشتنی URL ئەرخەیان ببە و دیسان تاقی‌بکەوە.\nگەر کێشەکە هەر بەردەوام بوو پەیوەندی بکە بە [[Special:ListUsers/sysop|بەڕێوبەر]].",
        "upload-too-many-redirects": "URL ڕەوانەکەری زۆری لەخۆ گرتووە",
        "upload-http-error": "هەڵەیەکی HTTP ڕووئ داوە: $1",
+       "upload-dialog-button-cancel": "ھەڵوەشاندنەوە",
        "upload-dialog-button-upload": "بارکردن",
+       "upload-form-label-own-work": "ئەمە کاری خۆمە",
        "backend-fail-stream": "نەکرا پەڕگەی $1 بنێردرێت.",
        "backend-fail-notexists": "پەڕگەی $1 بوونی نییە.",
        "backend-fail-delete": "نەکرا پەڕگەی $1 بسڕدرێتەوە.",
        "license-nopreview": "(پێشبینین ئامادەی کەڵک وەرگرتن نییە)",
        "upload_source_url": " (URLـی بەکار، بۆ دەست‌پێگەیشتنی  گشتی)",
        "upload_source_file": "(پەڕگەی ھەڵبژێرراوت لەسەر کۆمپیوتەرەکەت)",
-       "listfiles-delete": "بÛ\8cسÚ\95ەوە",
+       "listfiles-delete": "سÚ\95Û\8cÙ\86ەوە",
        "listfiles-summary": "ئەم پەڕە تایبەتە ھەموو پەڕگە بارکراوەکان نیشان دەدات.",
        "listfiles_search_for": "بگەڕێ بۆ ناوی میدیای:",
        "imgfile": "پەڕگە",
        "duplicatesoffile": "ئەم {{PLURAL:$1|پەڕگە دووبارەکرنەوەیەکی|پەڕگانە دووبارەکردنەوەی}} ئەم پەڕگەن ([[Special:FileDuplicateSearch/$2|وردەکاری زیاتر]]):",
        "sharedupload": "ئەم پەڕگە لە $1ەوەیە و لەوە دەچێ لە پرۆژەکانی دیکەش بەکار ببرێت.",
        "sharedupload-desc-there": "ئەم پەڕگە لە $1ەوەیە و لەوە دەچێ لە پرۆژەکانی دیکەش بەکار ببرێت.\nتکایە بۆ زانیاریی زیاتر چاو بکە لە [$2 لاپەڕەی ناساندنی پەڕگە].",
-       "sharedupload-desc-here": "ئەم پەڕگە لە $1ەوەیە و لەوانەیە لە پرۆژەکانی دیکەش بەکار ھاتبێت.\nپێناسەکەی لەسەر [$2 پەڕەی وەسفی پەڕگەکە] لە خوارەوە نیشان دراوە.",
+       "sharedupload-desc-here": "ئەم پەڕگە لە $1ەوەیە و لەوانەیە لە پڕۆژەکانی دیکەش بەکار ھاتبێت.\nپێناسەکەی لەسەر [$2 پەڕەی وەسفی پەڕگەکە] لە خوارەوە نیشان دراوە.",
        "filepage-nofile": "پەڕگەیەک بەم ناوە نیە.",
        "filepage-nofile-link": "پەڕگەیەک بەم ناوە نیە بەڵام دەتوانی [$1 باری بکەی].",
        "uploadnewversion-linktext": "وەشانێکی نوێی ئەم پەڕگەیە بار بکە",
        "suppress": "چاودێری",
        "apisandbox-unfullscreen": "نیشاندانی پەڕە",
        "booksources": "سەرچاوەکانی کتێب",
-       "booksources-search-legend": "بۆ سەرچاوەی کتێب بگەڕێ",
+       "booksources-search-legend": "گەڕان بۆ سەرچاوەکانی کتێب",
        "booksources-search": "بگەڕێ",
        "booksources-text": "لە خوارەوە لیستێک لە بەستەر بۆ ماڵپەڕهایەک کە کتێبی نوێ و بەکارهێنراو دەفرۆشێت و لەوانەیە لەوێ زانیاریی زیاترت دەست‌کەوێت سەبارەت بەو کتێبانەی لە دووی دەگەڕیت:",
        "booksources-invalid-isbn": "ISBN دراو لەوە ناچی بەکار بێت، سەرنج بدە لە کاتی کۆپی کردن لە سەرچاوە تووشی هەڵە نوبوبێت.",
        "logempty": "هیچ بابەتێکی هاوتا لە لۆگەکاندا نەدۆزرایەوە.",
        "log-title-wildcard": "گەڕانی ئەو سەرناوانە بەم دەقەوە دەست پێدەکەن",
        "showhideselectedlogentries": "دیاریکردنی بابەتە ھەڵبژێردراوەکانی لۆگ بگۆڕە",
+       "checkbox-all": "ھەموو",
        "checkbox-none": "هیچ",
        "allpages": "ھەموو پەڕەکان",
        "nextpage": "پەڕەی پاشەوە ($1)",
        "usermessage-summary": "بەجێھێشتنی پەیامی سیستەم",
        "usermessage-editor": "پەیامنێری سیستەم",
        "watchlist": "پێرستی چاودێری",
-       "mywatchlist": "پێرستی چاودێری",
+       "mywatchlist": "پێڕستی چاودێری",
        "watchlistfor2": "بۆ $1 $2",
        "nowatchlist": "لە لیستی چاودێڕییەکانتدا ھیچ نیە.",
        "watchlistanontext": "بۆ دیتن و دەستکاریی بابەتەکانی  ناو پێرستی چاودێرییەکەتدا دەبێ $1.",
        "excontentauthor": "ناوەرۆک ئەمە بوو: «$1» (و تەنیا بەشداربوو «[[Special:Contributions/$2|$2]]» بوو)",
        "exbeforeblank": "ناوەرۆک بەر لە واڵاکردنەوە ئەمە بوو: «$1»",
        "delete-confirm": "سڕینەوەی «$1»",
-       "delete-legend": "بÛ\8cسÚ\95ەوە",
+       "delete-legend": "سÚ\95Û\8cÙ\86ەوە",
        "historywarning": "<strong>ھۆشیار بە:</strong> پەڕەیەک کە خەریکیت دەیسڕیتەوە مێژوویەکی ھەیە بە $1 {{PLURAL:$1|پێداچوونەوە|پێداچوونەوە}}وە:",
        "historyaction-submit": "نیشاندان",
        "confirmdeletetext": "تۆ خەریکی پەڕەیەک بە ھەموو مێژووەکەیەوە دەسڕیتەو.\nتکایە پشتڕاستی بکەوە کە دەتەوێت ئەم کارە بکەی، لە ئاکامەکەی تێدەگەی، و ئەم کارە بە پێی [[{{MediaWiki:Policy-url}}|سیاسەتنامە]] ئەنجام دەدەی.",
        "sp-contributions-username": "ناونیشانی ئایپی یان ناوی‌ بەکارھێنەر:",
        "sp-contributions-toponly": "تەنیا ئەو دەستکارییانە نیشان بدە کە دوایین پێداچوونەوەن",
        "sp-contributions-newonly": "تەنیا ئەو دەستکارییانە نیشان بدە کە دروستکردنی پەڕەن",
+       "sp-contributions-hideminor": "شاردنەوەی دەستکارییە بچووکەکان",
        "sp-contributions-submit": "بگەڕێ",
        "whatlinkshere": "بەستەرەکان بە ئێرەوە",
        "whatlinkshere-title": "ئەو پەڕانەی بەستەریان ھەیە بۆ «$1»",
        "javascripttest": "تاقیکردنەوەی جاڤاسکریپت",
        "tooltip-pt-userpage": "پەڕەی {{GENDER:|تۆ}}",
        "tooltip-pt-anonuserpage": "پەڕەی بەکارھێنەری بۆ ئای‌پی یەکە کە بەناویەوە خەریکی دەستکاری کردنی",
-       "tooltip-pt-mytalk": "پەڕەی لێدوانەکەت",
+       "tooltip-pt-mytalk": "پەڕەی لێدوان",
        "tooltip-pt-anontalk": "لێدوان لەسەر دەستکارییەکان لەم ئایپی ئەدرەسەوە",
        "tooltip-pt-preferences": "{{GENDER:|هەڵبژاردەکانت}}",
-       "tooltip-pt-watchlist": "پێرستی ئەو پەڕانە کە چاودێریی گۆڕانکارییەکانیانی دەکەی",
-       "tooltip-pt-mycontris": "پێرستی بەشدارییەکانت",
+       "tooltip-pt-watchlist": "پێڕستی ئەو پەڕانەی کە چاودێریی گۆڕانکارییەکانیان دەکەیت",
+       "tooltip-pt-mycontris": "پێڕستی بەشدارییەکان",
        "tooltip-pt-login": "پێشنیارت پێدەکرێ بچیتە ژوورەوە؛ ھەرچەندە زۆرت لێناکرێ",
        "tooltip-pt-logout": "دەرچوون",
-       "tooltip-ca-talk": "Ù\84Û\8eدÙ\88اÙ\86 Ø¯Û\95ربارÛ\95Û\8c Ù\86اÙ\88Û\95Ú\95Û\86Ú©Û\8c Ù¾Û\95رÛ\95",
+       "tooltip-ca-talk": "Ù\88تÙ\88Ù\88Û\8eÚ\98 Ø³Û\95بارÛ\95ت Ø¨Û\95 Ù¾Û\95Ú\95Û\95Û\8c Ù\86اÙ\88Û\95Ú\95Û\86Ú©",
        "tooltip-ca-edit": "دەستکاری ئەم پەڕەیە بکە‌",
        "tooltip-ca-addsection": "بەشێکی نوێ دەست پێ بکە",
        "tooltip-ca-viewsource": "ئەم پەڕەیە پارێزراوە.\nئەتوانی سەرچاوەکەی ببینیت",
        "tooltip-n-recentchanges": "لیستی دوایین گۆڕانکارییەکان لەم ویکییەدا",
        "tooltip-n-randompage": "پەڕەیەک بە هەڵکەوت نیشان بدە",
        "tooltip-n-help": "شوێنی تێگەیشتن",
-       "tooltip-t-whatlinkshere": "پێرستی ھەموو پەڕەکانی ویکی کە بەستەر دراون بۆ ئێرە",
+       "tooltip-t-whatlinkshere": "پێڕستی ھەموو پەڕەکانی ویکی کە بەستەر دراون بۆ ئێرە",
        "tooltip-t-recentchangeslinked": "دوایین گۆڕانکارییەکان لەو پەڕانە کە بەگرەوە گرێ دراون",
        "tooltip-feed-rss": "RSS feed بۆ ئەم پەڕە",
        "tooltip-feed-atom": "Atom feed بۆ ئەم پەڕە",
-       "tooltip-t-contributions": "پێرستی بەشدارییەکانی {{GENDER:$1|ئەم بەکارھێنەرە}}",
+       "tooltip-t-contributions": "پێڕستی بەشدارییەکانی {{GENDER:$1|ئەم بەکارھێنەرە}}",
        "tooltip-t-emailuser": "ئیمەیلێک بنێرە بۆ ئەم بەکارھێنەرە",
        "tooltip-t-upload": "پەڕگە بار بکە",
-       "tooltip-t-specialpages": "پێرستی ھەموو پەڕە تایبەتەکان",
+       "tooltip-t-specialpages": "پێڕستی ھەموو پەڕە تایبەتەکان",
        "tooltip-t-print": "وەشانی چاپی ئەم پەڕەیە",
        "tooltip-t-permalink": "گرێدەری ھەمیشەیی بۆ ئەم وەشانەی ئەم پەڕەیە",
        "tooltip-ca-nstab-main": "بینینی پەڕەی ناوەڕۆک",
        "tooltip-ca-nstab-user": "پەڕەی بەکارھێنەر تەماشا بکە",
        "tooltip-ca-nstab-media": "پەڕەی میدیا چاو لێ بکە",
        "tooltip-ca-nstab-special": "ئەمە پەڕەیەکی تایبەتە و دەستکاری ناکرێت",
-       "tooltip-ca-nstab-project": "بینینی پەڕەی پرۆژە",
+       "tooltip-ca-nstab-project": "بینینی پەڕەی پڕۆژە",
        "tooltip-ca-nstab-image": "بینینی پەڕەی پەڕگە",
        "tooltip-ca-nstab-mediawiki": "بینینی پەیامی سیستەم",
        "tooltip-ca-nstab-template": "بینینی قاڵبەکە",
        "tooltip-ca-nstab-help": "بینینی پەڕەی رێنمایی",
-       "tooltip-ca-nstab-category": "پەڕەی پۆلەکە ببینە",
+       "tooltip-ca-nstab-category": "بینینی پەڕەی پۆلەکە",
        "tooltip-minoredit": "ئەمە وەک گۆڕانکارییەکی بچووک دیاری بکە",
        "tooltip-save": "گۆڕانکارییەکانی خۆت پاشکەوت بکە",
        "tooltip-preview": "پێش بینینی گۆڕانکارییەکان، تکایە پێش پاشکەوت کردن ئەمە بەکار بھێنە",
        "tags-active-yes": "بەڵێ",
        "tags-active-no": "نا",
        "tags-edit": "دەستکاری",
+       "tags-delete": "سڕینەوە",
        "tags-hitcount": "$1 {{PLURAL:$1|گۆڕان|گۆڕانکاری}}",
        "comparepages": "پەڕەکان ھەڵسەنگێنە",
        "compare-page1": "پەڕەی ١",
        "logentry-upload-overwrite": "$1 وەشانێکی نوێی $3ی {{GENDER:$2|بار کرد}}",
        "rightsnone": "(ھیچ)",
        "revdelete-summary": "پوختەی دەستکاری",
-       "feedback-cancel": "ھەڵیوەشێنەوە",
+       "feedback-back": "گەڕانەوە",
+       "feedback-cancel": "ھەڵوەشاندنەوە",
        "feedback-close": "کرا",
        "feedback-message": "پەیام:",
        "feedback-subject": "بابەت:",
        "special-characters-group-gujarati": "گوجەراتی",
        "special-characters-group-thai": "تایلەندی",
        "special-characters-group-khmer": "خمێری",
+       "log-action-filter-all": "ھەموو",
        "log-action-filter-upload-upload": "بارکردنی نوێ"
 }
index 1e09490..7e9eecf 100644 (file)
@@ -33,7 +33,8 @@
                        "Matma Rex",
                        "Dvorapa",
                        "Walter Klosse",
-                       "Martin Urbanec"
+                       "Martin Urbanec",
+                       "Marek Pavlica"
                ]
        },
        "tog-underline": "Podtrhávat odkazy:",
        "grant-group-high-volume": "Velkoobjemové činnosti",
        "grant-group-customization": "Nastavení a přizpůsobení",
        "grant-group-administration": "Provádění správcovských činností",
+       "grant-group-private-information": "Přístup k soukromým údajům o vás",
        "grant-group-other": "Různé činnosti",
        "grant-blockusers": "Blokovat a odblokovávat uživatele",
        "grant-createaccount": "Zakládat účty",
        "grant-highvolume": "Hromadné editace",
        "grant-oversight": "Skrývat uživatele a utajovat revize",
        "grant-patrol": "Patrolovat změny stránek",
+       "grant-privateinfo": "Přístup k soukromým údajům",
        "grant-protect": "Zamykat a odemykat stránky",
        "grant-rollback": "Vracet editace zpět",
        "grant-sendemail": "Posílat e-maily ostatním uživatelům",
        "uploadstash-errclear": "Soubory se nepodařilo vymazat.",
        "uploadstash-refresh": "Aktualizovat seznam souborů",
        "uploadstash-thumbnail": "zobrazit náhled",
+       "uploadstash-exception": "Načtený soubor se nepodařilo uložit do skrýše ($1): „$2“.",
        "invalid-chunk-offset": "Neplatný posun bloku",
        "img-auth-accessdenied": "Přístup odepřen",
        "img-auth-nopathinfo": "Chybí PATH_INFO.\nVáš server není nastaven tak, aby tuto informaci poskytoval.\nMožná funguje pomocí CGI a img_auth na něm nemůže fungovat.\nVizte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "trackingcategories-name": "Název hlášení",
        "trackingcategories-desc": "Kritéria pro vložení do kategorie",
        "restricted-displaytitle-ignored": "Stránky s ignorovanými zobrazovanými názvy",
-       "restricted-displaytitle-ignored-desc": "Stránka obsahuje příkaz <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>, který se ignoruje, protože není ekvivalentní skutečnému názvu stránky.",
+       "restricted-displaytitle-ignored-desc": "Stránka obsahuje příkaz <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>, který se ignoruje, neboť není ekvivalentní skutečnému názvu stránky.",
        "noindex-category-desc": "Stránka není indexována roboty, protože obsahuje kouzelné slovo <code><nowiki>__NOINDEX__</nowiki></code> a je ve jmenném prostoru, ve kterém je tento příznak dovolen.",
        "index-category-desc": "Stránka obsahuje kouzelné slovo <code><nowiki>__INDEX__</nowiki></code> (a je ve jmenném prostoru, ve kterém je tento příznak dovolen), takže je indexována roboty, přestože by normálně nebyla.",
        "post-expand-template-inclusion-category-desc": "Stránka je po rozbalení všech šablon větší než <code>$wgMaxArticleSize</code>, takže některé šablony rozbaleny nebyly.",
        "undeletehistorynoadmin": "Tato stránka byla smazána. Důvod smazání je uveden níže, spolu s informacemi o uživatelích, kteří tuto stránku před smazáním editovali. Samotný text stránky je dostupný pouze správcům.",
        "undelete-revision": "Smazaná verze stránky $1 (z $4 dne $5) od uživatele $3:",
        "undeleterevision-missing": "Nesprávná nebo chybějící revize. Možná máte špatný odkaz, nebo revize byla obnovena či odstraněna z archivu.",
+       "undeleterevision-duplicate-revid": "Nebylo možné obnovit {{PLURAL:$1|jednu revizi|$1 revize|$1 revizí}}, protože {{PLURAL:$1|její|jejich}} <code>rev_id</code> již {{PLURAL:$1|bylo obsazeno|byla obsazena}}.",
        "undelete-nodiff": "Nebyla nalezena žádná předchozí verze.",
        "undeletebtn": "Obnovit",
        "undeletelink": "prohlédnout/obnovit",
        "undeletedrevisions": "{{PLURAL:$1|Obnovena jedna verze|Obnoveny $1 verze|Obnoveno $1 verzí}}",
        "undeletedrevisions-files": "{{PLURAL:$1|Obnovena jedna verze|Obnoveny $1 verze|Obnoveno $1 verzí}} a {{PLURAL:$2|jeden soubor|$2 soubory|$2 souborů}}.",
        "undeletedfiles": "{{PLURAL:$1|Obnoven jeden soubor|Obnoveny $1 soubory|Obnoveno $1 souborů}}",
-       "cannotundelete": "Obnovení se nezdařilo:\n$1",
+       "cannotundelete": "Některá nebo všechna obnovení se nezdařila:\n$1",
        "undeletedpage": "<strong>Stránka „$1“ byla obnovena</strong>\n\nZáznam o posledních mazáních a obnoveních najdete v [[Special:Log/delete|knize smazaných stránek]].",
        "undelete-header": "Vizte nedávno smazané stránky v [[Special:Log/delete|knize smazaných stránek]].",
        "undelete-search-title": "Hledání smazaných stránek",
        "sp-contributions-newbies-sub": "Noví uživatelé",
        "sp-contributions-newbies-title": "Příspěvky nových uživatelů",
        "sp-contributions-blocklog": "kniha zablokování",
-       "sp-contributions-suppresslog": "utajené příspěvky uživatele",
-       "sp-contributions-deleted": "smazané editace uživatele",
+       "sp-contributions-suppresslog": "utajené příspěvky {{GENDER:$1|uživatele|uživatelky}}",
+       "sp-contributions-deleted": "smazané editace {{GENDER:$1|uživatele|uživatelky}}",
        "sp-contributions-uploads": "načtené soubory",
        "sp-contributions-logs": "protokolovací záznamy",
        "sp-contributions-talk": "diskuse",
index 747148d..4fb3f7b 100644 (file)
        "minoredit": "Dette er en mindre ændring",
        "watchthis": "Overvåg denne side",
        "savearticle": "Gem side",
+       "publishpage": "Offentliggør side",
+       "publishchanges": "Offentliggør ændringer",
        "preview": "Forhåndsvisning",
        "showpreview": "Forhåndsvisning",
        "showdiff": "Vis ændringer",
index d4fee1b..8a8fe7b 100644 (file)
        "grant-group-high-volume": "Massenaktivitäten ausführen",
        "grant-group-customization": "Anpassung und Einstellungen",
        "grant-group-administration": "Administrative Aktionen ausführen",
+       "grant-group-private-information": "Auf private Daten über dich zugreifen",
        "grant-group-other": "Verschiedene Aktivitäten",
        "grant-blockusers": "Benutzer sperren und freigeben",
        "grant-createaccount": "Benutzerkonten erstellen",
        "grant-highvolume": "Massenbearbeitungen",
        "grant-oversight": "Benutzer verstecken und Versionen unterdrücken",
        "grant-patrol": "Änderungen an Seiten kontrollieren",
+       "grant-privateinfo": "Auf private Informationen zugreifen",
        "grant-protect": "Seiten schützen und freigeben",
        "grant-rollback": "Änderungen an Seiten zurücksetzen",
        "grant-sendemail": "E-Mails an andere Benutzer versenden",
        "undeletehistorynoadmin": "Diese Seite wurde gelöscht. Der Löschgrund ist in der Zusammenfassung angegeben,\ngenauso wie Details zum letzten Benutzer, der diese Seite vor der Löschung bearbeitet hat.\nDer aktuelle Text der gelöschten Seite ist nur Administratoren zugänglich.",
        "undelete-revision": "Gelöschte Version von $1 (vom $4 um $5 Uhr), $3:",
        "undeleterevision-missing": "Ungültige oder fehlende Version. Entweder ist der Link falsch oder die Version wurde aus dem Archiv wiederhergestellt oder entfernt.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Eine Version konnte|$1 Versionen konnten}} nicht wiederhergestellt werden, da ihre <code>rev_id</code> bereits in Verwendung {{PLURAL:$1|ist|sind}}.",
        "undelete-nodiff": "Keine vorhergehende Version vorhanden.",
        "undeletebtn": "Wiederherstellen",
        "undeletelink": "ansehen/wiederherstellen",
        "undeletedrevisions": "{{PLURAL:$1|1 Version wurde|$1 Versionen wurden}} wiederhergestellt",
        "undeletedrevisions-files": "{{PLURAL:$1|1 Version|$1 Versionen}} und {{PLURAL:$2|1 Datei|$2 Dateien}} wurden wiederhergestellt",
        "undeletedfiles": "{{PLURAL:$1|1 Datei wurde|$1 Dateien wurden}} wiederhergestellt",
-       "cannotundelete": "Die Wiederherstellung ist fehlgeschlagen:\n$1",
+       "cannotundelete": "Einige oder alle Wiederherstellungen sind fehlgeschlagen:\n$1",
        "undeletedpage": "'''„$1“''' wurde wiederhergestellt.\n\nIm [[Special:Log/delete|Lösch-Logbuch]] findest du eine Übersicht der gelöschten und wiederhergestellten Seiten.",
        "undelete-header": "Siehe das [[Special:Log/delete|Lösch-Logbuch]] für kürzlich gelöschte Seiten.",
        "undelete-search-title": "Nach gelöschten Seiten suchen",
        "sp-contributions-newbies-sub": "Von neuen Benutzern",
        "sp-contributions-newbies-title": "Benutzerbeiträge von neuen Benutzern",
        "sp-contributions-blocklog": "Sperr-Logbuch",
-       "sp-contributions-suppresslog": "Unterdrückte Benutzerbeiträge",
-       "sp-contributions-deleted": "Gelöschte Beiträge",
+       "sp-contributions-suppresslog": "Unterdrückte {{GENDER:$1|Benutzerbeiträge}}",
+       "sp-contributions-deleted": "Gelöschte {{GENDER:$1|Benutzerbeiträge}}",
        "sp-contributions-uploads": "Hochgeladene Dateien",
        "sp-contributions-logs": "Logbücher",
        "sp-contributions-talk": "Diskussion",
index 90d074e..7ca8358 100644 (file)
        "july-date": "Temuz $1",
        "august-date": "Tebaxe $1",
        "september-date": "Keşkelun $1",
-       "october-date": "$1 Cetan",
-       "november-date": "$1 Kelverdan",
+       "october-date": "Tışrino Verên $1",
+       "november-date": "Tışrino Peyên $1",
        "december-date": "Kanun $1",
        "period-am": "AM",
        "period-pm": "PM",
        "anontalk": "Werênayış",
        "navigation": "Pusula",
        "and": "&#32;u",
-       "qbfind": "Bıvêne",
+       "qbfind": "Bıvin",
        "qbbrowse": "Çım ra viyarne",
        "qbedit": "Bıvurne",
        "qbpageoptions": "Ena pele",
        "talkpagelinktext": "werênayış",
        "specialpage": "Pela xısusiye",
        "personaltools": "Hacetê şexsiy",
-       "articlepage": "Pela zerreki bıvêne",
+       "articlepage": "Pera zerreki bıvin",
        "talk": "Werênayış",
        "views": "Asayışi",
        "toolbox": "Haceti",
        "imagepage": "Pera dosya bıasne",
        "mediawikipage": "Pera mesaci bıasne",
        "templatepage": "Pera şabloni bıasne",
-       "viewhelppage": "Pela peşti bıvêne",
+       "viewhelppage": "Pera peşti bıvin",
        "categorypage": "Pela kategoriya bıasne",
        "viewtalkpage": "Werênayışi bıvêne",
        "otherlanguages": "Zıwananê binan de",
        "redirectedfrom": "($1 ra kırışı yê)",
        "redirectpagesub": "Pela berdışi",
        "redirectto": "Beno hetê:",
-       "lastmodifiedat": "Ena pele tewr peyên roca $1, seate $2 de biya rocaniye.{{MediaWiki bın}}",
+       "lastmodifiedat": "Per roca $1, sehat $2 de biye neye.",
        "viewcount": "Ena pele {{PLURAL:$1|rae|$1 rey}} vêniya.",
        "protectedpage": "Pela pawıtiye",
        "jumpto": "Şo be:",
        "confirmable-yes": "Eya",
        "confirmable-no": "Nê",
        "thisisdeleted": "Bıvêne ya zi $1 peyser biya?",
-       "viewdeleted": "$1 bıvêne?",
+       "viewdeleted": "$1 bıvin?",
        "restorelink": "{{PLURAL:$1|jew vurnayış besteriya|$1 vurnayışi besteriyaye}}",
        "feedlinks": "Warikerdış:",
        "feed-invalid": "Qeydey cıresnayışê  beğşi nêvêreno.",
        "perfcached": "Datay cı ver hazır biye. No semedê ra nıkayin niyo! tewr zaf {{PLURAL:$1|netice|$1 netice}} debêno de",
        "perfcachedts": "Cêr de malumatê nımıteyi esti, demdê newe kerdışo peyın: $1. Tewr zaf {{PLURAL:$4|netice|$4 neticey cı}} debyayo de",
        "querypage-no-updates": "Rocanebiyayışê na pele nıka cadayiyê.\nDayiyi tiya nıka newe nêbenê.",
-       "viewsource": "Çımey bıvêne",
+       "viewsource": "Çemi bıvin",
        "viewsource-title": "Cı geyrayışê $1'i bıvin",
        "actionthrottled": "Kerden peysnaya",
        "actionthrottledtext": "Riyê tedbirê anti-spami ra,  wextê do kılmek de şıma nê fealiyeti nêşkenê zaf zêde bıkerê, şıma ki no hedi viyarna ra.\nÇend deqey ra tepeya reyna bıcerrebnên.",
        "nologinlink": "Yew hesab ake",
        "createaccount": "Hesab vıraze",
        "gotaccount": "Hesabê şıma esto? '''$1'''.",
-       "gotaccountlink": "Ronıştış ak",
+       "gotaccountlink": "Cıkewtış",
        "userlogin-resetlink": "Melumatê cıkewtışi xo vira kerdê?",
        "userlogin-resetpassword-link": "Parola xo kerda xo vira?",
        "userlogin-helplink2": "Heqa qeydbiyayışi de peşti bıgêrên",
        "botpasswords-label-appid": "Nameyê boti:",
        "botpasswords-label-create": "Vıraze",
        "botpasswords-label-update": "Rocane ke",
-       "botpasswords-label-cancel": "Bıterkın",
+       "botpasswords-label-cancel": "İbtal ke",
        "botpasswords-label-delete": "Bestere",
        "botpasswords-label-resetpassword": "Parola raçarne",
        "botpasswords-label-grants-column": "Dayen",
        "resetpass_forbidden": "parolayi nêvuryayi",
        "resetpass-no-info": "şıma gani hesab akere u hona bıeşke bırese cı",
        "resetpass-submit-loggedin": "Parola bıvurne",
-       "resetpass-submit-cancel": "Bıterkın",
+       "resetpass-submit-cancel": "İbtal ke",
        "resetpass-wrong-oldpass": "parolayo parola maqbul niyo.\nşıma ya parolaye xo vurnayo ya zi parolayo muwaqqat waşto.",
        "resetpass-recycled": "Parolaya şımaya newiye wa paroloya şımaya verêne ra ferqıne bo.",
        "resetpass-temp-emailed": "E postaya rışyayê yubkoda şıma ronıştış akerdo.  Ronıştışi xo temammkerdışi rê yu parolaya newi lazım a",
        "hr_tip": "Xeta verardiye (teserrufın bıgureyne/bıxebetne)",
        "summary": "Xulasa:",
        "subject": "Mewzu:",
-       "minoredit": "No yew vurnayışo werdiyo",
-       "watchthis": "Ena pele seyr ke",
-       "savearticle": "Pele qeyd ke",
+       "minoredit": "Vurriyayışo werdiyo",
+       "watchthis": "Seyr kı",
+       "savearticle": "Qeyd kı",
        "savechanges": "Vurnayışan qeyd ke",
        "publishpage": "Perer bıhesırne",
        "publishchanges": "Vurnayışa vıla ke",
        "accmailtext": "[[User talk:$1|$1]] parolayo ke raşt ameyo şırawiyo na adres $2.\n\nQey na hesabê newe parola, cıkewtış dıma şıma eşkeni na qısım de ''[[Special:ChangePassword|parola bıvurn]]'' bıvurni.",
        "newarticle": "(Newe)",
        "newarticletext": "To yew gıre tıkna be ra yew pela ke hewna çıniya.\nSeba afernayışê pele ra, qutiya metnê cêrêni bıgurene (seba melumati qaytê [$1 pela peşti] ke).\nEke be ğeletine ameya tiya, wa gocega <strong>peyser</strong>i programê xo de bıtıkne.",
-       "anontalkpagetext": "----''No pel, pel o karbero hesab a nêkerdeyan o, ya zi karbero hesab akerdeyan o labele pê hesabê xo nêkewto de. No sebeb ra ma IP adres şuxulneni û ney IP adresan herkes eşkeno bıvino. Eke şıma qayil niye ina bo xo ri [[Special:CreateAccount|yew hesab bıvıraze]] veyaxut [[Special:UserLogin|hesab akere]].''",
+       "anontalkpagetext": "----''Na per, perêk kı karbero hesab a nêkerdeyan o, ya zi karbero hesab akerdeyan o labele pê hesabê xo nêkewto de. No sebeb ra ma IP adres xebetneno û ney IP adresan herkes nêşeno bıvino. Eke şıma qayil niye ina bo xorê [[Special:CreateAccount|yew hesab bıvıraze]] veya xut [[Special:UserLogin|hesab akere]].''",
        "noarticletext": "Ena pele de hewna theba çıniyo.\nTı şenê zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|qandê  sernameyê ena pele cı geyre]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre],\nya zi [{{fullurl:{{FULLPAGENAME}}|action=edit}} ena pele vıraze]</span>.{{MediaWiki mesaca pera newi}}",
        "noarticletext-nopermission": "Ena pele de hewna theba çıniyo.\nTı şenay zerreyê pelanê binan de [[Special:Search/{{PAGENAME}}|seba sernameyê na pele cı geyre]], ya zi <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} qeydan miyan de cı geyre]</span>, ema destur çıniyo ke na pele vırazê.",
        "missing-revision": "Rewizyonê name dê pela da #$1 \"{{FULLPAGENAME}}\" dı çıniyo.\n\nNo normal de tarix dê pelanê besterneyan dı ena xırabin asena.\nDetayê besternayışi [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} tiya dı] aseno.",
        "next-page": "Pela peyên",
        "prevn-title": "$1o verên  {{PLURAL:$1|netice|neticeyan}}",
        "nextn-title": "$1o ke yeno {{PLURAL:$1|netice|neticey}}",
-       "shown-title": "bimocne $1î  {{PLURAL:$1|netice|neticeyan}} ser her pel",
+       "shown-title": "Herg per sero $1 {{PLURAL:$1|netici|netica}} bıasne",
        "viewprevnext": "($1 {{int:pipe-separator}} $2) ($3) bıvênên",
        "searchmenu-exists": "''Ena 'Wikipediya de ser \"[[:$1]]\" yew pel esto'''",
        "searchmenu-new": "<strong>Na wiki de pela \"[[:$1]]\" vıraze!</strong> {{PLURAL:$2|0=|Sewbina pela ke şıma geyrayê cı aye bıvênê.|Yew zi neticanê cıgeyrayışê xo bıvênê.}}",
        "rightslogtext": "Ena listeyê loganê ke heqqa karbaranî mucneno.",
        "action-read": "ena pela wanayış",
        "action-edit": "ena pela bıvurnê",
-       "action-createpage": "Ena perer bıvıraze",
+       "action-createpage": "na perer bıvıraz",
        "action-createtalk": "pelanê werênayışi bıvıraze",
        "action-createaccount": "hesabê nê karberi bıvıraze",
        "action-autocreateaccount": "nê hesabê karberiyê teberi otomatik vıraze",
        "enhancedrc-history": "tarix",
        "recentchanges": "Vurriyayışê peyêni",
        "recentchanges-legend": "Tercihê vurnayışanê peyênan",
-       "recentchanges-summary": "\"Wiki sero vurnayışanê peyênan ena perer ra teqib ke.\"\n{{vp-diq}}",
+       "recentchanges-summary": "Wiki sero vurriyayışê peyêni asenê.",
        "recentchanges-noresult": "Goreyê kriteranê kıfşkerdeyan ra qet yew vurnayış nêvêniya.",
        "recentchanges-feed-description": "Ena feed dı vurnayişanê tewr peniyan teqip bık.",
        "recentchanges-label-newpage": "Enê vurnayışi ra yew pela newiye vıraziye",
-       "recentchanges-label-minor": "No yew vurnayışo werdiyo",
+       "recentchanges-label-minor": "Vurriyayışo werdiyo",
        "recentchanges-label-bot": "Eno vurnayış terefê yew boti ra vıraziyo",
        "recentchanges-label-unpatrolled": "Eno vurnayış hewna dewriya nêbiyo",
        "recentchanges-label-plusminus": "Ebadê pele de bazê bayti de vayeyê cı",
        "recentchanges-submit": "Bıasne",
        "rcnotefrom": "Cêr de <strong>$2</strong> ra nata {{PLURAL:$5|vurnayışiyê}} asenê (tewr vêşi <strong>$1</strong> asenê) <strong>$3, $4</strong>",
        "rclistfrom": "$3 $2 ra tepiya vurnayışanê neweyan bımocne",
-       "rcshowhideminor": "vurriyayışanê werdiyan $1",
+       "rcshowhideminor": "vurriyayışê werdi $1",
        "rcshowhideminor-show": "Bımocne",
        "rcshowhideminor-hide": "Bınımne",
        "rcshowhidebots": "botan $1",
        "rcshowhidecategorization": "kategorizasyonê pele $1",
        "rcshowhidecategorization-show": "Bıasne",
        "rcshowhidecategorization-hide": "Bınımne",
-       "rclinks": "$2 rocan de $1 vurriyayışanê peyêna bıasne <br />$3",
+       "rclinks": "Peyniya $2 rocan de $1 vurriyayışê <br />$3 asenê",
        "diff": "ferq",
        "hist": "verên",
        "hide": "Bınımne",
        "newpages-submit": "Bıasene",
        "newpages-username": "Nameyê karberi:",
        "ancientpages": "Pelê kehenêri",
-       "move": "Bıkırış",
+       "move": "Bıkırışe",
        "movethispage": "Ena pele bıkırışe",
        "unusedimagestext": "Enê dosyey estê, feqet zerrey yew pele de wedardey niyê.\nXo vira mekerê ke, sıteyê webiê bini şenê direkt ebe URLi yew dosya ra gırê bê, u wına şenê verba gurênayışo feal de tiya hewna lista bê.",
        "unusedcategoriestext": "Kategoriyê ke cêr derê, nê bıbê zi, terefê qet madeyan ya zi kategoriyan ra nêgureniyenê.",
        "removedwatchtext": "Ena pela \"[[:$1]]\" biya wedariya [[Special:Watchlist|listeyê seyr-kerdışi şıma]].",
        "removedwatchtext-short": "Pera $1`i listeya seyran de şıma ra wedari yê",
        "watch": "Seyr ke",
-       "watchthispage": "Ena pele seyr ke",
+       "watchthispage": "Seyr kı",
        "unwatch": "Teqib meke",
        "unwatchthispage": "temaşa kerdışê peli vındarn.",
        "notanarticle": "mebhesê peli niyo",
        "undeleterevision-missing": "revizyonê nemeqbul u vindbiyayeyi.\nRevizyoni ya hewn a biyê ya arşiw ra veciyayê ya zi cıresayişê şımayi şaş o.",
        "undelete-nodiff": "revizyonê verıni nidiya",
        "undeletebtn": "Timar bike",
-       "undeletelink": "bıvêne/peyser biya",
+       "undeletelink": "bıewni/peyser biya",
        "undeleteviewlink": "bıvin",
        "undeleteinvert": "Weçinayışi dimlaşt ke",
        "undeletecomment": "Sebeb:",
        "unblocked-id": "Blokê $1î wedariyayo",
        "blocklist": "Karberê kılitbiyayey",
        "ipblocklist": "Karberê kılitbiyayey",
-       "ipblocklist-legend": "Yew karberê kılitbiyayey bıvêne",
+       "ipblocklist-legend": "Karberê kılit biyayey bıvin",
        "blocklist-userblocks": "Kılitkerdışê hesaban bınımne",
        "blocklist-tempblocks": "Kılitkerdışan mıweqet bınımne",
        "blocklist-addressblocks": "Tenya kılitkerdışanê IPy bınımne",
        "articleexists": "Ena nameyê pela database ma dı esta ya zi tı raşt nınuşt. .\nYewna name bınus.",
        "cantmove-titleprotected": "şıma nêşkeni yew peli bıhewelnê tiya çunke pawıyeno",
        "movetalk": "Pela werênayışiê elaqedare bere",
-       "move-subpages": "pelê bınini bıkırış($1 heta tiya)",
-       "move-talk-subpages": "pelê bınini yê pelê werê ameyeşi bıkırış ($1 heta tiya)",
+       "move-subpages": "Peranê bınênan bıkırış (hetana $1)",
+       "move-talk-subpages": "Bın peranê peranê vatena bıkırış (hetana $1)",
        "movepage-page-exists": "maddeya $1i ca ra esta u newe ra otomatikmen nênusyena.",
        "movepage-page-moved": "pelê $1i kırışiya pelê $2i.",
        "movepage-page-unmoved": "pelê $1i nêkırışiyeno sernameyê $2i.",
        "anonymous": "{{PLURAL:$1|karberê|karberê}} anonimi yê keyepelê {{SITENAME}}i",
        "siteuser": "karberê {{SITENAME}}i $1",
        "anonuser": "karberê anonim o {{SITENAME}}i $1",
-       "lastmodifiedatby": "Ena pele tewr peyên roca $2, $1 de tereftê $3 ra vuriya ya.",
+       "lastmodifiedatby": "Ena per tewr peyên roca $2, $1 de terefê $3 ra vurmaya ya.",
        "othercontribs": "xebatê $1 ıney geriyayo diqqeti/geriyayo nezer.",
        "others": "bini",
        "siteusers": "{{SITENAME}} {{PLURAL:$2|karberê ey|karberanê ey}} $1",
        "fileduplicatesearch-result-1": "Dosyayê ''$1î'' de hem-kopya çini yo.",
        "fileduplicatesearch-result-n": "Dosyayê ''$1î'' de {{PLURAL:$2|1 hem-kopya|$2 hem-kopyayî'}} esto.",
        "fileduplicatesearch-noresults": "Ebe namey \"$1\" ra dosya nêdiyayê.",
-       "specialpages": "Pelê xısusiy",
+       "specialpages": "Page bağsey",
        "specialpages-note-top": "Kıtabek",
        "specialpages-note": "* Pelê xasê normali.\n* <span class=\"mw-specialpagerestricted\">Pelê xasê nımıtey.</span>",
        "specialpages-group-maintenance": "Raporê pawıtışi",
        "feedback-bugcheck": "Harika! Sadece [xırabina ke $1 ] çınyayışê cı kontrol keno.",
        "feedback-bugnew": "Mı qontrol ke. Xetaya newi xeber ke",
        "feedback-bugornote": "Jew mersela teferruato teknik esta şıma reca malumatê şıma hazıro se [ $1  jew xırab rapor] bıvinê.Zewbi zi, formê cerê xo rê şenê karfiyê. Vatışê xo pela da \"[ $3  $2 ]\", namey karber dê xoya piya u wasteriya karfiye.",
-       "feedback-cancel": "Bıterkın",
+       "feedback-cancel": "İbtal kı",
        "feedback-close": "Biya star",
        "feedback-error1": "Xeta: API ra neticey ne vıcyay",
        "feedback-error2": "Xeta: Timar kerdış nebı",
index b06d8d6..12f6e28 100644 (file)
        "tagline": "Από {{SITENAME}}",
        "help": "Βοήθεια",
        "search": "Αναζήτηση",
+       "search-ignored-headings": "#<!-- αφήστε αυτή τη γραμμή όπως είναι --> <pre>\n# Επικεφαλίδες που θα αγνοηθούν από την αναζήτηση.\n# Αλλαγές σε αυτό ισχύουν μόλις η σελίδα με τον τίτλο ευρετηριαστεί.\n# Μπορείτε να επιβάλετε επανευρετηρίαση της σελίδας κάνοντας μια κενή επεξεργασία.\n# Η σύνταξη είναι ως εξής:\n# * Όλα από ένα χαρακτήρα \"#\" μέχρι το τέλος της γραμμής είναι ένα σχόλιο.\n# * Κάθε μη κενή γραμμή είναι ο ακριβής τίτλος που θα αγνοήσει, κεφαλαία/πεζά και τα πάντα.\nΠαραπομπές\nΕξωτερικοί σύνδεσμοι\nΔείτε επίσης\n #</pre> <!-- leave this line exactly as it is -->",
        "searchbutton": "Αναζήτηση",
        "go": "Μετάβαση",
        "searcharticle": "Μετάβαση",
        "botpasswords-label-delete": "Διαγραφή",
        "botpasswords-label-resetpassword": "Επαναφορά κωδικού",
        "botpasswords-label-grants": "Ισχύουσες άδειες:",
+       "botpasswords-help-grants": "Κάθε παραχώρηση δίνει πρόσβαση στα ορισμένα δικαιώματα χρήστη που που ήδη έχει ένας λογαριασμός χρήστη. Δείτε τη [[Special:ListGrants|πίνακας παραχωρήσεων]] για περισσότερες πληροφορίες.",
        "botpasswords-label-restrictions": "Περιορισμοί χρήσης:",
        "botpasswords-label-grants-column": "Χορηγήθηκε",
        "botpasswords-bad-appid": "Η ονομασία του ρομπότ «$1» δεν είναι έγκυρη.",
+       "botpasswords-insert-failed": "Αποτυχία να προστεθεί το όνομα bot \"$1\". Έχει ήδη προστεθεί;",
        "botpasswords-update-failed": "Αποτυχία ενημέρωσης της ονομασίας του ρομπότ «$1». Μήπως διαγράφτηκε ο κωδικός;",
        "botpasswords-created-title": "Ο κωδικός πρόσβασης του ρομπότ δημιουργήθηκε",
        "botpasswords-created-body": "Ο κωδικός πρόσβασης για το όνομα ρομπότ \"$1\" του χρήστη \"$2\" δημιουργήθηκε.",
        "botpasswords-updated-title": "Ο κωδικός πρόσβασης του ρομπότ ενημερώθηκε",
        "botpasswords-updated-body": "Ο κωδικός πρόσβασης του ρομπότ «$1» του χρήστη «$2» ενημερώθηκε.",
        "botpasswords-deleted-title": "Ο κωδικός πρόσβασης του ρομπότ διαγράφτηκε",
+       "botpasswords-deleted-body": "Ο κωδικός πρόσβασης για το όνομα ρομπότ \"$1\" του χρήστη \"$2\" διαγράφηκε.",
+       "botpasswords-newpassword": "Ο νέος κωδικός πρόσβασης για να συνδεθείτε με το <strong>$1</strong> είναι <strong>$2</strong>. <em>Παρακαλούμε σημειώστε το για μελλοντική αναφορά.</em>",
        "botpasswords-no-provider": "BotPasswordsSessionProvider δεν είναι διαθέσιμο.",
+       "botpasswords-restriction-failed": "Περιορισμοί κωδικών πρόσβασης bot εμποδίζουν τη συγκεκριμένη σύνδεση.",
        "resetpass_forbidden": "Οι κωδικοί πρόσβασης δεν μπορούν να αλλαχθούν",
        "resetpass_forbidden-reason": "Οι κωδικοί πρόσβασης δεν μπορούν να αλλαχθούν: $1",
        "resetpass-no-info": "Πρέπει να είστε συνδεδεμένος για να δείτε αυτήν την σελίδα απευθείας",
index b55cb76..e1c37c8 100644 (file)
        "grant-group-high-volume": "Perform high volume activity",
        "grant-group-customization": "Customization and preferences",
        "grant-group-administration": "Perform administrative actions",
+       "grant-group-private-information": "Access private data about you",
        "grant-group-other": "Miscellaneous activity",
        "grant-blockusers": "Block and unblock users",
        "grant-createaccount": "Create accounts",
        "grant-highvolume": "High-volume editing",
        "grant-oversight": "Hide users and suppress revisions",
        "grant-patrol": "Patrol changes to pages",
+       "grant-privateinfo": "Access private information",
        "grant-protect": "Protect and unprotect pages",
        "grant-rollback": "Rollback changes to pages",
        "grant-sendemail": "Send email to other users",
        "undeletehistorynoadmin": "This page has been deleted.\nThe reason for deletion is shown in the summary below, along with details of the users who had edited this page before deletion.\nThe actual text of these deleted revisions is only available to administrators.",
        "undelete-revision": "Deleted revision of $1 (as of $4, at $5) by $3:",
        "undeleterevision-missing": "Invalid or missing revision.\nYou may have a bad link, or the revision may have been restored or removed from the archive.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|One revision|$1 revisions}} could not be restored, because {{PLURAL:$1|its|their}} <code>rev_id</code> was already in use.",
        "undelete-nodiff": "No previous revision found.",
        "undeletebtn": "Restore",
        "undeletelink": "view/restore",
        "undeletedrevisions": "{{PLURAL:$1|1 revision|$1 revisions}} restored",
        "undeletedrevisions-files": "{{PLURAL:$1|1 revision|$1 revisions}} and {{PLURAL:$2|1 file|$2 files}} restored",
        "undeletedfiles": "{{PLURAL:$1|1 file|$1 files}} restored",
-       "cannotundelete": "Undelete failed:\n$1",
+       "cannotundelete": "Some or all of the undeletion failed:\n$1",
        "undeletedpage": "<strong>$1 has been restored</strong>\n\nConsult the [[Special:Log/delete|deletion log]] for a record of recent deletions and restorations.",
        "undelete-header": "See [[Special:Log/delete|the deletion log]] for recently deleted pages.",
        "undelete-search-title": "Search deleted pages",
        "sp-contributions-newbies-sub": "For new accounts",
        "sp-contributions-newbies-title": "User contributions for new accounts",
        "sp-contributions-blocklog": "block log",
-       "sp-contributions-suppresslog": "suppressed user contributions",
-       "sp-contributions-deleted": "deleted user contributions",
+       "sp-contributions-suppresslog": "suppressed {{GENDER:$1|user}} contributions",
+       "sp-contributions-deleted": "deleted {{GENDER:$1|user}} contributions",
        "sp-contributions-uploads": "uploads",
        "sp-contributions-logs": "logs",
        "sp-contributions-talk": "talk",
index 73c96e8..10e56f2 100644 (file)
@@ -58,7 +58,7 @@
        "tog-extendwatchlist": "Etendi la atentaron por montri ĉiujn ŝanĝojn, ne nur la plej lastajn",
        "tog-usenewrc": "Grupigi ŝanĝojn laŭ paĝo en \"Lastaj ŝanĝoj\" kaj \"Atentaro\" (bezonas Ĝavaskripton)",
        "tog-numberheadings": "Aŭtomate numeri sekciojn",
-       "tog-showtoolbar": "Montri redakto-breton (per Ĝavaskripto)",
+       "tog-showtoolbar": "Montri redakto-breton",
        "tog-editondblclick": "Redakti paĝojn per duobla alklako",
        "tog-editsectiononrightclick": "Ŝalti sekcian redaktadon per dekstra musklako de sekciaj titoloj (per Ĝavaskripto)",
        "tog-watchcreations": "Aldoni miajn kreatajn paĝojn kaj miajn alŝutaĵojn al mia atentaro",
        "october-date": "$1‑a de oktobro",
        "november-date": "$1‑a de novembro",
        "december-date": "$1‑a de decembro",
-       "period-am": "ATM",
-       "period-pm": "PTM",
+       "period-am": "atm.",
+       "period-pm": "ptm.",
        "pagecategories": "{{PLURAL:$1|Kategorio|Kategorioj}}",
        "category_header": "Artikoloj en kategorio “$1”",
        "subcategories": "Subkategorioj",
        "updatedmarker": "ĝisdatigita de post mia lasta vizito",
        "printableversion": "Presebla versio",
        "permalink": "Konstanta ligilo",
-       "print": "Printi",
+       "print": "Presi",
        "view": "Vidi",
        "view-foreign": "Rigardi en $1",
        "edit": "Redakti",
        "accmailtext": "Hazarde generita pasvorto por [[User talk:$1|$1]] estis sendita al $2.\n\nLa pasvorto por ĉi tiu nova konto povas esti ŝanĝita en la paĝo ''[[Special:ChangePassword|ŝanĝi pasvorton]]'' dum ensalutado.",
        "newarticle": "(Nova)",
        "newarticletext": "Vi sekvis ligilon al paĝo ankoraŭ ne ekzistanta. Se vi volas krei ĝin, ektajpu malsupre (vidu la [$1 helpopaĝon] por klarigoj.) Se vi malintence alvenis ĉi tien, simple alklaku la retrobutonon de via retumilo.",
-       "anontalkpagetext": "<em>Jen diskutopaĝo por anonima kontribuanto kiu ne jam kreis konton aŭ ne uzas ĝin.</em>\nNi tial devas uzi la cifran IP-adreson por identigi lin/ŝin.\nĈi tia IP-adreso povas esti uzata de pluraj uzantoj.\nSe vi estas anonimulo kaj preferus eviti tiajn mistrafajn komentojn al vi, bonvolu [[Special:CreateAccount|krei konton]] aŭ [[Special:UserLogin|ensaluti]] por eviti estontan konfuzon pro aliaj anonimaj uzantoj.''",
+       "anontalkpagetext": "<em>Jen diskutopaĝo por anonima kontribuanto kiu ankoraŭ ne kreis konton aŭ ne uzas ĝin.</em>\nNi tial devas uzi la cifran IP-adreson por identigi tiun kontribuanton.\nĈi tia IP-adreso povas esti uzata de pluraj uzantoj.\nSe vi estas anonimulo kaj preferus eviti tiajn mistrafajn komentojn al vi, bonvolu [[Special:CreateAccount|krei konton]] aŭ [[Special:UserLogin|ensaluti]] por eviti estontan konfuzon pro aliaj anonimaj uzantoj.''",
        "noarticletext": "Mankas teksto en ĉi tiu paĝo.\nVi povas [[Special:Search/{{PAGENAME}}|serĉi ĉi tiun paĝtitolon]] en aliaj paĝoj,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serĉi la rilatajn protokolojn],\naŭ [{{fullurl:{{FULLPAGENAME}}|action=edit}} krei ĉi tiun paĝon]</span>.",
        "noarticletext-nopermission": "Estas neniom da teksto en ĉi tiu paĝo.\nVi povas [[Special:Search/{{PAGENAME}}|serĉi ĉi tiun paĝan titolon]] en aliaj paĝoj,\naŭ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serĉi la rilatajn protokolojn]</span>, sed vi ne rajtas krei ĉi tiun paĝon.",
        "missing-revision": "La revizio n-ro $1 de la paĝo nomata \"{{FULLPAGENAME}}\" ne ekzistas.\n\nTio kutime estas kaŭzata per sekvado de malaktuala historio-ligilo al paĝo forigita.\nDetaloj troveblos en la [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de forigoj].",
        "content-model-css": "CSS",
        "content-json-empty-object": "Malplena objeto",
        "content-json-empty-array": "Malplena tabelo",
-       "deprecated-self-close-category": "Paĝoj kun nevalida memferma HTML‑etikedon",
+       "deprecated-self-close-category": "Paĝoj kun nevalida memferma HTML‑etikedo",
        "duplicate-args-warning": "'''Averto:''' [[:$1]] vokas al [[:$2]] kun pli ol unu valoro por la parametro \"$3\". Nur la lasta liverita valoro estos uzata.",
        "duplicate-args-category": "Paĝoj kun pluroblaj argumentoj en ŝablonvokoj",
        "duplicate-args-category-desc": "La paĝo enhavas uzon de ŝablono kun pluroble uzitaj argumentoj, kiel ekzemple <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> aŭ <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "undo-summary-username-hidden": "Malfari ŝanĝon $1 de kaŝita uzanto",
        "cantcreateaccount-text": "Konto-kreado de ĉi tiu IP-adreso ('''$1''') estis forbarita de [[User:$3|$3]].\n\nLa kialo donata de $3 estas ''$2''.",
        "cantcreateaccount-range-text": "La kreado de kontoj de IP-adresoj en la intervalo <strong>$1</strong>, kiu inkludas vian IP-adreson (<strong>$4</strong>), estis blokita de [[User:$3|$3]].\n\nLa donita kialo de $3 estas <em>$2</em>",
-       "viewpagelogs": "Vidi la protokolojn por tiu ĉi paĝo",
+       "viewpagelogs": "Vidi la protokolojn por ĉi tiu paĝo",
        "nohistory": "Ne ekzistas historio de redaktoj por ĉi tiu paĝo.",
        "currentrev": "Aktuala versio",
        "currentrev-asof": "Nuna versio ekde $1",
        "tooltip-pt-logout": "Elsaluti",
        "tooltip-pt-createaccount": "Ni rekomendas al vi kreon de uzantokonto kaj ensaluto; tamen, tio ne estas deviga",
        "tooltip-ca-talk": "Diskuto pri la artikolo",
-       "tooltip-ca-edit": "Redakti tiun ĉi paĝon",
+       "tooltip-ca-edit": "Redakti ĉi tiun paĝon",
        "tooltip-ca-addsection": "Starti novan sekcion",
        "tooltip-ca-viewsource": "Tiu paĝo estas protektita. Vi povas nur rigardi ties fonton.",
-       "tooltip-ca-history": "Antaŭaj versioj de tiu ĉi paĝo.",
+       "tooltip-ca-history": "Antaŭaj versioj de ĉi tiu paĝo.",
        "tooltip-ca-protect": "Protekti tiun ĉi paĝon",
        "tooltip-ca-unprotect": "Ŝanĝi protektadon de ĉi tiu paĝo",
        "tooltip-ca-delete": "Forigi tiun ĉi paĝon",
        "tooltip-ca-undelete": "Restarigu la redaktojn faritajn al tiu ĉi paĝo antaŭ ties forigo",
-       "tooltip-ca-move": "Alinomigi tiun ĉi paĝon",
-       "tooltip-ca-watch": "Aldoni tiun ĉi paĝon al via atentaro",
+       "tooltip-ca-move": "Alinomigi ĉi tiun paĝon",
+       "tooltip-ca-watch": "Aldoni ĉi tiun paĝon al via atentaro",
        "tooltip-ca-unwatch": "Forigi tiun ĉi paĝon el via atentaro",
        "tooltip-search": "Serĉi tra {{SITENAME}}",
        "tooltip-search-go": "Iru al paĝo kun ĉi preciza nomo se ĝi ekzistas",
        "tooltip-n-randompage": "Iri al hazarda paĝo",
        "tooltip-n-help": "La loko por eltrovi",
        "tooltip-t-whatlinkshere": "Listo de ĉiuj vikiaj paĝoj kiuj ligas ĉi tien",
-       "tooltip-t-recentchangeslinked": "Lastaj ŝanĝoj en paĝoj kiuj ligas al tiu ĉi paĝo",
+       "tooltip-t-recentchangeslinked": "Lastaj ŝanĝoj en paĝoj kiuj ligas al ĉi tiu paĝo",
        "tooltip-feed-rss": "RSS-fonto por tiu ĉi paĝo",
        "tooltip-feed-atom": "Atom-fonto por ĉi tiu paĝo",
        "tooltip-t-contributions": "Listo de kontribuoj de {{GENDER:$1|ĉi tiu uzanto}}",
index cd16fd1..ac4112f 100644 (file)
        "logentry-protect-modify-cascade": "$1 سطح حفاظت برای $3 $4 را {{GENDER:$2|تغییر داد}}[آبشاری]",
        "logentry-rights-rights": "$1 دسترسی $3 را از گروه $4 به $5 تغییر داد",
        "logentry-rights-rights-legacy": "$1 گروه عضویت $3 را {{GENDER:$2|تغییر داد}}",
-       "logentry-rights-autopromote": "$1 به طور خودکار از $4 به $5 {{GENDER:$2|ارتقاء داد}}",
+       "logentry-rights-autopromote": "$1 به طور خودکار از $4 به $5 {{GENDER:$2|ارتقاء یافت}}",
        "logentry-upload-upload": "$1 $3 را {{GENDER:$2|بارگذاری کرد}}",
        "logentry-upload-overwrite": "$1 نسخهٔ تازه‌ای از $3 را {{GENDER:$2|بارگذاری کرد}}",
        "logentry-upload-revert": "$1 {{GENDER:$2|بارگذاری کرد}} $3",
index 87fb07f..f145ca9 100644 (file)
        "grant-group-high-volume": "Effectuer une activité de fort volume",
        "grant-group-customization": "Personnalisation et préférences",
        "grant-group-administration": "Effectuer des actions administratives",
+       "grant-group-private-information": "Accéder à vos données privées",
        "grant-group-other": "Activités diverses",
        "grant-blockusers": "Bloquer et débloquer des utilisateurs",
        "grant-createaccount": "Créer des comptes",
        "grant-highvolume": "Modification de gros volumes",
        "grant-oversight": "Masquer les utilisateurs et supprimer les révisions",
        "grant-patrol": "Vérifier les modifications de pages",
+       "grant-privateinfo": "Accéder aux informations privées",
        "grant-protect": "Protéger et déprotéger des pages",
        "grant-rollback": "Révoquer des modifications sur des pages",
        "grant-sendemail": "Envoyer des courriels aux autres utilisateurs",
        "upload_directory_missing": "Le répertoire d’import de fichier ($1) est introuvable et n’a pas pu être créé par le serveur web.",
        "upload_directory_read_only": "Le serveur web n’a pas accès en écriture au répertoire d’import de fichier ($1).",
        "uploaderror": "Erreur lors de l’import",
-       "upload-recreate-warning": "'''Attention : Un fichier portant ce nom a été supprimé ou déplacé.'''\n\nLe journal des suppressions et celui des déplacements de cette page sont affichés ici pour informations :",
+       "upload-recreate-warning": "<strong>Attention : Un fichier portant ce nom a été supprimé ou déplacé.</strong>\n\nLe journal des suppressions et celui des déplacements de cette page sont affichés ici pour informations :",
        "uploadtext": "Utilisez ce formulaire pour importer des fichiers sur le serveur.\nPour voir ou rechercher des images précédemment envoyées, consultez la [[Special:FileList|liste des images]]. L’import est aussi enregistré dans le [[Special:Log/upload|journal d’import des fichiers]], et les suppressions dans le [[Special:Log/delete|journal des suppressions]].\n\nPour inclure un fichier dans une page, utilisez un lien de la forme :\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:fichier.jpg]]</nowiki></code>''', pour afficher le fichier en pleine résolution (dans le cas d’une image) ;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:fichier.png|200px|thumb|left|texte descriptif]]</nowiki></code>''' pour utiliser une miniature de 200 pixels de large dans une boîte à gauche avec « texte descriptif » comme description ;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:fichier.ogg]]</nowiki></code>''' pour lier directement vers le fichier sans l’afficher.",
        "upload-permitted": "{{PLURAL:$2|Format|Formats}} de fichiers {{PLURAL:$2|autorisé|autorisés}} : $1.",
        "upload-preferred": "{{PLURAL:$2|Format|Formats}} de fichiers {{PLURAL:$2|préféré|préférés}} : $1.",
        "unknown-error": "Une erreur inconnue s’est produite.",
        "tmp-create-error": "Impossible de créer le fichier temporaire.",
        "tmp-write-error": "Erreur d'écriture du fichier temporaire.",
-       "large-file": "Les fichiers importés ne devraient pas dépasser $1 ; ce fichier fait $2.",
-       "largefileserver": "La taille de ce fichier est supérieure au maximum autorisé.",
+       "large-file": "Les fichiers importés ne devraient pas dépasser $1 ; \nce fichier fait $2.",
+       "largefileserver": "La taille de ce fichier est supérieure au maximum autorisé par le serveur.",
        "emptyfile": "Le fichier que vous voulez importer semble vide.\nCeci peut être dû à une erreur dans le nom du fichier.\nVeuillez vérifier que vous désirez vraiment importer ce fichier.",
        "windows-nonascii-filename": "Ce wiki ne supporte pas les noms de fichiers avec des caractères spéciaux.",
        "fileexists": "Un fichier existe déjà sous ce nom.\nMerci de vérifier <strong>[[:$1]]</strong> si vous n'êtes pas certain{{GENDER:||e|}} de vouloir le remplacer.\n[[$1|thumb]]",
-       "filepageexists": "La page de description pour ce fichier a déjà été créée ici <strong>[[:$1]]</strong>, mais aucun fichier n'existe actuellement sous ce nom.\nLe résumé que vous allez spécifier n'apparaîtra pas sur la page de description.\nPour que ce soit le cas, vous devrez modifier manuellement la page. [[$1|thumb]]",
+       "filepageexists": "La page de description pour ce fichier a déjà été créée ici <strong>[[:$1]]</strong>, mais aucun fichier n'existe actuellement sous ce nom.\nLe résumé que vous allez spécifier n'apparaîtra pas sur la page de description.\nPour que ce soit le cas, vous devrez modifier manuellement la page. \n[[$1|thumb]]",
        "fileexists-extension": "Un fichier existe avec un nom proche : [[$2|thumb]]\n* Nom du fichier à importer : <strong>[[:$1]]</strong>\n* Nom du fichier existant : <strong>[[:$2]]</strong>\nPeut-être voulez-vous utiliser un nom plus explicite ?",
        "fileexists-thumbnail-yes": "Le fichier semble être une image en taille réduite <em>(vignette)</em>. \n[[$1|thumb]]\nVeuillez vérifier le fichier <strong>[[:$1]]</strong>.\nSi le fichier vérifié est la même image avec la taille initiale, il n'y a pas besoin d'importer une version réduite.",
        "file-thumbnail-no": "Le nom du fichier commence par <strong>$1</strong>.\nIl est possible qu'il s'agisse d'une version réduite <em>(vignette)</em>.\nSi vous disposez du fichier en haute résolution, importez-le, sinon veuillez modifier son nom.",
        "uploadscripted": "Ce fichier contient du code HTML ou un script qui pourrait être interprété de façon incorrecte par un navigateur web.",
        "upload-scripted-pi-callback": "Impossible de charger un fichier qui contient des instructions de traitement de feuille de style XML.",
        "uploaded-script-svg": "Élément scriptable « $1 » trouvé dans le fichier SVG téléchargé.",
-       "uploaded-hostile-svg": "CSS non sûr trouvé dans l’élément style d’un fichier SVG téléchargé.",
+       "uploaded-hostile-svg": "CSS non sûr trouvé dans l’élément style d’un fichier SVG téléversé.",
        "uploaded-event-handler-on-svg": "Fixer des attributs de gestionnaire d’événement <code>$1=\"$2\"</code> n’est pas autorisé dans les fichiers SVG.",
        "uploaded-href-attribute-svg": "les attributs href dans les fichiers SVG ne sont autorisés que pour faire référence à des cibles http:// ou https://, <code>&lt;$1 $2=\"$3\"&gt;</code> trouvé.",
-       "uploaded-href-unsafe-target-svg": "href vers des données non sûres trouvé dans le fichier SVG téléchargé : URI cible <code>&lt;$1 $2=\"$3\"&gt;</code>.",
+       "uploaded-href-unsafe-target-svg": "Un href vers des données non sûres a été trouvé dans le fichier SVG téléchargé : URI cible <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-animate-svg": "Balise « animate » trouvée, qui pourrait modifier le href en utilisant l’attribut « from » <code>&lt;$1 $2=\"$3\"&gt;</code> dans le fichier SVG téléchargé.",
        "uploaded-setting-event-handler-svg": "Positionner des attributs de gestionnaire d’événement est bloqué, <code>&lt;$1 $2=\"$3\"&gt;</code> trouvé dans le fichier SVG téléchargé.",
        "uploaded-setting-href-svg": "L’utilisation de la balise « set » pour ajouter un attribut « href » à l’élément parent est interdite.",
        "backend-fail-describe": "Impossible de modifier les métadonnées du fichier « $1 ».",
        "backend-fail-alreadyexists": "Le fichier \"$1\" existe déjà.",
        "backend-fail-store": "Impossible de stocker le fichier \"$1\" en \"$2\".",
-       "backend-fail-copy": "Impossible de copier le fichier $1 en $2.",
+       "backend-fail-copy": "Impossible de copier le fichier « $1 » en « $2 ».",
        "backend-fail-move": "Impossible de déplacer le fichier \"$1\" en \"$2\".",
        "backend-fail-opentemp": "Impossible d’ouvrir le fichier temporaire.",
        "backend-fail-writetemp": "Impossible d’écrire dans le fichier temporaire.",
        "backend-fail-closetemp": "Impossible de fermer le fichier temporaire.",
        "backend-fail-read": "Impossible de lire le fichier \"$1\".",
-       "backend-fail-create": "Impossible d’écrire le fichier « $1\" ».",
-       "backend-fail-maxsize": "Impossible d’écrire le fichier $1 parce qu’il est plus grand {{PLURAL:$2|qu’un octet|que $2 octets}}.",
+       "backend-fail-create": "Impossible d’écrire le fichier « $1 ».",
+       "backend-fail-maxsize": "Impossible d’écrire le fichier « $1 » parce qu’il est plus grand {{PLURAL:$2|qu’un octet|que $2 octets}}.",
        "backend-fail-readonly": "Le support de stockage « $1 » est actuellement en lecture seule. La raison indiquée est : <em>$2</em>",
        "backend-fail-synced": "Le fichier « $1 » est dans un état incohérent dans les supports de stockage internes",
        "backend-fail-connect": "Impossible de se connecter au support de stockage « $1 ».",
        "img-auth-noread": "L'utilisateur n'a pas le droit en lecture sur « $1 ».",
        "http-invalid-url": "URL incorrecte : $1",
        "http-invalid-scheme": "Les URL avec le schéma « $1 » ne sont pas prises en charge.",
-       "http-request-error": "Erreur inconnue lors de l'envoi de la requête.",
+       "http-request-error": "Erreur inconnue lors de l'envoi de la requête HTTP.",
        "http-read-error": "Erreur de lecture HTTP.",
        "http-timed-out": "La requête HTTP a expiré.",
        "http-curl-error": "Erreur lors de la récupération de l'URL : $1",
        "http-bad-status": "Il y a eu un problème lors de la requête HTTP : $1 $2",
        "upload-curl-error6": "URL injoignable",
-       "upload-curl-error6-text": "L’URL fournie ne peut pas être atteinte. Veuillez vérifier que l’URL est correcte et que le site est en ligne.",
+       "upload-curl-error6-text": "L’URL fournie ne peut pas être atteinte. \nVeuillez vérifier que l’URL est correcte et que le site est en ligne.",
        "upload-curl-error28": "Dépassement du délai lors de l'import",
-       "upload-curl-error28-text": "Le site a mis trop longtemps à répondre. Vérifiez que le site est en ligne, attendez un peu et réessayez. Vous pouvez aussi réessayer à une heure de moindre affluence.",
+       "upload-curl-error28-text": "Le site a mis trop longtemps à répondre. \nVérifiez que le site est en ligne, attendez un peu et réessayez. \nVous pouvez aussi réessayer à une heure de moindre affluence.",
        "license": "Licence",
        "license-header": "Conditions d'utilisation",
        "nolicense": "Aucune licence sélectionnée",
        "nolinkstoimage": "Aucune page n'utilise ce fichier.",
        "morelinkstoimage": "Voir [[Special:WhatLinksHere/$1|plus de liens]] vers ce fichier.",
        "linkstoimage-redirect": "$1 (redirection de fichier) $2",
-       "duplicatesoffile": "{{PLURAL:$1|Le fichier suivant est un duplicata|Les fichiers suivants sont des duplicatas}} de celui-ci ([[Special:FileDuplicateSearch/$2|plus de détails]]) :",
+       "duplicatesoffile": "{{PLURAL:$1|Le fichier suivant est un doublon|Les $1 fichiers suivants sont des doublons}} de celui-ci ([[Special:FileDuplicateSearch/$2|plus de détails]]) :",
        "sharedupload": "Ce fichier provient de : $1. Il peut être utilisé par d'autres projets.",
        "sharedupload-desc-there": "Ce fichier provient de : $1. Il peut être utilisé par d'autres projets.\nVeuillez consulter [$2 sa page de description] pour plus d'informations.",
        "sharedupload-desc-here": "Ce fichier provient de $1. Il peut être utilisé par d'autres projets.\nSa description sur sa [$2 page de description] est affichée ci-dessous.",
        "filedelete-intro-old": "Vous êtes en train d'effacer la version de '''[[Media:$1|$1]]''' du [$4 $2 à $3].",
        "filedelete-comment": "Motif :",
        "filedelete-submit": "Supprimer",
-       "filedelete-success": "'''$1''' a été supprimé.",
-       "filedelete-success-old": "La version de '''[[Media:$1|$1]]''' du $2 à $3 a été supprimée.",
-       "filedelete-nofile": "'''$1''' n'existe pas.",
-       "filedelete-nofile-old": "Il n'existe aucune version archivée de '''$1''' avec les attributs indiqués.",
+       "filedelete-success": "<strong>$1</strong> a été supprimé.",
+       "filedelete-success-old": "La version de <strong>[[Media:$1|$1]]</strong> du $2 à $3 a été supprimée.",
+       "filedelete-nofile": "<strong>$1</strong> n'existe pas.",
+       "filedelete-nofile-old": "Il n'existe aucune version archivée de <strong>$1</strong> avec les attributs indiqués.",
        "filedelete-otherreason": "Motif autre / supplémentaire :",
        "filedelete-reason-otherlist": "Autre motif",
        "filedelete-reason-dropdown": "* Motifs fréquents de suppression de fichiers\n** Violation du droit d'auteur\n** Fichier dupliqué",
-       "filedelete-edit-reasonlist": "Modifier les motifs fréquents de suppression",
-       "filedelete-maintenance": "La suppression et restauration de fichiers est temporairement désactivée durant la maintenance.",
+       "filedelete-edit-reasonlist": "Modifier les motifs de suppression",
+       "filedelete-maintenance": "La suppression et la restauration de fichiers sont  temporairement désactivées durant la maintenance.",
        "filedelete-maintenance-title": "Impossible de supprimer le fichier",
        "mimesearch": "Recherche par type de contenu MIME",
        "mimesearch-summary": "Cette page vous permet de filtrer les fichiers par leur type de contenu MIME.\nEntrée : type_de_contenu/sous-type ou type_de_contenu/*, par ex. <code>image/jpeg</code>.",
        "randompage-nopages": "Il n'y a aucune page dans {{PLURAL:$2|l'espace de noms|les espaces de noms}} : $1.",
        "randomincategory": "Page au hasard dans la catégorie",
        "randomincategory-invalidcategory": "« $1 » n’est pas un nom de catégorie valide.",
-       "randomincategory-nopages": "Il n’y a pas de page dans [[:Category:$1]].",
+       "randomincategory-nopages": "Il n’y a pas de pages dans la catégorie [[:Category:$1|$1]].",
        "randomincategory-category": "Catégorie :",
        "randomincategory-legend": "Page aléatoire dans la catégorie",
        "randomincategory-submit": "Lancer",
        "statistics-edits-average": "Nombre moyen de modifications par page",
        "statistics-users": "[[Special:ListUsers|Utilisateurs]] enregistrés",
        "statistics-users-active": "Utilisateurs actifs",
-       "statistics-users-active-desc": "Utilisateurs ayant fait au moins une action durant {{PLURAL:$1|le dernier jours|les $1 derniers jours}}",
+       "statistics-users-active-desc": "Utilisateurs ayant fait au moins une action {{PLURAL:$1|il y a un jour|pendant les $1 derniers jours}}",
        "pageswithprop": "Pages avec une propriété de page",
        "pageswithprop-legend": "Pages avec une propriété de page",
        "pageswithprop-text": "Cette page liste les pages qui utilisent une propriété de page particulière.",
        "apisandbox-fullscreen-tooltip": "Étendre le panneau du bac à sable pour remplir la fenêtre du navigateur.",
        "apisandbox-unfullscreen": "Afficher la page",
        "apisandbox-unfullscreen-tooltip": "Réduire le panneau du bac à sable, pour que les liens de navigation de MediaWiki soient disponibles.",
-       "apisandbox-submit": "Faire la demande",
+       "apisandbox-submit": "Envoyer la requête",
        "apisandbox-reset": "Effacer",
        "apisandbox-retry": "Réessayer",
        "apisandbox-loading": "Chargement des informations du module \"$1\" de l'API...",
        "undeletehistorynoadmin": "Cette page a été supprimée.\nLe motif de la suppression est indiqué dans le résumé ci-dessous, avec les détails des utilisateurs qui ont modifié la page avant sa suppression.\nLe contenu effectif de ces versions supprimées n’est accessible qu’aux administrateurs.",
        "undelete-revision": "Version supprimée de $1 (version du $4 à $5) par $3 :",
        "undeleterevision-missing": "Version incorrecte ou manquante.\nVous avez peut-être un mauvais lien, ou la version a pu être restaurée ou supprimée de l’archive.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Une révision n'a|$1 révisions n'ont}} pas pu être restaurée{{PLURAL:$1|car son|s car leur}}  <code>rev_id</code> était déjà en cours d'utilisation.",
        "undelete-nodiff": "Aucune version précédente trouvée.",
        "undeletebtn": "Restaurer",
        "undeletelink": "voir/restaurer",
        "undeletedrevisions": "$1 {{PLURAL:$1|version restaurée|versions restaurées}}",
        "undeletedrevisions-files": "$1 version{{PLURAL:$1||s}} et $2 fichier{{PLURAL:$2||s}} restauré{{PLURAL:$2||s}}",
        "undeletedfiles": "$1 {{PLURAL:$1|fichier restauré|fichiers restaurés}}",
-       "cannotundelete": "Échec de la restauration :\n$1",
+       "cannotundelete": "Certaines ou toutes les restitutions ont échoué:\n$1",
        "undeletedpage": "'''La page $1 a été restaurée.'''\n\nConsultez le [[Special:Log/delete|journal des suppressions]] pour obtenir la liste des récentes suppressions et restaurations.",
        "undelete-header": "Consultez le [[Special:Log/delete|journal des suppressions]] pour lister les pages récemment supprimées.",
        "undelete-search-title": "Rechercher les pages supprimées",
        "sp-contributions-newbies-sub": "Parmi les nouveaux comptes",
        "sp-contributions-newbies-title": "Contributions d'utilisateurs parmi les nouveaux comptes",
        "sp-contributions-blocklog": "journal des blocages",
-       "sp-contributions-suppresslog": "contributions masquées",
-       "sp-contributions-deleted": "contributions supprimées",
+       "sp-contributions-suppresslog": "contributions de l'{{GENDER:$1|utilisateur|utilisatrice}} supprimées",
+       "sp-contributions-deleted": "contributions de l’{{GENDER:$1|utilisateur|utilisatrice}} supprimées",
        "sp-contributions-uploads": "imports",
        "sp-contributions-logs": "journaux",
        "sp-contributions-talk": "discuter",
index 10bb66a..f76e5b8 100644 (file)
@@ -22,7 +22,8 @@
                        "VaiPolaSombra",
                        "Macofe",
                        "Banjo",
-                       "Josep Maria Roca Peña"
+                       "Josep Maria Roca Peña",
+                       "Luan"
                ]
        },
        "tog-underline": "Subliñar as ligazóns:",
        "grant-group-high-volume": "Realizar actividades de alto volume",
        "grant-group-customization": "Personalización e preferencias",
        "grant-group-administration": "Realizar accións administrativas",
+       "grant-group-private-information": "Acceder a datos privados sobre ti",
        "grant-group-other": "Outras actividades",
        "grant-blockusers": "Bloquear e desbloquear usuarios",
        "grant-createaccount": "Crear contas",
        "grant-highvolume": "Edicións de gran volume",
        "grant-oversight": "Agochar usuarios e eliminar revisións",
        "grant-patrol": "Patrullar os cambios feitos nas páxinas",
+       "grant-privateinfo": "Acceder a información privada",
        "grant-protect": "Protexer e desprotexer páxinas",
        "grant-rollback": "Reverter os cambios feitos nas páxinas",
        "grant-sendemail": "Enviar correos electrónicos a outros usuarios",
        "undeletehistorynoadmin": "Esta páxina foi borrada.\nO motivo do borrado consta no resumo que aparece a continuación, xunto cos detalles dos usuarios que editaron esta páxina antes da súa eliminación.\nO texto destas revisións eliminadas só está á disposición dos administradores.",
        "undelete-revision": "Revisión eliminada de \"$1\" (o $4 ás $5) feita por $3:",
        "undeleterevision-missing": "Revisión non válida ou inexistente. Pode que a ligazón conteña un erro ou que a revisión se restaurase ou eliminase do arquivo.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Unha revisión non pode ser restaurada|$1 revisións non poden ser restauradas}} porque {{PLURAL:$1|o seu|os seus}}  <code>rev_id</code> xa {{PLURAL:$1|está|están}} en uso.",
        "undelete-nodiff": "Non se atopou ningunha revisión anterior.",
        "undeletebtn": "Restaurar",
        "undeletelink": "ver/restaurar",
        "undeletedrevisions": "{{PLURAL:$1|Restaurouse $1 revisión|Restauráronse $1 revisións}}",
        "undeletedrevisions-files": "Restauráronse $1 {{PLURAL:$1|revisión|revisións}} e $2 {{PLURAL:$2|ficheiro|ficheiros}}",
        "undeletedfiles": "{{PLURAL:$1|Restaurouse $1 ficheiro|Restauráronse $1 ficheiros}}",
-       "cannotundelete": "Houbo un erro durante a restauración:\n$1",
+       "cannotundelete": "Algunhas ou todas as restauracións fallaronː\n$1",
        "undeletedpage": "'''A páxina \"$1\" foi restaurada'''\n\nComprobe o [[Special:Log/delete|rexistro de borrados]] para ver as entradas recentes no rexistro de páxinas eliminadas e restauradas.",
        "undelete-header": "Consulte [[Special:Log/delete|no rexistro de borrados]] as páxinas borradas recentemente.",
        "undelete-search-title": "Procurar páxinas borradas",
        "sp-contributions-newbies-sub": "Contribucións dos usuarios novos",
        "sp-contributions-newbies-title": "Contribucións dos usuarios novos",
        "sp-contributions-blocklog": "rexistro de bloqueos",
-       "sp-contributions-suppresslog": "contribucións borradas do usuario",
-       "sp-contributions-deleted": "contribucións borradas do usuario",
+       "sp-contributions-suppresslog": "contribucións {{GENDER:$1|do usuario|da usuaria}} suprimidas",
+       "sp-contributions-deleted": "contribucións {{GENDER:$1|do usuario|da usuaria}} borradas",
        "sp-contributions-uploads": "cargas",
        "sp-contributions-logs": "rexistros",
        "sp-contributions-talk": "conversa",
index b14e01a..432338d 100644 (file)
@@ -6,7 +6,8 @@
                        "Marwan Mohamad",
                        "Matma Rex",
                        "NoiX180",
-                       "Zhoelyakin"
+                       "Zhoelyakin",
+                       "Amire80"
                ]
        },
        "tog-underline": "Garisiyi totibawa pranala",
        "exif-orientation-1": "Normal",
        "namespacesall": "nga'amila",
        "monthsall": "nga'amila",
-       "signature": "[[{{ns:user}}:$1|$2]]\n([[{{ns:user_talk}}:$1|bisala]])",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|bisala]])",
        "specialpages": "Halaman Spesial",
        "tag-filter": "[[Special:Tags|Tag]]filter:",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag}}]]: $2)",
index 090585a..bda094a 100644 (file)
        "mainpage-nstab": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "error": "𐌰𐌹𐍂𐌶𐌴𐌹",
        "databaseerror-error": "𐌰𐌹𐍂𐌶𐌴𐌹: $1",
-       "missing-article": "ð\90\8d\83ð\90\8c° ð\90\8c³ð\90\8c°ð\90\8d\84ð\90\8c°ð\90\8c±ð\90\8c¿ð\90\8d\83 ð\90\8c½ð\90\8c¹ ð\90\8c²ð\90\8c°ð\90\8c½ð\90\8c°ð\90\8c¼ ð\90\8c¸ð\90\8c°ð\90\8c½ð\90\8c° ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8c°ð\90\8d\85ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c³ð\90\8c°ð\90\8c½ ð\90\8c´ð\90\8c¹ ð\90\8c¹ð\90\8d\84ð\90\8c° ð\90\8d\83ð\90\8cºð\90\8c°ð\90\8c» ð\90\8c±ð\90\8c¹ð\90\8c²ð\90\8c¹ð\90\8d\84ð\90\8c°ð\90\8c½: \"$1\" $2\n\n(The data base did not find the text of a page that it should have found, named \"$1\" $2.\n\nThis is usually caused by following an outdated diff or history link to a page that has been deleted.\n\nIf this is not the case, you may have found a bug in the software.\nPlease report this to an [[Special:ListUsers/sysop|administrator]], making note of the URL.)",
+       "missing-article": "ð\90\8c³ð\90\8c°ð\90\8d\84ð\90\8c°ð\90\8c±ð\90\8c´ð\90\8d\83 ð\90\8c½ð\90\8c¹ ð\90\8c±ð\90\8c¹ð\90\8c²ð\90\8c°ð\90\8d\84 ð\90\8c±ð\90\8d\89ð\90\8cºð\90\8d\89ð\90\8d\83 ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8c±ð\90\8c¹ð\90\8d\83 ð\90\8c¸ð\90\8c¹ð\90\8c¶ð\90\8c´ð\90\8c¹ ð\90\8d\83ð\90\8cºð\90\8c¿ð\90\8c»ð\90\8c³ð\90\8c´ð\90\8c³ð\90\8c¹ ð\90\8c±ð\90\8c¹ð\90\8c²ð\90\8c¹ð\90\8d\84ð\90\8c°ð\90\8c½, ð\90\8c·ð\90\8c°ð\90\8c¹ð\90\8d\84ð\90\8c°ð\90\8c½ð\90\8d\83 \"$1\" $2. \n\nð\90\8c¸ð\90\8c°ð\90\8d\84ð\90\8c° ð\90\8c¿ð\90\8d\86ð\90\8d\84ð\90\8c° ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¸ð\90\8c¹ð\90\8c¸ ð\90\8c¾ð\90\8c°ð\90\8c±ð\90\8c°ð\90\8c¹ ð\90\8c»ð\90\8c°ð\90\8c¹ð\90\8d\83ð\90\8d\84ð\90\8c¾ð\90\8c°ð\90\8c³ð\90\8c° ð\90\8d\86ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c½ð\90\8c¾ð\90\8c° ð\90\8c³ð\90\8c¹ð\90\8d\86ð\90\8d\86 ð\90\8c¸ð\90\8c°ð\90\8c¿ ð\90\8d\83ð\90\8d\80ð\90\8c¹ð\90\8c»ð\90\8c»ð\90\8c°ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹ð\90\8d\83ð\90\8d\83 ð\90\8d\83ð\90\8c´ð\90\8c¹ ð\90\8d\86ð\90\8d\82ð\90\8c°ð\90\8cµð\90\8c¹ð\90\8d\83ð\90\8d\84ð\90\8c¹ð\90\8c³ð\90\8c° ð\90\8c¹ð\90\8d\83ð\90\8d\84. ð\90\8c½ð\90\8c¹ð\90\8c±ð\90\8c°ð\90\8c¹ ð\90\8c¹ð\90\8d\83ð\90\8d\84, ð\90\8c¼ð\90\8c°ð\90\8c·ð\90\8d\84ð\90\8d\83 ð\90\8c¹ð\90\8d\83ð\90\8d\84 ð\90\8c´ð\90\8c¹ ð\90\8c±ð\90\8c¹ð\90\8c²ð\90\8c´ð\90\8d\84ð\90\8c´ð\90\8c¹ð\90\8d\83 ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c¶ð\90\8c´ð\90\8c¹ð\90\8c½ ð\90\8c¹ð\90\8c½ ð\90\8d\83ð\90\8c°ð\90\8c¿ð\90\8d\86ð\90\8d\84ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8d\82ð\90\8c°. \n\nð\90\8c±ð\90\8c¹ð\90\8c³ð\90\8c¾ð\90\8c°ð\90\8c¼ ð\90\8c¸ð\90\8c¿ð\90\8cº, ð\90\8c¼ð\90\8c´ð\90\8d\82ð\90\8c´ð\90\8c¹ ð\90\8c¸ð\90\8c°ð\90\8d\84ð\90\8c° ð\90\8c³ð\90\8c¿ [[Special:ListUsers/sysop\n|ð\90\8d\82ð\90\8c´ð\90\8c¹ð\90\8cº]] ð\90\8c²ð\90\8c¹ð\90\8d\86ð\90\8c¿ð\90\8c· ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹ð\90\8d\83ð\90\8d\83.",
        "badtitle": "𐌿𐌽𐍂𐌰𐌹𐌷𐍄𐌰𐍄𐌰 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹",
        "badtitletext": "𐍆𐍂𐌰𐌹𐌷𐌰𐌽𐍃 𐌻𐌰𐌿𐍆𐍃 𐍅𐌰𐍃 𐌿𐌽𐌲𐌰𐌼𐌰𐌲𐌰𐌽𐌳𐍃, 𐌻𐌰𐌿𐍃, 𐌰𐌹𐌸𐌸𐌰𐌿 𐌿𐌽𐍂𐌰𐌹𐌷𐍄𐌰𐌱𐌰 𐌲𐌰𐍅𐌹𐌳𐌰𐌽𐍃 𐌼𐌹𐌸𐍂𐌰𐌶𐌳𐌰 𐌸𐌰𐌿 𐌼𐌹𐌸-𐍅𐌹𐌺𐌹 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹. 𐌼𐌰𐌲𐌹 𐌷𐌰𐌱𐌰𐌽 𐌰𐌹𐌽𐌰 𐌸𐌰𐌿 𐌼𐌰𐌽𐌰𐌲𐌹𐌶𐍉𐍃 𐌱𐍉𐌺𐍉𐍃 𐌱𐍂𐌿𐌺𐌹𐌳𐍉𐍃 𐌹𐌽 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌾𐌰𐌼.",
        "viewsource": "𐍃𐌰𐌹𐍈 𐌱𐍂𐌿𐌽𐌽𐌰𐌽",
index 228c715..7f73d57 100644 (file)
        "datedefault": "ברירת המחדל",
        "prefs-labs": "אפשרויות מעבדה",
        "prefs-user-pages": "דפי משתמש",
-       "prefs-personal": "פרטי המשתמש",
+       "prefs-personal": "פרטי ה{{GENDER:|משתמש|משתמשת}}",
        "prefs-rc": "שינויים אחרונים",
        "prefs-watchlist": "רשימת המעקב",
        "prefs-editwatchlist": "עריכת רשימת המעקב",
        "grant-group-file-interaction": "אינטראקציה עם קבצים",
        "grant-group-watchlist-interaction": "אינטראקציה עם רשימת המעקב שלך",
        "grant-group-email": "שליחת דוא\"ל",
-       "grant-group-high-volume": "×\91×\99צ×\95×\99 פעולות מרובות",
+       "grant-group-high-volume": "×\91×\99צ×\95×¢ פעולות מרובות",
        "grant-group-customization": "התאמה אישית והעדפות",
        "grant-group-administration": "ביצוע פעולות ניהול",
-       "grant-group-other": "פעילות שונה",
+       "grant-group-private-information": "גישה למידע פרטי על עצמך",
+       "grant-group-other": "פעולות שונות",
        "grant-blockusers": "חסימת משתמשים ושחרורם",
        "grant-createaccount": "יצירת חשבונות",
        "grant-createeditmovepage": "יצירה, עריכה והעברה של דפים",
        "grant-highvolume": "ביצוע עריכות מרובות",
        "grant-oversight": "החבאת משתמשים והעלמת גרסאות",
        "grant-patrol": "ניטור שינויים לדפים",
+       "grant-privateinfo": "גישה למידע פרטי",
        "grant-protect": "הפעלת הגנה על דפים והסרתה",
        "grant-rollback": "שחזור שינויים בדפים",
        "grant-sendemail": "שליחת דואר אלקטרוני למשתמשים אחרים",
        "uploadstash-errclear": "מחיקת הקבצים נכשלה.",
        "uploadstash-refresh": "רענון רשימת הקבצים",
        "uploadstash-thumbnail": "הצגת תמונה ממוזערת",
+       "uploadstash-exception": "לא ניתן לאחסן את ההעלאה בסליק ($1): \"$2\".",
        "invalid-chunk-offset": "היסט גוש לא תקין",
        "img-auth-accessdenied": "הגישה נדחתה",
        "img-auth-nopathinfo": "PATH_INFO חסר.\nהשרת אינו מוגדר להעברת מידע זה.\nייתכן שהוא מבוסס על CGI ולכן אינו יכול לתמוך ב־img_auth.\nראו https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "undeletehistorynoadmin": "דף זה נמחק.\nהסיבה למחיקה מוצגת בתקציר שלמטה, וגם פרטים על המשתמשים שערכו את הדף לפני שהוא נמחק.\nהטקסט של הגרסאות הללו זמין למפעילי מערכת בלבד.",
        "undelete-revision": "גרסה שנמחקה מהדף $1 (מ־$5, $4) מאת $3:",
        "undeleterevision-missing": "הגרסה שגויה או חסרה. ייתכן שמדובר בקישור שבור, או שהגרסה שוחזרה או הוסרה מהארכיון.",
+       "undeleterevision-duplicate-revid": "לא ניתן היה לשחזר {{PLURAL:$1|גרסה אחת|$1 גרסאות}}, כיוון ששדה <code>rev_id</code> {{PLURAL:$1|שלה|שלהן}} כבר נמצא בשימוש.",
        "undelete-nodiff": "לא נמצאה גרסה קודמת.",
        "undeletebtn": "שחזור",
        "undeletelink": "הצגה/שחזור",
        "undeletedrevisions": "{{PLURAL:$1|שוחזרה גרסה אחת|שוחזרו $1 גרסאות}}",
        "undeletedrevisions-files": "{{PLURAL:$1|גרסה אחת|$1 גרסאות}} ו{{PLURAL:$2|קובץ אחד|־$2 קבצים}} שוחזרו",
        "undeletedfiles": "{{PLURAL:$1|שוחזר קובץ אחד|שוחזרו $1 קבצים}}",
-       "cannotundelete": "השחזור נכשל:\n$1",
+       "cannotundelete": "השחזור (או חלק ממנו) נכשל:\n$1",
        "undeletedpage": "<strong>הדף $1 שוחזר</strong>\n\nראו את [[Special:Log/delete|יומן המחיקות]] לרשימה של המחיקות והשחזורים שבוצעו לאחרונה.",
        "undelete-header": "{{GENDER:|ראה|ראי|ראו}} את [[Special:Log/delete|יומן המחיקות]] לרשימה של דפים שנמחקו לאחרונה.",
        "undelete-search-title": "חיפוש דפים שנמחקו",
        "sp-contributions-newbies-sub": "עבור משתמשים חדשים",
        "sp-contributions-newbies-title": "תרומות של משתמשים חדשים",
        "sp-contributions-blocklog": "יומן חסימות",
-       "sp-contributions-suppresslog": "תרומות משתמש מועלמות",
-       "sp-contributions-deleted": "תרומות משתמש מחוקות",
+       "sp-contributions-suppresslog": "תרומות {{GENDER:$1|משתמש|משתמשת}} מועלמות",
+       "sp-contributions-deleted": "תרומות {{GENDER:$1|משתמש|משתמשת}} מחוקות",
        "sp-contributions-uploads": "העלאות",
        "sp-contributions-logs": "יומנים",
        "sp-contributions-talk": "שיחה",
        "tags-active-yes": "כן",
        "tags-active-no": "לא",
        "tags-source-extension": "הוגדר על־ידי הרחבה",
-       "tags-source-manual": "×\94וחל באופן ידני על־ידי משתמשים ובוטים",
+       "tags-source-manual": "×\9eוחל באופן ידני על־ידי משתמשים ובוטים",
        "tags-source-none": "אינו בשימוש כעת",
        "tags-edit": "עריכה",
        "tags-delete": "מחיקה",
index 9603a3f..e4b81bf 100644 (file)
        "minoredit": "Ovo je manja promjena",
        "watchthis": "Prati ovu stranicu",
        "savearticle": "Sačuvaj stranicu",
+       "publishpage": "Objavi stranicu",
+       "publishchanges": "Objavi izmjene",
        "preview": "Pregled kako će stranica izgledati",
        "showpreview": "Prikaži kako će izgledati",
        "showdiff": "Prikaži promjene",
index 9ad03b8..d241144 100644 (file)
        "botpasswords-bad-appid": "A(z) „$1” botnév érvénytelen.",
        "botpasswords-insert-failed": "A(z) „$1” botnév hozzáadása sikertelen. Nem lehet, hogy már hozzá lett adva?",
        "botpasswords-created-title": "Botjelszó létrehozva",
-       "botpasswords-created-body": "Bot jelszó \"$1\" sikeresen létrehozva.",
+       "botpasswords-created-body": "\"$2\" felhasználó \"$1\" bot jelszava létrehozva.",
        "botpasswords-updated-title": "Botjelszó frissítve",
-       "botpasswords-updated-body": "Bot jelszó \"$1\" frissítése sikerült.",
+       "botpasswords-updated-body": "\"$2\" felhasználó \"$1\" bot jelszava módosítva.",
        "botpasswords-deleted-title": "Botjelszó törölve",
-       "botpasswords-deleted-body": "Bot jelszó \"$1\" törölve.",
+       "botpasswords-deleted-body": "\"$2\" felhasználó \"$1\" bot jelszava törölve.",
        "botpasswords-no-provider": "A BotPasswordsSessionProvider nem áll rendelkezésre.",
        "resetpass_forbidden": "A jelszavak nem változtathatók meg",
+       "resetpass_forbidden-reason": "A jelszavakat nem változtathatóak meg: $1",
        "resetpass-no-info": "Be kell jelentkezned, hogy közvetlenül elérd ezt a lapot.",
        "resetpass-submit-loggedin": "Jelszó megváltoztatása",
        "resetpass-submit-cancel": "Mégse",
        "minoredit": "Apró változtatás",
        "watchthis": "A lap figyelése",
        "savearticle": "Lap mentése",
+       "savechanges": "Módosítások mentése",
        "publishpage": "Lap közzététele",
        "publishchanges": "Változtatások közzététele",
        "preview": "Előnézet",
index 591cfa5..bcb0af0 100644 (file)
        "cannotlogoutnow-title": "Impossibile clauder session ora",
        "cannotlogoutnow-text": "Non es possibile clauder le session usante $1.",
        "welcomeuser": "Benvenite, $1!",
-       "welcomecreation-msg": "Tu conto ha essite create.\nNon oblida personalisar tu [[Special:Preferences|preferentias in {{SITENAME}}]].",
+       "welcomecreation-msg": "Tu conto ha essite create.\nTu pote personalisar tu [[Special:Preferences|preferentias]] in {{SITENAME}}, si tu vole.",
        "yourname": "Nomine de usator:",
        "userlogin-yourname": "Nomine de usator",
        "userlogin-yourname-ph": "Entra tu nomine de usator",
        "uploadstash-errclear": "Le radimento del files ha fallite.",
        "uploadstash-refresh": "Refrescar le lista de files",
        "uploadstash-thumbnail": "vider miniatura",
+       "uploadstash-exception": "Impossibile immagazinar le incargamento in le reserva ($1): \"$2\".",
        "invalid-chunk-offset": "Position de segmento invalide",
        "img-auth-accessdenied": "Accesso refusate",
        "img-auth-nopathinfo": "PATH_INFO manca.\nLe servitor non ha essite configurate pro passar iste information.\nIllo pote esser basate super CGI e non pote supportar img_auth.\nVide https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "protect_expiry_invalid": "Le tempore de expiration es invalide.",
        "protect_expiry_old": "Le tempore de expiration es in le passato.",
        "protect-unchain-permissions": "Disblocar ulterior optiones de protection",
-       "protect-text": "In basso tu pote vider e modificar le nivello de protection del pagina '''$1'''.",
-       "protect-locked-blocked": "Tu non pote cambiar le nivellos de protection durante que tu es blocate.\nEcce le configurationes actual del pagina '''$1''':",
-       "protect-locked-dblock": "Le nivellos de protection non pote esser cambiate proque es active un blocada del base de datos.\nEcce le configurationes actual del pagina '''$1''':",
+       "protect-text": "Hic tu pote vider e cambiar le nivello de protection del pagina <strong>$1</strong>.",
+       "protect-locked-blocked": "Tu non pote cambiar le nivellos de protection durante que tu es blocate.\nEcce le configuration actual del pagina <strong>$1</strong>:",
+       "protect-locked-dblock": "Le nivellos de protection non pote esser cambiate perque le base de datos es blocate.\nEcce le configuration actual del pagina <strong>$1</strong>:",
        "protect-locked-access": "Tu conto non ha le permission de cambiar le nivellos de protection de paginas.\nEcce le configurationes actual del pagina '''$1''':",
        "protect-cascadeon": "Iste pagina es actualmente protegite proque illo es transcludite in le sequente {{PLURAL:$1|pagina, le qual|paginas, le quales}} ha activate le protection in cascada.\nCambiamentos in le nivello de protection de iste pagina non influentia le protection in cascada.",
        "protect-default": "Permitter a tote le usatores",
        "undeletehistorynoadmin": "Iste pagina ha essite delite.\nLe motivo del deletion se monstra in le summario infra, con le detalios del usatores que habeva modificate iste pagina ante le deletion.\nLe texto complete de iste versiones delite es solmente disponibile al administratores.",
        "undelete-revision": "Version delite de $1 (facite le $4 a $5) per $3:",
        "undeleterevision-missing": "Version invalide o mancante.\nEs possibile que le adresse URL es invalide, o que le version ha essite restaurate o eliminate del archivo.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Un version|$1 versiones}} non poteva esser restaurate, perque {{PLURAL:$1|su|lor}} <code>rev_id</code> esseva jam in uso.",
        "undelete-nodiff": "Nulle version precedente trovate.",
        "undeletebtn": "Restaurar",
        "undeletelink": "vider/restaurar",
        "undeletecomment": "Motivo:",
        "undeletedrevisions": "{{PLURAL:$1|1 version|$1 versiones}} restaurate",
        "undeletedrevisions-files": "{{PLURAL:$1|1 version|$1 versiones}} e {{PLURAL:$2|1 file|$2 files}} restaurate",
-       "undeletedfiles": "$1 {{PLURAL:$1|archivo|archivos}} restaurate",
-       "cannotundelete": "Le restauration ha fallite:\n$1",
+       "undeletedfiles": "$1 {{PLURAL:$1|file|files}} restaurate",
+       "cannotundelete": "Le restauration ha partial- o totalmente fallite:\n$1",
        "undeletedpage": "'''$1 ha essite restaurate'''\n\nConsulta le [[Special:Log/delete|registro de deletiones]] pro un lista de deletiones e restaurationes recente.",
        "undelete-header": "Vide [[Special:Log/delete|le registro de deletiones]] pro un lista de paginas recentemente delite.",
        "undelete-search-title": "Cercar in paginas delite",
        "anoncontribs": "Contributiones",
        "contribsub2": "Pro {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Le conto de usator \"$1\" non es registrate.",
-       "nocontribs": "Necun modification ha essite trovate secundo iste criterios.",
+       "nocontribs": "Nulle modification correspondente a iste criterios ha essite trovate.",
        "uctop": "(ultime)",
        "month": "A partir del mense (e anterior):",
        "year": "A partir del anno (e anterior):",
        "sp-contributions-newbies-sub": "Pro nove contos",
        "sp-contributions-newbies-title": "Contributiones de nove contos de usator",
        "sp-contributions-blocklog": "Registro de blocadas",
-       "sp-contributions-suppresslog": "contributiones supprimite de usatores",
-       "sp-contributions-deleted": "contributiones delite de usatores",
+       "sp-contributions-suppresslog": "contributiones supprimite del {{GENDER:$1|usator}}",
+       "sp-contributions-deleted": "contributiones delite del {{GENDER:$1|usator}}",
        "sp-contributions-uploads": "incargamentos",
        "sp-contributions-logs": "registros",
        "sp-contributions-talk": "discussion",
        "ipb-blocklist": "Vider blocadas existente",
        "ipb-blocklist-contribs": "Contributiones de {{GENDER:$1|$1}}",
        "ipb-blocklist-duration-left": "$1 restante",
-       "unblockip": "Disblocar adresse IP",
-       "unblockiptext": "Usa le formulario infra pro restaurar le accesso de scriptura\na un adresse IP blocate previemente.",
+       "unblockip": "Disblocar usator",
+       "unblockiptext": "Usa le formulario infra pro restaurar le accesso de scriptura a un adresse IP o nomine de usator blocate previemente.",
        "ipusubmit": "Cancellar iste blocada",
-       "unblocked": "[[User:$1|$1]] ha essite disblocate",
+       "unblocked": "[[User:$1|$1]] ha essite disblocate.",
        "unblocked-range": "$1 ha essite disblocate",
-       "unblocked-id": "Le blocada $1 ha essite eliminate",
+       "unblocked-id": "Le blocada $1 ha essite removite.",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] ha essite disblocate.",
        "blocklist": "Usatores blocate",
        "ipblocklist": "Usatores blocate",
        "locknoconfirm": "Tu non ha marcate le quadrato de confirmation.",
        "lockdbsuccesssub": "Base de datos blocate con successo",
        "unlockdbsuccesssub": "Base de datos disblocate con successo",
-       "lockdbsuccesstext": "Le base de datos de {{SITENAME}} ha essite blocate.\n<br />Rememora te de disblocar lo post completar tu mantenentia.",
-       "unlockdbsuccesstext": "Le base de datos de {{SITENAME}} ha essite disblocate.",
+       "lockdbsuccesstext": "Le base de datos ha essite blocate.<br />\nNon oblida de [[Special:UnlockDB|disblocar lo]] post haber terminate le mantenentia.",
+       "unlockdbsuccesstext": "Le base de datos ha essite disblocate.",
        "lockfilenotwritable": "Impossibile scriber al file de blocada del base de datos.\nPro blocar o disblocar le base de datos, le servitor web debe poter scriber a iste file.",
        "databaselocked": "Le base de datos es jam blocate.",
        "databasenotlocked": "Le base de datos non es blocate.",
        "movenologintext": "Tu debe esser un usator registrate e [[Special:UserLogin|aperir un session]] pro poter renominar un pagina.",
        "movenotallowed": "Tu non ha le permission de renominar paginas.",
        "movenotallowedfile": "Tu non ha le permission de renominar files.",
-       "cant-move-user-page": "Tu non ha le permission de renominar paginas principal de usatores.",
+       "cant-move-user-page": "Tu non ha le permission de renominar paginas de usator (excepte subpaginas).",
        "cant-move-to-user-page": "Tu non ha le permission de renominar un pagina verso un pagina de usator (excepte un subpagina de usator).",
        "cant-move-category-page": "Tu non ha le permission de renominar paginas de categoria.",
        "cant-move-to-category-page": "Tu non ha le permission de renominar un pagina in un pagina de categoria.",
        "table_pager_empty": "Nulle resultato",
        "autosumm-blank": "Pagina vacuate",
        "autosumm-replace": "Contento reimplaciate per '$1'",
-       "autoredircomment": "Redirection verso [[$1]]",
+       "autoredircomment": "Pagina redirigite verso [[$1]]",
        "autosumm-new": "Pagina create con '$1'",
        "autosumm-newblank": "Pagina vacue create",
        "lag-warn-normal": "Le modificationes plus nove que $1 {{PLURAL:$1|secunda|secundas}} possibilemente non se revela in iste lista.",
index 1e7af01..bc271bd 100644 (file)
@@ -47,7 +47,8 @@
                        "Arief",
                        "Nemo bis",
                        "Mbrt",
-                       "Beeyan"
+                       "Beeyan",
+                       "Bonaditya"
                ]
        },
        "tog-underline": "Garis bawahi pranala:",
        "passwordreset-emailelement": "Nama pengguna: \n$1\n\nSandi sementara: \n$2",
        "passwordreset-emailsentemail": "Jika alamat surel ini berkaitan dengan akun Anda, maka surel untuk menyetel ulang kata sandi akan dikirim.",
        "passwordreset-emailsentusername": "Jika ada alamat surel yang berkaitan dengan nama pengguna ini, maka surel untuk menyetel ulang kata sandi akan dikirim.",
-       "passwordreset-emailsent-capture": "Surel setel ulang kata sandi telah dikirim, yang ditampilkan di bawah.",
-       "passwordreset-emailerror-capture": "Surel setel ulang kata sandi telah dibuat, yang ditampilkan di bawah, namun pengiriman pada {{GENDER:$2|pengguna}} gagal: $1",
        "passwordreset-emailsent-capture2": "Pemulihan kata sandi {{PLURAL:$1|surel|surel}} telah dikirim. {{PLURAL:$1|Nama pengguna dan kata sandi|Daftar nama pengguna dan kata sandi}} ditampilkan di bawah.",
        "passwordreset-emailerror-capture2": "Pengiriman surel kepada {{GENDER:$2|pengguna}} gagal: $1 {{PLURAL:$3|Nama pengguna dan kata sandi|Daftar nama pengguna dan kata sandi}} ditampilkan di bawah.",
        "passwordreset-nocaller": "Pemanggil harus diberikan",
        "passwordreset-nodata": "Nama pengguna ataupun alamat surel tidak diberikan",
        "changeemail": "Ubah atau hapus alamat surel",
        "changeemail-header": "Lengkapi formulir ini untuk mengubah alamat surel Anda. Jika Anda ingin menghapus seluruh alamat surel yang berkaitan dengan akun Anda, kosongkan alamat surel ketika mengirim formulir.",
-       "changeemail-passwordrequired": "Anda diharuskan memasukkan kata sandi untuk mengonfirmasikan perubahan ini.",
        "changeemail-no-info": "Anda harus masuk log untuk mengakses halaman ini secara langsung.",
        "changeemail-oldemail": "Alamat surel saat ini:",
        "changeemail-newemail": "Alamat surel baru:",
        "undo-nochange": "Suntingan ini nampaknya telah dibatalkan.",
        "undo-summary": "Membalikkan revisi $1 oleh [[Special:Contributions/$2|$2]] ([[User talk:$2|bicara]])",
        "undo-summary-username-hidden": "Batalkan revisi $1 oleh seorang pengguna tersembunyi",
-       "cantcreateaccounttitle": "Akun tak dapat dibuat",
        "cantcreateaccount-text": "Pembuatan akun dari alamat IP ini (<strong>$1</strong>) telah diblokir oleh [[User:$3|$3]].\n\nAlasan yang diberikan oleh $3 adalah ''$2''",
        "cantcreateaccount-range-text": "Pembuatan akun dari alamat IP dalam rentang <strong>$1</strong>, yang mencakup alamat IP anda (<strong>$4</strong>), telah diblokir oleh [[User:$3|$3]].\n\nAlasan yang diberikan oleh  $3  adalah <em>$2</em>",
        "viewpagelogs": "Lihat log halaman ini",
        "mw-widgets-dateinput-placeholder-month": "TTTT-BB",
        "mw-widgets-titleinput-description-new-page": "halaman belum ada",
        "mw-widgets-titleinput-description-redirect": "mengalihkan ke $1",
-       "api-error-blacklisted": "Pilih judul lain yang deskriptif",
        "sessionmanager-tie": "Tidak dapat menggabungkan banyak jenis otentikasi permintaan: $1.",
        "sessionprovider-generic": "sesi $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesi berdasarkan kuki",
index 8048a84..a8fbc04 100644 (file)
        "passwordreset-emailelement": "Notandanafn: \n$1\n\nBráðabirgðalykilorð: \n$2",
        "passwordreset-emailsentemail": "Ef þetta netfang er skráð fyrir aðganginum þínum þá hefur töluvpóstur verið sendur til að endursetja lykilorðið.",
        "passwordreset-emailsentusername": "Ef eitthvað netfang er skráð fyrir aðganginum þínum, þá mun verða sendur töluvpóstur til að endursetja lykilorðið.",
-       "passwordreset-emailsent-capture": "Tölvupóstur til að endursetja lykilorðið hefur verið sendur í tölvupósti, sem er sýndur hér fyrir neðan.",
-       "passwordreset-emailerror-capture": "Tölvupóstur til að endursetja lykilorðið var búinn til, sem er sýndur hér fyrir neðan, en ekki tókst að senda hana til {{GENDER:$2|notandans}}: $1",
        "changeemail": "Breyta eða fjarlægja netfang",
        "changeemail-header": "Fylltu út þetta eyðublað til að breyta netfanginu þínu. Ef þú vilt fjarlægja tengingu allra netfanga frá aðganginum þínum skildu þá netfangs reitinn eftir tóman.",
-       "changeemail-passwordrequired": "Þú verður að setja inn lykilorðið þitt til að staðfesta þessa breytingu.",
        "changeemail-no-info": "Þú verður að vera skráð(ur) inn til að hafa aðgang að þessari síðu.",
        "changeemail-oldemail": "Núverandi netfang:",
        "changeemail-newemail": "Nýtt netfang:",
        "watchthis": "Vakta þessa síðu",
        "savearticle": "Vista síðu",
        "publishpage": "Gefa út síðu",
+       "publishchanges": "Gefa út breytingar",
        "preview": "Forskoða",
        "showpreview": "Forskoða",
        "showdiff": "Sýna breytingar",
+       "blankarticle": "<strong>Viðvörun:</strong> Síðan sem þú ert að búa til er tóm.\nEf þú smellir aftur á \"{{int:savearticle}}\", verður síðan búin til án innihalds.",
        "anoneditwarning": "<strong>Viðvörun:</strong> Þú ert ekki innskráð(ur). Vistfang þitt verður sýnt opinberlega ef þú gerir einhverjar breytingar. Ef þú <strong>[$1 skráir þig inn]</strong> eða <strong>[$2 stofnar aðgang]</strong> munu breytingarnar þínar vera tengdar við notandanafn þitt, ásamt öðrum kostum.",
        "anonpreviewwarning": "Þú ert ekki innskráð(ur). Vistfang þitt skráist í breytingaskrá síðunnar.",
        "missingsummary": "'''Áminning:''' Þú hefur ekki skrifað breytingarágrip.\nEf þú smellir á Vista aftur, verður breyting þín vistuð án þess.",
        "permissionserrorstext-withaction": "Þú hefur ekki réttindi til að $2, af eftirfarandi {{PLURAL:$1|ástæðu|ástæðum}}:",
        "recreate-moveddeleted-warn": "'''Viðvörun: Þú ert að endurskapa síðu sem áður hefur verið eytt.'''\n\nAthuga skal hvort viðeigandi sé að gera þessa síðu.\nEyðingarskrá og flutningaskrá fyrir þessa síðu eru útvegaðar hér til þæginda:",
        "moveddeleted-notice": "Þessari síðu hefur verið eytt.\nEyðingaskrá og flutningaskrá síðunnar eru gefnar fyrir neðan til tilvísunar.",
+       "moveddeleted-notice-recent": "Því miður var þessari síðu eytt nýlega (innan síðustu 24 tímana).\nEyðingar og færsluskráin fyrir síðuna eru gefnar hér fyrir neðan til glöggvunar.",
        "log-fulllog": "Skoða alla aðgerðaskrána",
        "edit-hook-aborted": "Breyting síðu stöðvuð af viðbótarkrók (extension hook).\nEngin skýring gefin.",
        "edit-gone-missing": "Gat ekki uppfært síðu.\nSvo virðist sem henni hafi verið eytt.",
        "content-model-text": "hreinn texti",
        "content-model-javascript": "JavaScript",
        "content-model-css": "CSS",
+       "content-json-empty-object": "Tómur hlutur",
+       "content-json-empty-array": "Tómt fylki",
        "duplicate-args-category": "Síður sem nota tvíteknar breytur við ítengingu sniðmáts",
        "expensive-parserfunction-warning": "'''Viðvörun:''' Þessi síða inniheldur of mörg vinnslufrek aðgerðar þáttunar köll.\n\nHún ætti að innihalda minna en $2 {{PLURAL:$2|kall|köll}}, en {{PLURAL:$1|er nú $1 kall|eru nú $1 köll}}.",
        "expensive-parserfunction-category": "Síður með of mörg vinnslufrek aðgerðar þáttunar köll",
        "undo-nochange": "Breytingin virðist þegar hafa verið tekin til baka.",
        "undo-summary": "Tek aftur breytingu $1 frá [[Special:Contributions/$2|$2]] ([[User talk:$2|spjall]])",
        "undo-summary-username-hidden": "Afturkalla breytingu $1 eftir faldan notanda",
-       "cantcreateaccounttitle": "Ekki hægt að búa til aðgang",
        "cantcreateaccount-text": "Aðgangsgerð fyrir þetta vistfang ('''$1''') hefur verið bannað af [[User:$3|$3]].\n\nÁstæðan sem $3 gaf fyrir því er ''$2''",
        "cantcreateaccount-range-text": "Aðgangsgerð frá visföngunum „$1”, sem innihalda vistfang þitt („$4”) hefur verið bönnuð af [[User:$3|$3]].\n\nÁstæðan sem $3 gaf fyrir því er „$2”",
        "viewpagelogs": "Sýna aðgerðir varðandi þessa síðu",
        "revdelete-no-file": "Umbeðin skrá er ekki til.",
        "revdelete-show-file-confirm": "Ertu viss um að þú viljir sjá eydda breytingu af síðunni \"<nowiki>$1</nowiki>\" frá $2 $3?",
        "revdelete-show-file-submit": "Já",
+       "revdelete-selected-text": "{{PLURAL:$1|Valin útgáfa|Valdar útgáfur}} [[:$2]]:",
+       "revdelete-selected-file": "{{PLURAL:$1|Valin útgáfa skráarinnar|Valdar útgáfur skráarinnar}} [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Valin aðgerð|Valdar aðgerðir}}:",
+       "revdelete-text-text": "Eyddar breytingar munu áfram birtast í breytingarsögu, en hlutar hennar verða óaðgengileg almenningi.",
+       "revdelete-text-file": "Eyddar breytingar skráar munu áfram birtast í breytingarsögu, en hlutar hennar verða óaðgengileg almenningi.",
+       "revdelete-text-others": "Aðrir stjórnendur munu enn sjá falda efnið og geta tekið aftur eyðinguna, nema frekari takmarkanir séu í notkun.",
        "revdelete-confirm": "Staðfestu að þú viljir gera þetta, að þú skiljir afleiðingarnar og að þú sért að gera þetta í samræmi við  [[{{MediaWiki:Policy-url}}|samþykktir]].",
        "revdelete-suppress-text": "Bælingu á '''eingöngu''' að nota í eftirfarandi tilfellum:\n* Mögulegar ærumleiðandi upplýsingar\n* Óviðeigandi persónulegar upplýsingar\n*: ''heimilisfang, símanúmer, kennitala, osfrv.''",
        "revdelete-legend": "Setja sjáanlegar hamlanir",
        "search-category": "(flokkur $1)",
        "search-file-match": "(passar við innihald skráa)",
        "search-suggest": "Varstu að leita að: $1",
+       "search-rewritten": "Sýni niðurstöður $1. Leita í staðinn að $2.",
        "search-interwiki-caption": "Systurverkefni",
        "search-interwiki-default": "Útkomur frá $1:",
        "search-interwiki-more": "(fleiri)",
        "showingresultsinrange": "Sýni allt að <strong>$1</strong> {{PLURAL:$1|niðurstöðu|niðurstöður}} á bilinu <strong>$2</strong> til <strong>$3</strong>.",
        "search-showingresults": "{{PLURAL:$4|Niðurstaða|Niðurstöður}} <strong>$1-$2</strong> af <strong>$3</strong>",
        "search-nonefound": "Engar niðurstöður pössuðu við fyrirspurnina.",
+       "search-nonefound-thiswiki": "Engar niðurstöður fundust við fyrirspurninni á þessu vefsvæði.",
        "powersearch-legend": "Ítarlegri leit",
        "powersearch-ns": "Leita í nafnrýmum:",
        "powersearch-togglelabel": "Athuga:",
        "undeletedrevisions": "$1 {{PLURAL:$1|breyting endurvakin|breytingar endurvaktar}}",
        "undeletedrevisions-files": "$1 {{PLURAL:$1|breyting|breytingar}} og $2 {{PLURAL:$2|skrá|skrár}} endurvaktar",
        "undeletedfiles": "$1 {{PLURAL:$1|skrá endurvakin|skrár endurvaktar}}",
-       "cannotundelete": "Ekki var hægt að afturkalla eyðingu.\n$1",
+       "cannotundelete": "Afturköllun eyðingar mistókst að hluta eða í heild: \n$1",
        "undeletedpage": "'''$1 var endurvakin'''\n\nSkoðaðu [[Special:Log/delete|eyðingaskrána]] til að skoða eyðingar og endurvakningar.",
        "undelete-header": "Sjá [[Special:Log/delete|eyðingarskrá]] fyrir síður sem nýlega hefur verið eytt.",
        "undelete-search-title": "Leita í eyddum síðum",
        "sp-contributions-newbies-sub": "Fyrir nýliða",
        "sp-contributions-newbies-title": "Breytingar nýrra notenda",
        "sp-contributions-blocklog": "fyrri bönn",
-       "sp-contributions-suppresslog": "bæld framlög notanda",
-       "sp-contributions-deleted": "eyddar breytingar notanda",
+       "sp-contributions-suppresslog": "bæld framlög {{GENDER:$1|notanda}}",
+       "sp-contributions-deleted": "eyddar breytingar {{GENDER:$1|notanda}}",
        "sp-contributions-uploads": "innsendingar",
        "sp-contributions-logs": "aðgerðaskrá",
        "sp-contributions-talk": "spjall",
index 7fcde5c..b807488 100644 (file)
        "grant-group-high-volume": "Esegue azioni massive",
        "grant-group-customization": "Personalizzazione e preferenze",
        "grant-group-administration": "Esegue azioni amministrative",
+       "grant-group-private-information": "Accede ai dati privati su di te",
        "grant-group-other": "Attività varie",
        "grant-blockusers": "Blocca e sblocca utenti",
        "grant-createaccount": "Crea un'utenza",
        "grant-highvolume": "Modifiche massive",
        "grant-oversight": "Nasconde utenti e sopprime le versioni",
        "grant-patrol": "Segna le modifiche alle pagine come verificate",
+       "grant-privateinfo": "Accede a informazioni private",
        "grant-protect": "Protegge e sprotegge pagine",
        "grant-rollback": "Rollback delle modifiche alle pagine",
        "grant-sendemail": "Invia email ad altri utenti",
        "undeletehistorynoadmin": "Questa pagina è stata cancellata.\nIl motivo della cancellazione è mostrato qui sotto, assieme ai dettagli dell'utente che ha modificato questa pagina prima della cancellazione.\nIl testo contenuto nelle versioni cancellate è disponibile solo agli amministratori.",
        "undelete-revision": "Versione cancellata della pagina $1, inserita il $4 alle $5 da $3:",
        "undeleterevision-missing": "Versione errata o mancante. Il collegamento è errato oppure la versione è stata già ripristinata o eliminata dall'archivio.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Una versione non può essere ripristinata|$1 versioni non possono essere ripristinate}}, poiché {{PLURAL:$1|il suo|i loro}} <code>rev_id</code> {{PLURAL:$1|è già utilizzato|sono già utilizzati}}.",
        "undelete-nodiff": "Non è stata trovata nessuna versione precedente.",
        "undeletebtn": "Ripristina",
        "undeletelink": "visualizza/ripristina",
        "undeletedrevisions": "{{PLURAL:$1|Una versione recuperata|$1 versioni recuperate}}",
        "undeletedrevisions-files": "{{PLURAL:$1|Una versione|$1 versioni}} e $2 file recuperati",
        "undeletedfiles": "{{PLURAL:$1|Un file recuperato|$1 file recuperati}}",
-       "cannotundelete": "Ripristino non riuscito:\n$1",
+       "cannotundelete": "Alcuni o tutti i ripristini non riusciti:\n$1",
        "undeletedpage": "'''La pagina $1 è stata recuperata'''\n\nConsulta il [[Special:Log/delete|registro delle cancellazioni]] per vedere le cancellazioni e i recuperi più recenti.",
        "undelete-header": "Consulta il [[Special:Log/delete|registro delle cancellazioni]] per vedere le cancellazioni più recenti.",
        "undelete-search-title": "Ricerca nelle pagine cancellate",
        "sp-contributions-newbies-sub": "Per i nuovi utenti",
        "sp-contributions-newbies-title": "Contributi dei nuovi utenti",
        "sp-contributions-blocklog": "blocchi",
-       "sp-contributions-suppresslog": "contributi utente soppressi",
-       "sp-contributions-deleted": "contributi utente cancellati",
+       "sp-contributions-suppresslog": "contributi {{GENDER:$1|utente}} soppressi",
+       "sp-contributions-deleted": "contributi {{GENDER:$1|utente}} cancellati",
        "sp-contributions-uploads": "file caricati",
        "sp-contributions-logs": "registri",
        "sp-contributions-talk": "discussione",
index ec7a8a3..321c5d4 100644 (file)
        "undeletehistorynoadmin": "このページは削除されています。\n削除の理由は、削除前にこのページを編集していた利用者の詳細情報と共に、以下に表示されています。\n管理者以外の利用者には、削除された各版の本文への制限がかけられています。",
        "undelete-revision": "削除されたページ $1 の $4 $5 時点での $3 による版:",
        "undeleterevision-missing": "無効または存在しない版です。\n間違ったリンクをたどったか、この版は既に復元されたか、もしくは保存版から除去された可能性があります。",
+       "undeleterevision-duplicate-revid": "<code>rev_id</code> は既に使用されているため、{{PLURAL:$1|1件の版|$1件の版}}を復元できませんでした。",
        "undelete-nodiff": "これより前の版はありません。",
        "undeletebtn": "復元",
        "undeletelink": "閲覧/復元",
        "undeletedrevisions": "{{PLURAL:$1|$1版}}を復元しました",
        "undeletedrevisions-files": "{{PLURAL:$1|$1版}}と{{PLURAL:$2|$2ファイル}}を復元しました",
        "undeletedfiles": "{{PLURAL:$1|$1ファイル}}を復元しました",
-       "cannotundelete": "復元に失敗しました:\n$1",
+       "cannotundelete": "復元に一部またはすべて失敗しました:\n$1",
        "undeletedpage": "<strong>$1を復元しました。</strong>\n\n最近の削除と復元の記録については[[Special:Log/delete|削除記録]]を参照してください。",
        "undelete-header": "最近削除されたページは[[Special:Log/delete|削除記録]]で確認できます。",
        "undelete-search-title": "削除されたページの検索",
        "sp-contributions-newbies-sub": "新規利用者のみ",
        "sp-contributions-newbies-title": "新規利用者の投稿記録",
        "sp-contributions-blocklog": "ブロック記録",
-       "sp-contributions-suppresslog": "利用者の秘匿された投稿",
-       "sp-contributions-deleted": "削除された投稿の一覧",
+       "sp-contributions-suppresslog": "{{GENDER:$1|利用者}}の秘匿された投稿",
+       "sp-contributions-deleted": "{{GENDER:$1|利用者}}の削除された投稿の一覧",
        "sp-contributions-uploads": "アップロード",
        "sp-contributions-logs": "記録",
        "sp-contributions-talk": "トーク",
index f3a6409..2402224 100644 (file)
        "listfiles_thumb": "Gambar mini",
        "listfiles_date": "Tanggal",
        "listfiles_name": "Jeneng",
-       "listfiles_user": "Panganggo",
+       "listfiles_user": "Naraguna",
        "listfiles_size": "Ukuran (bita)",
        "listfiles_description": "Dèskripsi",
        "listfiles_count": "Vèrsi",
        "filehist-thumb": "Gambar cilik",
        "filehist-thumbtext": "Gambar cilik kanggo owahan $1",
        "filehist-nothumb": "Ora ana miniatur",
-       "filehist-user": "Panganggo",
+       "filehist-user": "Naraguna",
        "filehist-dimensions": "Alang ujur",
        "filehist-filesize": "Gedhené berkas",
        "filehist-comment": "Tanggapan",
        "blocklogpage": "Log pamblokiran",
        "blocklog-showlog": "Panganggo iki wis tau diblokir sakdurungé.\nLog blokiran sumadhiya nèng ngisor kanggo rujukan:",
        "blocklog-showsuppresslog": "Panganggo iki wis tau diblokir lan didhelikaké sakdurungé.\nLog brèdèlan sumadhiya nèng ngisor kanggo rujukan:",
-       "blocklogentry": "mblokir \"[[$1]]\" dipun watesi wekdalipun $2 $3",
-       "reblock-logentry": "Ngowahi sèting pamblokiran [[$1]] kanthi wektu daluwarsa $2 $3",
+       "blocklogentry": "mblokir [[$1]] kanthi wektu kadaluwarsa $2 $3",
+       "reblock-logentry": "ngowah setèlan blokir tumrap [[$1]] kanthi wektu kadaluwarsa $2 $3",
        "blocklogtext": "Ing ngisor iki kapacak log pamblokiran lan panjabelan blokir panganggo.\nAlamat IP sing diblokir sacara otomatis ora ana ing daftar iki.\nMangga mirsani [[Special:BlockList|daftar panganggo sing diblokir]] kanggo daftar blokir pungkasan.",
        "unblocklogentry": "njabel blokir \"$1\"",
        "block-log-flags-anononly": "namung panganggo anonim waé",
        "block-log-flags-hiddenname": "jeneng panganggo didhelikaké",
        "range_block_disabled": "Fungsi pamblokir blok IP kanggo para opsis dipatèni.",
        "ipb_expiry_invalid": "Wektu kadaluwarsa ora absah.",
+       "ipb_expiry_old": "Wektu kadaluwarsa ana ing nguni.",
        "ipb_expiry_temp": "Pamblokiran tumrap jeneng panganggo sing didhelikaké kudu permanèn.",
        "ipb_hide_invalid": "Ora bisa ndhelikaké akun iki; manawa wis kakèhan suntingan.",
        "ipb_already_blocked": "\"$1\" wis diblokir",
        "revdelete-uname-unhid": "jeneng panganggo dituduhaké",
        "revdelete-restricted": "rèstriksi ditrapaké marang para opsis",
        "revdelete-unrestricted": "rèstriksi marang para opsis dijabel",
+       "logentry-block-block": "$1 {{GENDER:$2|mblokir}} {{GENDER:$4|$3}} kanthi wektu kadaluwarsa $5 $6",
+       "logentry-block-reblock": "$1 {{GENDER:$2|ngowah}} setèlan blokir tumrap {{GENDER:$4|$3}} kanthi wektu kadaluwarsa $5 $6",
+       "logentry-suppress-block": "$1 {{GENDER:$2|mblokir}} {{GENDER:$4|$3}} kanthi wektu kadaluwarsa $5 $6",
+       "logentry-suppress-reblock": "$1 {{GENDER:$2|ngowah}} setèlan blokir tumrap {{GENDER:$4|$3}} kanthi wektu kadaluwarsa $5 $6",
        "logentry-move-move": "$1 {{GENDER:$2|ngalih}} kaca $3 nyang $4",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|mindhahaké}} kaca $3 nèng $4 tanpa ninggalaké pangalihan",
        "logentry-move-move_redir": "$1 {{GENDER:$2|mindhahaké}} kaca $3 nèng $4 nindesi pangalihan liyane",
index c634c56..cc3b52e 100644 (file)
        "sp-contributions-username": "IP-мекенжайы немесе қатысушы аты:",
        "sp-contributions-toponly": "Өңдемелердің тек соңғы нұсқаларын көрсету",
        "sp-contributions-newonly": "Бет бастау өңдемелерін ғана көрсету",
+       "sp-contributions-hideminor": "Шағын өңдемелерді жасыру",
        "sp-contributions-submit": "Іздеу",
        "whatlinkshere": "Мұнда сілтейтін беттер",
        "whatlinkshere-title": "$1 дегенге сілтейтін беттер",
index db93552..8552d01 100644 (file)
@@ -75,7 +75,7 @@
        "tog-numberheadings": "자동으로 머릿글 번호 매기기",
        "tog-showtoolbar": "편집 도구 모음 보이기",
        "tog-editondblclick": "더블 클릭으로 문서 편집하기",
-       "tog-editsectiononrightclick": "제목을 오른쪽 클릭해서 문단 편집하기 활성화",
+       "tog-editsectiononrightclick": "문단 제목을 오른쪽 클릭해서 문단 편집하기 활성화",
        "tog-watchcreations": "내가 만든 문서와 내가 올린 파일을 주시문서 목록에 추가",
        "tog-watchdefault": "내가 편집한 문서와 파일을 주시문서 목록에 추가",
        "tog-watchmoves": "내가 이동한 문서와 파일을 주시문서 목록에 추가",
@@ -93,7 +93,7 @@
        "tog-oldsig": "현재 서명:",
        "tog-fancysig": "서명을 위키텍스트로 취급 (자동으로 링크를 걸지 않음)",
        "tog-uselivepreview": "실시간 미리 보기 사용하기",
-       "tog-forceeditsummary": "편집 요약을 쓰지 않았을 때 물어보기",
+       "tog-forceeditsummary": "í\8e¸ì§\91 ì\9a\94ì\95½ì\9d\84 ì\93°ì§\80 ì\95\8aì\95\98ì\9d\84 ë\95\8c ë\82´ê²\8c ë¬¼ì\96´ë³´ê¸°",
        "tog-watchlisthideown": "주시문서 목록에서 내 편집을 숨기기",
        "tog-watchlisthidebots": "주시문서 목록에서 봇 편집을 숨기기",
        "tog-watchlisthideminor": "주시문서 목록에서 사소한 편집을 숨기기",
        "tog-diffonly": "편집 차이를 비교할 때 문서 내용을 보지 않기",
        "tog-showhiddencats": "숨은 분류 보이기",
        "tog-norollbackdiff": "되돌리기 후 차이를 보지 않기",
-       "tog-useeditwarning": "바꾼 내용을 저장하지 않고 편집 페이지를 벗어날 때 알림",
+       "tog-useeditwarning": "바꾼 내용을 저장하지 않고 편집 페이지를 벗어날 때 내게 경고하기",
        "tog-prefershttps": "로그인할 때 항상 보안 연결 사용",
        "underline-always": "항상",
        "underline-never": "항상 치지 않기",
        "underline-default": "스킨 또는 브라우저 기본값",
-       "editfont-style": "편집 영역의 글꼴:",
+       "editfont-style": "편집 영역의 글꼴 형식:",
        "editfont-default": "브라우저 기본값",
        "editfont-monospace": "고정폭 글꼴",
        "editfont-sansserif": "산세리프 글꼴",
        "userlogin-resetlink": "로그인 정보를 잊으셨나요?",
        "userlogin-resetpassword-link": "비밀번호를 잊으셨나요?",
        "userlogin-helplink2": "로그인에 대한 도움말",
-       "userlogin-loggedin": "이미 {{GENDER:$1|$1}} 사용자로 로그인되어 있습니다.\n다른 사용자로 로그인하려면 아래의 양식을 사용하세요.",
+       "userlogin-loggedin": "이미 {{GENDER:$1|$1}}님으로 로그인되어 있습니다.\n다른 사용자로 로그인하려면 아래의 양식을 사용하세요.",
        "userlogin-reauth": "당신이 {{GENDER:$1|$1}}임을 검증하려면 다시 로그인해야 합니다.",
        "userlogin-createanother": "다른 계정 만들기",
        "createacct-emailrequired": "이메일 주소",
        "createacct-loginerror": "계정 만들기는 성공했으나 자동으로 로그인하지 못했습니다. [[Special:UserLogin|수동으로 로그인]]해 주십시오.",
        "noname": "사용자 계정 이름이 올바르지 않습니다.",
        "loginsuccesstitle": "로그인함",
-       "loginsuccess": "<strong>{{SITENAME}}에 \"$1\" 계정으로 로그인했습니다.</strong>",
+       "loginsuccess": "<strong>{{SITENAME}}에 \"$1\"으로 로그인했습니다.</strong>",
        "nosuchuser": "이름이 \"$1\"인 사용자는 없습니다.\n사용자 이름은 대소문자를 구별합니다.\n철자가 맞는지 확인해주세요. [[Special:CreateAccount|새 계정을 만들 수도 있습니다]].",
        "nosuchusershort": "이름이 \"$1\"인 사용자는 없습니다.\n철자가 맞는지 확인하세요.",
        "nouserspecified": "사용자 계정 이름을 입력하지 않았습니다.",
        "acct_creation_throttle_hit": "당신의 IP 주소를 이용한 방문자가 이전에 이미 {{PLURAL:$1|계정 $1개}}를 만들어, 계정 만들기 한도를 초과하였습니다.\n따라서 지금은 이 IP 주소로는 더 이상 계정을 만들 수 없습니다.",
        "emailauthenticated": "이메일 주소가 $2 $3에 인증되었습니다.",
        "emailnotauthenticated": "이메일 주소를 인증하지 않았습니다.\n이메일 확인 절차를 거치지 않으면 다음 이메일 기능을 사용할 수 없습니다.",
-       "noemailprefs": "이 기능을 사용하기 위해서는 사용자 환경 설정에서 이메일 주소를 설정해야 합니다.",
+       "noemailprefs": "이 기능을 사용하려면 사용자 환경 설정에서 이메일 주소를 지정하세요.",
        "emailconfirmlink": "이메일 주소 확인",
        "invalidemailaddress": "이메일 주소의 형식이 잘못되어 인식할 수 없습니다.\n정상적인 형식의 이메일을 입력하거나 칸을 비워 주세요.",
        "cannotchangeemail": "이 위키에서는 계정의 이메일 주소를 바꿀 수 없습니다.",
        "rev-showdeleted": "보이기",
        "revisiondelete": "판 삭제/되살리기",
        "revdelete-nooldid-title": "대상 판이 잘못되었습니다.",
-       "revdelete-nooldid-text": "이 기능을 수행할 특정 판을 제시하지 않았거나 해당 판이 없습니다. 또는 현재 판을 숨기려 하고 있을 수도 있습니다.",
+       "revdelete-nooldid-text": "이 기능을 수행할 대상 판을 지정하지 않았거나 해당 판이 존재하지 않습니다. 아니면 현재 판을 숨기려 하고 있을 수도 있습니다.",
        "revdelete-no-file": "해당 파일이 존재하지 않습니다.",
        "revdelete-show-file-confirm": "정말 \"<nowiki>$1</nowiki>\" 파일의 삭제된 $2 $3 버전을 보시겠습니까?",
        "revdelete-show-file-submit": "예",
        "search-category": "(분류 $1)",
        "search-file-match": "(내용이 일치하는 파일 있음)",
        "search-suggest": "$1 문서를 찾고 있으신가요?",
-       "search-rewritten": "$1의 결과를 보여주고 있습니다. $2 대신 검색합니다.",
+       "search-rewritten": "$1의 결과를 보여주고 있습니다. $2을(를) 대신 검색합니다.",
        "search-interwiki-caption": "자매 프로젝트",
        "search-interwiki-default": "$1로부터의 결과:",
        "search-interwiki-more": "(더 보기)",
        "search-external": "바깥 검색",
        "searchdisabled": "{{SITENAME}} 검색이 비활성화되어 있습니다.\n검색이 작동하지 않는 동안 Google을 통해 검색할 수 있습니다.\n검색 엔진의 내용은 최신이 아닐 수 있다는 점을 참고하세요.",
        "search-error": "검색하는 동안 오류가 발생했습니다: $1",
-       "preferences": "사용자 환경 설정",
+       "preferences": "환경 설정",
        "mypreferences": "환경 설정",
        "prefs-edits": "편집 수:",
        "prefsnologintext2": "사용자 환경 설정을 바꾸려면 로그인하세요.",
        "prefs-resetpass": "비밀번호 바꾸기",
        "prefs-changeemail": "이메일 주소를 바꾸거나 제거하기",
        "prefs-setemail": "이메일 주소 설정하기",
-       "prefs-email": "ì\9d´ë©\94ì\9d¼ ì\84¤ì \95",
-       "prefs-rendering": "문ì\84\9c ë³´ì\9d´ê¸°",
+       "prefs-email": "ì\9d´ë©\94ì\9d¼ ì\98µì\85\98",
+       "prefs-rendering": "보이기",
        "saveprefs": "저장",
        "restoreprefs": "(모든 부분에서) 모두 기본 설정으로 되돌리기",
        "prefs-editing": "편집",
        "recentchangesdays-max": "최대 $1{{PLURAL:$1|일}}",
        "recentchangescount": "기본으로 보여줄 편집 수:",
        "prefs-help-recentchangescount": "이 설정은 최근 바뀜, 문서 역사와 기록에 적용됩니다.",
-       "prefs-help-watchlist-token2": "내 주시문서 목록의 웹 피드의 비밀 키입니다.\n비밀 키를 알고 있는 사람은 내 주시문서 목록을 읽을 수 있으니 비밀 키를 알리지 마세요.\n필요하다면 [[Special:ResetTokens|비밀 키를 재설정할 수 있습니다]].",
+       "prefs-help-watchlist-token2": "내 주시문서 목록의 웹 피드의 비밀 키입니다.\n이 키를 알고 있는 사람은 내 주시문서 목록을 읽을 수 있으니 이 키를 공유하지 마세요.\n필요하다면 [[Special:ResetTokens|이 키를 재설정할 수 있습니다]].",
        "savedprefs": "설정을 저장했습니다.",
        "savedrights": "$1의 사용자 권한이 저장되었습니다.",
        "timezonelegend": "시간대:",
        "prefs-help-email-others": "자신의 사용자 문서나 토론 문서에 있는 이메일 보내기 링크로 다른 사용자가 연락할 수 있게 할 수도 있습니다.\n이 경우에도 이메일 주소는 다른 사용자가 연락할 때 공개되지 않습니다.",
        "prefs-help-email-required": "이메일 주소가 필요합니다.",
        "prefs-info": "기본 정보",
-       "prefs-i18n": "언어 설정",
+       "prefs-i18n": "국제화",
        "prefs-signature": "서명",
        "prefs-dateformat": "날짜 형식",
        "prefs-timeoffset": "시차 설정",
-       "prefs-advancedediting": "ì\9d¼ë°\98 ì\84¤ì \95",
+       "prefs-advancedediting": "ì\9d¼ë°\98 ì\98µì\85\98",
        "prefs-editor": "편집기",
        "prefs-preview": "미리 보기",
-       "prefs-advancedrc": "ê³ ê¸\89 ì\84¤ì \95",
-       "prefs-advancedrendering": "ê³ ê¸\89 ì\84¤ì \95",
-       "prefs-advancedsearchoptions": "ê³ ê¸\89 ì\84¤ì \95",
-       "prefs-advancedwatchlist": "ê³ ê¸\89 ì\84¤ì \95",
-       "prefs-displayrc": "보이기 설정",
-       "prefs-displaywatchlist": "보이기 설정",
+       "prefs-advancedrc": "ê³ ê¸\89 ì\98µì\85\98",
+       "prefs-advancedrendering": "ê³ ê¸\89 ì\98µì\85\98",
+       "prefs-advancedsearchoptions": "ê³ ê¸\89 ì\98µì\85\98",
+       "prefs-advancedwatchlist": "ê³ ê¸\89 ì\98µì\85\98",
+       "prefs-displayrc": "표시 설정",
+       "prefs-displaywatchlist": "표시 설정",
        "prefs-tokenwatchlist": "토큰",
        "prefs-diffs": "차이",
        "prefs-help-prefershttps": "이 사용자 환경 설정은 다음 로그인부터 적용됩니다.",
        "grant-group-high-volume": "대량의 작업 수행",
        "grant-group-customization": "사용자 최적화 및 환경 설정",
        "grant-group-administration": "관리 기능 수행",
+       "grant-group-private-information": "당신에 관한 개인 데이터 접근",
        "grant-group-other": "기타 활동",
        "grant-blockusers": "사용자 차단 또는 차단 해제",
        "grant-createaccount": "계정 만들기",
        "grant-editprotected": "보호된 문서 편집하기",
        "grant-highvolume": "대용량 편집",
        "grant-oversight": "사용자 숨기기와 판 억제",
-       "grant-patrol": "페이지 검토",
+       "grant-patrol": "페이지 변경 사항 점검",
+       "grant-privateinfo": "개인 정보 접근",
        "grant-protect": "문서 보호 및 보호 해제",
        "grant-rollback": "문서의 바뀜을 되돌리기",
        "grant-sendemail": "다른 사용자에게 이메일 보내기",
        "protectedpages-performer": "보호한 사용자",
        "protectedpages-params": "보호 변수",
        "protectedpages-reason": "이유",
-       "protectedpages-submit": "문서 보이기",
+       "protectedpages-submit": "문서 표시",
        "protectedpages-unknown-timestamp": "알 수 없음",
        "protectedpages-unknown-performer": "알 수 없는 사용자",
        "protectedtitles": "만들기 보호된 표제어 목록",
        "protectedtitles-summary": "이 페이지는 현재 만들기 보호가 설정되어 있는 문서 제목을 나열합니다. 보호된 기존 문서들의 목록을 보려면 [[{{#special:ProtectedPages}}|{{int:protectedpages}}]]을 보세요.",
        "protectedtitlesempty": "해당 조건에 맞는 만들기 금지 표제어가 없습니다.",
-       "protectedtitles-submit": "제목 보이기",
+       "protectedtitles-submit": "제목 표시",
        "listusers": "사용자 목록",
        "listusers-editsonly": "기여가 있는 사용자만 보기",
        "listusers-creationsort": "계정을 만든 날짜순으로 정렬",
        "emailccsubject": "$1에게 보낸 메시지의 복사본: $2",
        "emailsent": "이메일 보냄",
        "emailsenttext": "이메일을 보냈습니다.",
-       "emailuserfooter": "이 이메일은 {{SITENAME}}의 $1님이 $2 사용자에게 \"{{int:emailuser}}\" 기능을 통해 보냈습니다.",
+       "emailuserfooter": "이 이메일은 {{SITENAME}}의 $1님이 $2에게 \"{{int:emailuser}}\" 기능을 통해 보냈습니다.",
        "usermessage-summary": "시스템 메시지 남기기",
        "usermessage-editor": "시스템 메신저",
        "usermessage-template": "MediaWiki:UserMessage",
        "undeletehistorynoadmin": "이 문서는 삭제되었습니다.\n삭제된 이유와 삭제되기 전에 이 문서를 편집한 사용자가 아래에 나와 있습니다.\n삭제된 문서의 내용을 보려면 관리자 권한이 필요합니다.",
        "undelete-revision": "삭제된 $1 문서의 $4 $5 버전 (기여자 $3):",
        "undeleterevision-missing": "해당 판이 잘못되었거나 존재하지 않습니다.\n잘못된 링크를 따라왔거나, 특정 판이 이미 되살렸거나 데이터베이스에서 제거되었을 수도 있습니다.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|해당 판의|해당 판들의}} <code>rev_id</code>가 이미 사용 중이기 때문에 {{PLURAL:$1|한 개의 판|$1개의 판}}을 복구할 수 없습니다.",
        "undelete-nodiff": "이전의 판이 없습니다.",
        "undeletebtn": "되살리기",
        "undeletelink": "보기/되살리기",
        "undeletedrevisions": "{{PLURAL:$1|판 1개|판 $1개}}를 되살렸습니다",
        "undeletedrevisions-files": "{{PLURAL:$1|판 1개|판 $1개}}와 {{PLURAL:$2|파일 1개|파일 $2개}}를 되살렸습니다",
        "undeletedfiles": "{{PLURAL:$1|파일 1개|파일 $1개}}를 되살렸습니다",
-       "cannotundelete": "되살리는 데 실패했습니다:\n$1",
+       "cannotundelete": "일부 또는 모든 항목의 되살리기를 실패했습니다:\n$1",
        "undeletedpage": "<strong>$1 문서를 되살렸습니다.</strong>\n\n[[Special:Log/delete|삭제 기록]]에서 최근의 삭제 및 되살리기 기록을 볼 수 있습니다.",
        "undelete-header": "최근에 삭제한 문서에 대한 기록은 [[Special:Log/delete|여기]]에서 볼 수 있습니다.",
        "undelete-search-title": "삭제된 문서 검색",
        "sp-contributions-newbies-sub": "새 사용자의 기여",
        "sp-contributions-newbies-title": "새 사용자의 기여",
        "sp-contributions-blocklog": "차단 기록",
-       "sp-contributions-suppresslog": "숨겨진 사용자 기여",
-       "sp-contributions-deleted": "삭제된 사용자 기여",
+       "sp-contributions-suppresslog": "숨겨진 {{GENDER:$1|사용자}} 기여",
+       "sp-contributions-deleted": "삭제된 {{GENDER:$1|사용자}} 기여",
        "sp-contributions-uploads": "올린 파일",
        "sp-contributions-logs": "기록",
        "sp-contributions-talk": "토론",
        "pageinfo-header-edits": "편집 역사",
        "pageinfo-header-restrictions": "문서 보호",
        "pageinfo-header-properties": "문서 속성",
-       "pageinfo-display-title": "보여줄 제목",
+       "pageinfo-display-title": "표시 제목",
        "pageinfo-default-sort": "기본 정렬 키",
        "pageinfo-length": "문서 길이 (바이트)",
        "pageinfo-article-id": "문서 ID",
        "tags-edit-success": "바뀜이 적용되었습니다.",
        "tags-edit-failure": "수정 사항이 적용될 수 없습니다: $1",
        "tags-edit-nooldid-title": "대상 판이 잘못되었습니다",
-       "tags-edit-nooldid-text": "이 기능을 수행할 특정 판을 제시하지 않았거나 해당 판이 없습니다.",
+       "tags-edit-nooldid-text": "이 기능을 수행할 대상 판을 지정하지 않았거나 해당 판이 존재하지 않습니다.",
        "tags-edit-none-selected": "추가하거나 제거할 최소 하나 이상의 태그를 선택하세요.",
        "comparepages": "문서 비교",
        "compare-page1": "첫 번째 문서",
index 7896792..0d7d482 100644 (file)
        "passwordreset-emailtitle": "{{SITENAME}} сайтындагы эсеп жазуусу жөнүндөгү маалымат",
        "passwordreset-emailelement": "Колдонуучу аты: \n$1\n\nУбактылуу сырсөз: \n$2",
        "passwordreset-emailsentemail": "Сырсөздү алмаштыруу эмейлге жөнөтүлдү.",
-       "passwordreset-emailsent-capture": "Төмөндө көрсөтүлгөн эмейлге сырсөздү алмаштыруучу кат жөнөтүлдү.",
-       "passwordreset-emailerror-capture": "Төмөндө көрсөтүлгөн дарекке сырсөздү алмаштыруу кат түзүлдү,бирок аны  {{GENDER:$2|катышуучуга}} жөнөтүү оңунан чыккан жок: $1",
        "changeemail": "E-mail даректи өзгөртүү",
        "changeemail-header": "Эл. почтанын дарегин өзгөртүү",
        "changeemail-no-info": "Бул баракка түз кайрылыш үчүн, сиз системага киришиңиз керек.",
        "post-expand-template-argument-warning": "'''Эскертүү:''' Бул барак, жок дегенде, абдан чоң көлөмдүү калыптын бир жүйөсүн камтыйт жана  жайылганда өлчөмү абдан чоң болуп кетет. \nУшул сыяктуу жүйөлөр аттатылды.",
        "post-expand-template-argument-category": "Калыптардын аттатылган жүйөлөрүн камтыган барактар",
        "parser-template-loop-warning": "Калыптарда илмек бар:[[$1]]",
-       "cantcreateaccounttitle": "Эсеп жазуусун түзүү мүмкүн эмес",
        "viewpagelogs": "Бул барактын журналдарын көрүү",
        "nohistory": "Бул барактын өзгөртүүлөр тарыхы жок",
        "currentrev": "Соңку версиясы",
        "watchlisttools-view": "Тийиштүү өзгөрүүлөрдү кароо",
        "watchlisttools-edit": "Көзөмөл тизмесин кароо жана оңдоо",
        "watchlisttools-raw": "Жетиле элек көзөмөл тизмени оңдоо",
-       "signature": "[[{{ns:колдонуучу}}:$1|$2]] ([[{{ns:колдонуучу_баарлашуу}}:$1|баарлашуу]])",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|баарлашуу]])",
        "duplicate-defaultsort": "'''Эскертүү:''' \"$2\" белгиленген ылгоочу ачкыч \"$1\" мурунку белгиленген ылгоочу ачкычты жокко чыгарат.",
        "version": "Версия",
        "version-extensions": "Орнотулган кеңейтүүлөр",
index ccb5dbc..594636e 100644 (file)
        "nocookiesnew": "De Benotzerkont gouf ugeluecht, awer Dir sidd net ageloggt.\n{{SITENAME}} brauch fir dës Funktioun Cookien.\nDir hutt d'Cookien desaktivéiert.\nAktivéiert déi w.e.g. a loggt Iech da mat Ärem neie Benotzernomm a mat dem respektive Passwuert an.",
        "nocookieslogin": "{{SITENAME}} benotzt Cookië beim Umelle vun de Benotzer.\nDir hutt Cookien ausgeschalt.\nAktivéiert d'Cookien w.e.g. a versicht et nach eng Kéier.",
        "nocookiesfornew": "De Benotzerkont gouf net ugeluecht, well mir seng Quell net bestëmme konnten.\nVergewëssert Iech datt Dir Cookien zouloosst, luet dës Säit nei a probéiert nach emol.",
+       "createacct-loginerror": "De Benotzerkont gouf ugeluecht, mä Dir konnt net automatesch ageloggt ginn. [[Special:UserLogin|Loggt Iech w.e.g. manuell an]].",
        "noname": "Dir hutt kee gëltege Benotzernumm uginn.",
        "loginsuccesstitle": "Ageloggt",
        "loginsuccess": "'''Dir sidd elo als \"$1\" op {{SITENAME}} ugemellt.'''",
        "botpasswords-label-cancel": "Ofbriechen",
        "botpasswords-label-delete": "Läschen",
        "botpasswords-label-resetpassword": "D'Passwuert zrécksetzen",
+       "botpasswords-help-grants": "All Berechtegung gëtt Zougang op déi Benotzerrechter déi e Benotzerkont schonn huet. Kuckt d'[[Special:ListGrants|Tabell vun de Berechtigunge]] fir méi Informatiounen.",
        "botpasswords-label-restrictions": "Limite fir d'Benotzen:",
        "botpasswords-label-grants-column": "Accordéiert",
        "botpasswords-bad-appid": "Den Numm vum Bot \"$1\" ass net valabel.",
        "botpasswords-insert-failed": "De Botnumm \"$1\" konnt net dobäigesat ginn. Gouf e schonn derbäigesat?",
+       "botpasswords-created-title": "Botpasswuert ugeluecht",
        "botpasswords-created-body": "D'Botpasswuert fir de Bot-Numm \"$1\" vum Benotzer ''$2'' gouf ugeluecht.",
        "botpasswords-updated-title": "Botpasswuert aktualiséiert",
        "botpasswords-updated-body": "D'Botpasswuert fir de Bot-Numm \"$1\" vum Benotzer ''$2'' gouf aktualiséiert.",
        "botpasswords-deleted-title": "Botpasswuert geläscht",
        "botpasswords-deleted-body": "D'Botpasswuert fir de Bot-Numm \"$1\" vum Benotzer ''$2'' gouf geläscht.",
+       "botpasswords-newpassword": "Dat neit Passwuert fir sech mat <strong>$1</strong> anzeloggen ass <strong>$2</strong>.\n<em>Versuergt dat fir sech spéider dorop ze referéieren.</em>",
        "botpasswords-not-exist": "De Benotzer \"$1\" huet kee Botpasswuert mam Numm \"$2\".",
        "resetpass_forbidden": "Passwierder kënnen net geännert ginn.",
        "resetpass_forbidden-reason": "Passwierder kënnen net geännert ginn: $1",
        "right-createpage": "Säiten uleeën (déi keng Diskussiounssäite sinn)",
        "right-createtalk": "Diskussiounssäiten uleeën",
        "right-createaccount": "Nei Benotzerkonten uleeën",
+       "right-autocreateaccount": "Automatesch alogge mat engem externe Benotzerkont",
        "right-minoredit": "Ännerungen als kleng markéieren",
        "right-move": "Säite réckelen",
        "right-move-subpages": "Säiten zesumme mat hiren Ënnersäite réckelen",
        "grant-group-high-volume": "Massenaktivitéiten ausféieren",
        "grant-group-customization": "Upassungen an Astellungen",
        "grant-group-administration": "Administrativ Aktioune maachen",
+       "grant-group-private-information": "Op perséinlech Date vun Iech zougräifen",
        "grant-group-other": "Verschidden Aktivitéiten",
        "grant-blockusers": "Benotzer spären an d'Spären ophiewen",
        "grant-createaccount": "Benotzerkonten opmaachen",
        "grant-highvolume": "Massenännerungen",
        "grant-oversight": "Benotzer verstoppen a Versioune läschen",
        "grant-patrol": "Ännerungen op Säiten kontrolléieren",
+       "grant-privateinfo": "Op perséinlech Informatiounen zougräifen",
        "grant-protect": "Säite spären an entspären",
        "grant-rollback": "Ännerungen op Säiten zrécksetzen",
        "grant-sendemail": "Anere Benotzer E-Maile schécken",
        "undeletedrevisions": "$1 {{PLURAL:$1|Versioun gouf|$1 Versioune goufe}} restauréiert",
        "undeletedrevisions-files": "{{PLURAL:$1|1 Versioun|$1 Versiounen}} a(n) {{PLURAL:$2|1 Fichier|$2 Fichiere}} goufe restauréiert",
        "undeletedfiles": "$1 {{PLURAL:$1|Fichier gouf|Fichiere goufe}} restauréiert",
-       "cannotundelete": "D'Restauratioun huet net funktionéiert:\n$1",
+       "cannotundelete": "E puer oder all d'Restauratiounen hunn net funktionéiert:\n$1",
        "undeletedpage": "'''$1''' gouf restauréiert.\n\nAm [[Special:Log/delete|Läsch-Logbuch]] fannt Dir déi geläscht a restauréiert Säiten.",
        "undelete-header": "Kuckt [[Special:Log/delete|Läschlescht]] fir rezent geläscht Säiten.",
        "undelete-search-title": "Geläscht Säite sichen",
        "sp-contributions-newbies-sub": "Fir déi Nei",
        "sp-contributions-newbies-title": "Kontributioune vun neie Benotzer",
        "sp-contributions-blocklog": "Spärlescht",
-       "sp-contributions-suppresslog": "geläscht Benotzerkontributiounen",
-       "sp-contributions-deleted": "geläscht Kontributiounen",
+       "sp-contributions-suppresslog": "geläscht {{GENDER:$1|Benotzerkontributiounen}}",
+       "sp-contributions-deleted": "geläscht {{GENDER:$1|Benotzerkontributiounen}}",
        "sp-contributions-uploads": "Eropgeluede Fichieren",
        "sp-contributions-logs": "Logbicher",
        "sp-contributions-talk": "diskutéieren",
index bd20fa3..8de4353 100644 (file)
        "passwordreset-emailelement": "Nomme utente: \n$1\n\nPoula segretta temporannia: \n$2",
        "passwordreset-emailsentemail": "Se questo addresso de posta elettronnica o l'è associou a-a teu utença, alloa saiâ inviou un'e-mail pe rempostâ a poula segretta.",
        "passwordreset-emailsentusername": "Se gh'è un adreçço de posta elettronica associou con questo nomme utente, alloa saiâ inviou una email pe rempostâ a password.",
-       "passwordreset-emailsent-capture": "L'è stæto inviòu un'e-mail de reimpostaçion da poula segretta, o contegnuo o l'è riportòu chì appreuvo.",
-       "passwordreset-emailerror-capture": "L'è stæto generòu un'e-mail de reimpostaçion da poula segretta, riportà chì appreuvo. L'invio {{GENDER:$2|a l'utente}} o no l'è ariêscîo: $1",
        "passwordreset-emailsent-capture2": "L'email de rempostaçion da password {{PLURAL:$1|a l'è stæta inviâ|son stæte inviæ}}. {{PLURAL:$1|O nomme|L'elenco di nommi}} utente e password o l'è mostrou chì de sotta.",
        "passwordreset-emailerror-capture2": "Invio de email {{GENDER:$2|a l'utente}} non ariescio: $1. {{PLURAL:$3|O nomme|L'elenco di nommi}} utente e password o l'è mostrou chì de sotta.",
        "passwordreset-nocaller": "Un chi ciamma ti g'hæ da dâlo",
        "passwordreset-nodata": "No è stæto fornio ni un nomme utente ni un adreçço de posta elettronica",
        "changeemail": "Cangia o elimmina l'adresso e-mail",
        "changeemail-header": "Completa sto formulaio pe cangiâ o to adresso e-mail. Se ti veu rimeuve l'associaçion de quasesegge addresso e-mail da-a teu utensa, lascia io neuvo addresso e-mail veuo quande ti invii o formulaio.",
-       "changeemail-passwordrequired": "Saiâ necessaio insei a poula segretta pe confermâ a modiffica.",
        "changeemail-no-info": "Pe anâ direttamente a sta paggina, primma ti g'hæ da intrâ .",
        "changeemail-oldemail": "Addresso e-mail corrente:",
        "changeemail-newemail": "Noeuvo adresso e-mail",
        "undo-nochange": "Pâ che-a modiffica a sæ zà stæta anullâ.",
        "undo-summary": "Annullou a modiffica $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|discuscion]])",
        "undo-summary-username-hidden": "Anullou a modiffica $1 de un utente ascoso",
-       "cantcreateaccounttitle": "Non se peu registrâ l'utente",
        "cantcreateaccount-text": "A registrassion da questo addresso IP (<b>$1</b>) a l'è stæta bloccâ da [[User:$3|$3]].\n\nA raxon dæta a l'è ''$2''",
        "cantcreateaccount-range-text": "A registraçion da di addressi IP inte l'intervallo <strong>$1</strong>, ch'o  l'includde o teu (<strong>$4</strong>), a l'è stæta bloccâ da [[User:$3|$3]].\n\nA raxon dæta da $3 a l'è <em>$2</em>",
        "viewpagelogs": "Veddi i log relativi a 'sta paggina.",
        "emptyfile": "O file apen-a caregou pâ esee voeuo. Questo poriæ ese dovuo a un aro into nomme do file. Controlla se ti voeu davei caregâ sto file.",
        "windows-nonascii-filename": "Questo wiki o no supporta di nommi de file con di caratteri speciali.",
        "fileexists": "Un papê con sto nomme o l'existe za, pe piaxei danni 'n'euggiâ a <strong>[[:$1]]</strong> se no ti t'ê seguo de voeilo cangiâ.\n[[$1|thumb]]",
-       "filepageexists": "A pagina de descriçion de questo file aq l'è za stæta creâ a l'adreçço <strong>[[:$1]]</strong>, sciben che no ghe segge ancon un file con questo nomme. A descriçion de l'oggetto inseia in fase de caregamento a no l'appariâ in scia pagina de descriçion. Pe fâ scì che l'oggetto o comparisce in scia pagina de descriçion, saiâ necessaio modificala manualmente.\n[[$1|thumb]]",
+       "filepageexists": "A pagina de descriçion de questo file a l'è za stæta creâ a l'adreçço <strong>[[:$1]]</strong>, sciben che no ghe segge ancon un file con questo nomme. A descriçion de l'oggetto inseia in fase de caregamento a no l'appariâ in scia pagina de descriçion. Pe fâ scì che l'oggetto o comparisce in sciâ pagina de descriçion, saiâ necessaio modificala manualmente.\n[[$1|thumb]]",
        "fileexists-extension": "Un file co-in nomme scimile a questo o l'esiste za: [[$2|thumb]]\n* Nomme do file caregou: <strong>[[:$1]]</strong>\n* Nomme do file existente: <strong>[[:$2]]</strong>\nTi voeu miga çerne un nomme ciu caratteristego?",
        "fileexists-thumbnail-yes": "O file caregou o pâ ese una miniatua ''(thumbnail)''. [[$1|thumb]]\nVerifica, pe confronto, il file <strong>[[:$1]]</strong>.\nSe se tratta da mæxima inmaggine, inte dimenscioin originale, no l'è necessaio caregâne un'atra in miniatua.",
        "file-thumbnail-no": "O nomme do file comença con <strong>$1</strong>; pâ ch'o segge un'inmaggine de dimenscioin redute ''(miniatua)''.\nSe ti dispon-i del'immaggine inta risoluçion originale, carreghila. Sedunque, pe piaxei, cangighe o nomme.",
index b180b5f..2cc972a 100644 (file)
        "passwordreset-emailtitle": "Detil akun nang {{SITENAME}}",
        "passwordreset-emailelement": "Jeneng panganggo: \n$1\n\nTembung sandhi sauntara: \n$2",
        "passwordreset-emailsentemail": "Imel nggo nyetel maning tembung sandhi uwis dikirim.",
-       "passwordreset-emailsent-capture": "Imel kanggo nyetel maning tembung sandhi uwis dikirim, kaya sing ditidokna nang ngisor kiye.",
-       "passwordreset-emailerror-capture": "Imel nggo nyetel maning tembung sandhi uwis digawe, kaya sing ditidokna nang ngisor kiye, ningen gole ngirim maring {{GENDER:$2|panganggo}} ora teyeng: $1",
        "changeemail": "Ganti alamat imel",
        "changeemail-header": "Ganti alamat imel-e akun",
        "changeemail-no-info": "Rika kudu mlebu log kanggo ngakses kaca kiye sacara langsung.",
        "subject": "Subyek/judhul:",
        "minoredit": "Kiye suntingan cilik",
        "watchthis": "Awasi kaca kiyé",
-       "savearticle": "Simpen",
+       "savearticle": "Terbitna Kaca",
        "preview": "Pra tayang",
        "showpreview": "Pra tayang",
        "showdiff": "Ndeleng bedané",
        "undo-failure": "Suntingan kiye ora teyeng dibatalna jalaran ana konflik panyuntingan antara.",
        "undo-norev": "Suntingan kiye ora teyeng dibatalna jalaran wis ora ana utawa anu wis dibusek.",
        "undo-summary": "Mbatalna revisi $1 sekang [[Special:Contributions/$2|$2]] ([[User talk:$2|dopokan]])",
-       "cantcreateaccounttitle": "Ora teyeng gawe akun",
        "cantcreateaccount-text": "Ngawe akun sekang alamat IP kiye ('''$1''') wis diblokir nang [[User:$3|$3]].\n\nAlesane miturut $3 yakuwe ''$2''",
        "viewpagelogs": "Deleng log-e kaca kiye",
        "nohistory": "Ora ana sajarah panyuntingan kanggo kaca kiye.",
index e1722ba..94699ba 100644 (file)
        "category-file-count-limited": "Anatin'ity sokajy ity ireo rakitra ireo. ($1 no aseho) {{PLURAL:}}",
        "listingcontinuesabbrev": " manaraka.",
        "index-category": "pejy voasokajy",
-       "noindex-category": "Pejy tsy voasikajy",
+       "noindex-category": "Pejy tsy voatondro",
        "broken-file-category": "Pejy misy rohin-drakitra tapaka",
        "about": "Mombamomba",
        "article": "Votoatin'ny pejy",
        "passwordreset-emailtext-user": "Nisy mpikambana mitondra anarana $1 eo amin'i {{SITENAME}} nangataka fampatsiahivana mikasika ny kaontinao eo amin'i {{SITENAME}} ($4). Manana io adiresy imailaka {{PLURAL:$3|io kaontim-pikambana io|ireo kaontim-pikambana ireo}} :\n\n$2\n\nHitsahatra afaka {{PLURAL:$5|iray|$5}} andro {{PLURAL:$3|io|ireo}} tenimiafina {{PLURAL:$3|io|ireo}}. Mila miditra dien'izao ianao izao ary mifidy tenimiafina vaovao. Raha tsy avy aminao ity hataka ity na efa nahatadidy ny tenimiafinao taloha ianao, ary raha tsy tianao hovaina intsony ilay tenimiafinao, dia azonao tsy raharahiana ity hafatra ity ary mampiasa ny tenimiafinao taloha.",
        "passwordreset-emailelement": "Anaram-pikambana : \n$1\n\nTenimiafina miserana : \n$2",
        "passwordreset-emailsentemail": "Lasa ny mailaka famerenana tenimiafina.",
-       "passwordreset-emailsent-capture": "Lasa ilay mailaka famerenana tenimiafina, izay aseho eo ambany.",
-       "passwordreset-emailerror-capture": "Nosoratana ilay mailaka famerenana tenimiafina, izay aseho eo ambany, fa tsy tafalefa tany amin'ilay mpikambana ilay izy : $1{{GENDER:$2}}",
        "changeemail": "Hanova ny adiresy imailaka",
        "changeemail-header": "Hanova ny adiresy imailak'ilay kaonty",
        "changeemail-no-info": "Mila tafiditra ianao vao avaka mijery ity pejy ity.",
        "undo-nochange": "Hoatry ny efa nofoanana ilay fanovana.",
        "undo-summary": "Niala ny fanovàna $1 nataon'i [[Special:Contributions/$2|$2]] ([[User talk:$2|resaho]])",
        "undo-summary-username-hidden": "Namafa ny famerenana $1 nataom-pikambana afenina",
-       "cantcreateaccounttitle": "Tsy afaka manokatra kaonty ianao.",
        "cantcreateaccount-text": "Voasakan'i [[User:$3|$3]] ny fanokafana kaonty avy amin'ity adiresy IP (<b>$1</b>)\n\n''$2'' ny antony.",
        "cantcreateaccount-range-text": "Nosakanan'i [[User:$3|$3]] ny fanokafana kaonty avy amin'ny adiresy IP ao amin'ny elanelana <strong>$1</strong> izay ahitana ny adiresy IP-nao (<strong>$4</strong>).",
        "viewpagelogs": "Hijery ny fanovan'ity pejy ity",
index c9a7894..459c47b 100644 (file)
        "grant-group-high-volume": "Вршење на активности од голем обем",
        "grant-group-customization": "Прилагодувања и поставки",
        "grant-group-administration": "Вршење на административни дејства",
+       "grant-group-private-information": "Пристап до лични податоци за вас",
        "grant-group-other": "Разни активности",
        "grant-blockusers": "Блокирање и одблокирање корисници",
        "grant-createaccount": "Правење сметки",
        "grant-highvolume": "Високообемно уредување",
        "grant-oversight": "Скривање на корисници и преработки",
        "grant-patrol": "Патрола на измени во страници",
+       "grant-privateinfo": "Пристап до лични информации",
        "grant-protect": "Заштита на незаштитени страници",
        "grant-rollback": "Отповикување на измени во страници",
        "grant-sendemail": "Испраќање на е-пошта до други корисници",
        "undeletehistorynoadmin": "Оваа статија е избришана. Причината за бришењето е наведена подолу,\nзаедно со информации за корисникот кој ја уредувал страницата пред бришењето. Целиот текст\nод избришаните верзии е достапен само за администраторите.",
        "undelete-revision": "Избришана преработка на $1 (од $4, во $5) од уредникот $3:",
        "undeleterevision-missing": "Грешна или непостоечка преработка.\nМожеби имате лоша врска, преработката била обновена или избришана од архивата.",
+       "undeleterevision-duplicate-revid": "Не можев да повратам {{PLURAL:$1|една преработка|$1 преработки}} бидејќи {{PLURAL:$1|нејзината|нивните}} <code>rev_id</code> се веќе зафатени.",
        "undelete-nodiff": "Не постои постара преработка.",
        "undeletebtn": "Врати",
        "undeletelink": "погледај/врати",
        "undeletedrevisions": "{{PLURAL:$1|1 измена е обновена|$1 измени се обновени}}",
        "undeletedrevisions-files": "{{PLURAL:$1|1 измена|$1 измени}} и {{PLURAL:$2|1 податотека|$2 податотеки}} се вратени",
        "undeletedfiles": "{{PLURAL:$1|1 податотека е вратена|$1 податотеки се вратени}}",
-       "cannotundelete": "Враќањето не успеа:\n$1",
+       "cannotundelete": "Враќањето не успеа делумно или целосно:\n$1",
        "undeletedpage": "'''$1 беше обновена'''\n\nПогледнете го [[Special:Log/delete|дневникот на бришења]] за попис на претходни бришења и обновувања.",
        "undelete-header": "Списокот на неодамна избришани страници ќе го најдете на [[Special:Log/delete|дневникот на бришења]].",
        "undelete-search-title": "Пребарување на избришани страници",
        "sp-contributions-newbies-sub": "За нови кориснички сметки",
        "sp-contributions-newbies-title": "Придонеси на нови корисници",
        "sp-contributions-blocklog": "Дневник на блокирања",
-       "sp-contributions-suppresslog": "притаени придонеси на корисникот",
-       "sp-contributions-deleted": "избÑ\80иÑ\88ани ÐºÐ¾Ñ\80иÑ\81ниÑ\87ки Ð¿Ñ\80идонеÑ\81и",
+       "sp-contributions-suppresslog": "притаени придонесите на {{GENDER:$1|корисникот|корисничката}}",
+       "sp-contributions-deleted": "избÑ\80иÑ\88ани Ð¿Ñ\80идонеÑ\81иÑ\82е Ð½Ð° {{GENDER:$1|коÑ\80иÑ\81никоÑ\82|коÑ\80иÑ\81ниÑ\87каÑ\82а}}",
        "sp-contributions-uploads": "подигања",
        "sp-contributions-logs": "дневници",
        "sp-contributions-talk": "разговор",
index ebb6a50..d8bf6e3 100644 (file)
        "passwordreset-emailelement": "सदस्यनाव: \n$1\n\nअस्थायी परवलीचा शब्द: \n$2",
        "passwordreset-emailsentemail": "जर हा विपत्रपत्ता आपल्या खात्याशी संलग्न असेल तर, परवलीच्या शब्दाच्या पुनर्स्थापनेबाबत एक विपत्र पाठवण्यात येईल.",
        "passwordreset-emailsentusername": "जर या सदस्यनावाशी संलग्न विपत्रपत्ता असेल तर, परवलीचा शब्द पुनर्स्थापनाबाबत विपत्र पाठविल्या जाईल.",
-       "passwordreset-emailsent-capture": "'परवलीचा शब्द' पुनर्स्थापनेबाबत एक विपत्र पाठवण्यात आले आहे जे खाली दर्शविण्यात आले आहे.",
-       "passwordreset-emailerror-capture": "'परवलीचा शब्द' पुनर्स्थापनेबाबत एक विपत्र निर्माण करण्यात आले, जे खाली दर्शविण्यात आले आहे.परंतु,{{GENDER:$2|सदस्य}}ला पाठविणे असफल झाले: $1",
        "changeemail": "विपत्रपत्ता बदला किंवा हटवा",
        "changeemail-header": "आपला विपत्रपत्ता बदलण्यास हे आवेदन पूर्ण करा.जर आपणास आपल्या खात्याशी संलग्न कोणताही विपत्रपत्ता हटवायचा असेल तर,आवेदन सादर करण्यापूर्वी, नविन विपत्रपत्त्यासाठी असलेली जागा कोरी ठेवा.",
-       "changeemail-passwordrequired": "हे बदल नक्की करण्यासाठी आपणास आपला परवलीचा शब्द टाकावा लागेल.",
        "changeemail-no-info": "हे पान थेट बघण्यासठी तुम्हाला सनोंद-प्रवेशित असावे लागेल.",
        "changeemail-oldemail": "सध्याचा ईमेल पत्ता :",
        "changeemail-newemail": "नवा ईमेल पत्ता:",
        "undo-nochange": "असे दिसते कि हे संपादन पूर्ववत केल्या गेले आहे.",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|चर्चा]])यांची आवृत्ती $1 परतवली.",
        "undo-summary-username-hidden": "अज्ञात सदस्याची $1 आवृत्ती परतवा",
-       "cantcreateaccounttitle": "खाते उघडू शकत नाही",
        "cantcreateaccount-text": "('''$1''')या आंतरजाल अंकपत्त्याकडूनच्या खाते निर्मितीस [[User:$3|$3]]ने अटकाव केला आहे.\n\n$3ने ''$2'' कारण दिले आहे.",
        "cantcreateaccount-range-text": "<strong>$1</strong>आवाक्यातील आंतरजाल अंकपत्ते,ज्यात आपल्या (<strong>$4</strong>) या अंकपत्त्याचा समावेश आहे, [[User:$3|$3]] ने त्यांच्या खाते निर्मितीस प्रतिबंध केला आहे.\n\n$3 ने <em>$2</em>कारण दिले आहे.",
        "viewpagelogs": "या पानाच्या नोंदी पहा",
        "undeletedrevisions": "{{PLURAL:$1|1 आवर्तन|$1 आवर्तने}} पुनर्स्थापित",
        "undeletedrevisions-files": "{{PLURAL:$1|1 आवर्तन|$1 आवर्तने}}आणि {{PLURAL:$2|1 संचिका|$2 संचिका}} पुनर्स्थापित",
        "undeletedfiles": "{{PLURAL:$1|1 संचिका|$1 संचिका}} पुनर्स्थापित",
-       "cannotundelete": "उलटवणे फसले:$1",
+       "cannotundelete": "à¤\95ाहà¥\80 à¤\95िà¤\82वा à¤¸à¤°à¥\8dवà¤\9a à¤\89लà¤\9fवणà¥\87 à¤«à¤¸à¤²à¥\87:$1",
        "undeletedpage": "<strong>$1ला पुनर्स्थापित केले</strong>\n\nअलिकडिल वगळलेल्या आणि पुनर्स्थापितांच्या नोंदीकरिता [[Special:Log/delete|वगळल्याच्या नोंदी]] पहा .",
        "undelete-header": "अलीकडील वगळलेल्या पानांकरिता [[Special:Log/delete|वगळलेल्या नोंदी]] पहा.",
        "undelete-search-title": "वगळलेली पाने शोधा",
        "sp-contributions-newbies-sub": "नवशिक्यांसाठी",
        "sp-contributions-newbies-title": "नवीन खात्यांसाठी सदस्य योगदान",
        "sp-contributions-blocklog": "रोध नोंदी",
-       "sp-contributions-suppresslog": "सदस्य योगदानाचे दमन केले",
-       "sp-contributions-deleted": "वगळलेली सदस्य संपादने",
+       "sp-contributions-suppresslog": "{{GENDER:$1|सदस्य}} योगदानाचे दमन केले",
+       "sp-contributions-deleted": "वगळलेली {{GENDER:$1|सदस्य}} संपादने",
        "sp-contributions-uploads": "अपभारणे",
        "sp-contributions-logs": "नोंदी",
        "sp-contributions-talk": "चर्चा",
index 4a82353..305228d 100644 (file)
@@ -21,7 +21,8 @@
                        "Pizza1016",
                        "Macofe",
                        "Matma Rex",
-                       "Nemo bis"
+                       "Nemo bis",
+                       "Mbrt"
                ]
        },
        "tog-underline": "Garis bawah pautan:",
        "subject": "Perkara:",
        "minoredit": "Ini adalah suntingan kecil",
        "watchthis": "Pantau laman ini",
-       "savearticle": "Simpan",
+       "savearticle": "Paparkan Laman",
        "publishpage": "Terbitkan",
        "publishchanges": "Terbit perubahan",
        "preview": "Pralihat",
index c756f47..b13f5f9 100644 (file)
        "action-applychangetags": "appreca tag pe' tramente ca se fanno 'e cagnamiente vuoste",
        "action-changetags": "azzecca o lèva tag a caso dint'a verziune nnividuale e riggistre 'e log",
        "action-deletechangetags": "scancellare 'e tag d' 'o database",
+       "action-purge": "agghiuorna sta paggena",
        "nchanges": "$1 {{PLURAL:$1|cagnamiento|cagnamiente}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|'a ll'urdema visita}}",
        "enhancedrc-history": "cronologgia",
        "uploadstash-errclear": "'A pulezzia d' 'e file scassaje.",
        "uploadstash-refresh": "Agghiuorna l'elenco d' 'e file",
        "uploadstash-thumbnail": "vide miniatura",
+       "uploadstash-exception": "Nun s'è pututo sarvà 'a càrreca dint' 'a stash ($1): \"$2\".",
        "invalid-chunk-offset": "Distanza d' 'a parte nun valida",
        "img-auth-accessdenied": "Acciesso negato",
        "img-auth-nopathinfo": "PATH_INFO mancante.\n'O server nun è mpustato pe' passà sta nfurmazione.\nPuò darse ca, essenno basato ncopp'a CGI, nun putesse suppurtà img_auth.\nVide https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "watchnologin": "Acciesso nun affettuato",
        "addwatch": "Miette dint' 'a l'elenco 'e paggene cuntrullate",
        "addedwatchtext": "'A paggena \"[[:$1]]\" e 'a paggena 'e chiacchiera è stata azzeccata dint'a l'elenco 'e [[Special:Watchlist|paggene cuntrullate]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" e 'a paggena 'e chiacchiera suòccia è stata azzeccata dint'a l'elenco 'e [[Special:Watchlist|paggene cuntrullate]] vuosto.",
        "addedwatchtext-short": "Chista paggena \"$1\" è stata azzeccata a l'elenco 'e paggene cuntrullate.",
        "removewatch": "Leva 'a l'elenco 'e paggene cuntrullate",
-       "removedwatchtext": "\"[[:$1]]\" 'e 'a paggena 'e chiacchiera soja so' state scancellata 'a l'elenco [[Special:Watchlist|'e paggene cuntrullate]] vuosto.",
+       "removedwatchtext": "\"[[:$1]]\" e 'a paggena 'e chiacchiera soja so' state scancellate 'a l'elenco [[Special:Watchlist|'e paggene cuntrullate]] vuosto.",
+       "removedwatchtext-talk": "\"[[:$1]]\" e 'a paggena 'e chiacchiera soja so' state luvate 'a l'elenco [[Special:Watchlist|'e paggene cuntrullate]] vuosto.",
        "removedwatchtext-short": "Chista paggena \"$1\" è stata luvata a l'elenco 'e paggene cuntrullate.",
        "watch": "Secuta",
        "watchthispage": "Tiene d'uocchio sta paggena",
index f50e348..a4514e7 100644 (file)
        "content-model-css": "CSS",
        "content-json-empty-object": "Objeto vazio",
        "content-json-empty-array": "Array vazia",
+       "deprecated-self-close-category": "Páginas com etiquetas HTML de autofechamento não válidas",
        "duplicate-args-warning": "<strong> Aviso: </strong> [[:$1]] está chamando [[:$2]] com mais de um valor para o parâmetro \"$3\". Será utilizado apenas o último valor fornecido.",
        "duplicate-args-category": "Páginas com argumentos de predefinições duplicados",
        "duplicate-args-category-desc": "A pagina contem modelos que usam argumentos duplicados, como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ou <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
index 16842c2..8108c7a 100644 (file)
        "content-model-css": "CSS",
        "content-json-empty-object": "Objeto vazio",
        "content-json-empty-array": "Matriz vazia",
+       "deprecated-self-close-category": "Páginas com etiquetas HTML de autofechamento não válidas",
        "duplicate-args-warning": "<strong>Aviso:</strong> [[:$1]] chama [[:$2]] com mais de um valor para o parâmetro \"$3\". Somente o último valor fornecido será utilizado.",
        "duplicate-args-category": "Páginas com argumentos de predefinições duplicados",
        "duplicate-args-category-desc": "A página contém campos de predefinições que utilizam duplicatas de argumentos, tais como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ou <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "showhideselectedversions": "Mostrar/ocultar versões selecionadas",
        "editundo": "desfazer",
        "diff-empty": "(Sem diferenças)",
-       "diff-multi-sameuser": "(Há {{PLURAL:$1|uma edição intermédia|$1 edições intermédias}} do mesmo utilizador que não estão a ser apresentadas)",
+       "diff-multi-sameuser": "(Há {{PLURAL:$1|uma edição intermédia do mesmo utilizador que não está a ser apresentada|$1 edições intermédias do mesmo utilizador que não estão a ser apresentadas}})",
        "diff-multi-otherusers": "(Há {{PLURAL:$1|uma revisão intermédia|$1 revisões intermédias}} de {{PLURAL:$2|outro utilizador|$2 utilizadores}} que não {{PLURAL:$1|está a ser apresentada|estão a ser apresentadas}})",
        "diff-multi-manyusers": "({{PLURAL:$1|Uma edição intermédia|$1 edições intermédias}} de mais de {{PLURAL:$2|um utilizador|$2 utilizadores}} não {{PLURAL:$1|apresentada|apresentadas}})",
        "difference-missing-revision": "{{PLURAL:$2|Uma revisão|$2 revisões}} desta diferença ($1) não {{PLURAL:$2|foi encontrada|foram encontradas}}.\n\nIsto é geralmente causado por seguir uma ligação de histórico desatualizada para uma página que foi eliminada.\nOs detalhes podem ser encontrados no [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registo de eliminação].",
        "grant-group-high-volume": "Realizar actividades em grande quantidade",
        "grant-group-customization": "Personalização e preferências",
        "grant-group-administration": "Executar acções administrativas",
+       "grant-group-private-information": "Aceder aos seus dados privados",
        "grant-group-other": "Actividade diversa",
        "grant-blockusers": "Bloquear e desbloquear utilizadores",
        "grant-createaccount": "Criar contas",
        "undeletedrevisions": "$1 {{PLURAL:$1|edição restaurada|edições restauradas}}",
        "undeletedrevisions-files": "$1 {{PLURAL:$1|edição restaurada|edições restauradas}} e $2 {{PLURAL:$2|ficheiro restaurado|ficheiros restaurados}}",
        "undeletedfiles": "{{PLURAL:$1|ficheiro restaurado|$1 ficheiros restaurados}}",
-       "cannotundelete": "Restauração falhada:\n$1",
+       "cannotundelete": "Algumas ou todas as restaurações falharam:\n$1",
        "undeletedpage": "'''$1 foi restaurada'''\n\nConsulte o [[Special:Log/delete|registo de eliminações]] para um registo das eliminações e restaurações mais recentes.",
        "undelete-header": "Consulte o [[Special:Log/delete|registo de eliminações]] para ver as páginas eliminadas recentemente.",
        "undelete-search-title": "Pesquisar páginas eliminadas",
        "sp-contributions-newbies-sub": "Para contas novas",
        "sp-contributions-newbies-title": "Contribuições de contas novas",
        "sp-contributions-blocklog": "registo de bloqueios",
-       "sp-contributions-suppresslog": "contribuições suprimidas",
-       "sp-contributions-deleted": "contribuições eliminadas",
+       "sp-contributions-suppresslog": "contribuições de {{GENDER:$1|utilizador|utilizadora|utilizador(a)}} suprimidas",
+       "sp-contributions-deleted": "contribuições de {{GENDER:$1|utilizador|utilizadora|utilizador(a)}} eliminadas",
        "sp-contributions-uploads": "carregamentos",
        "sp-contributions-logs": "registos",
        "sp-contributions-talk": "discussão",
index 953ebbb..6a3d604 100644 (file)
        "right-applychangetags": "{{doc-right|applychangetags}}",
        "right-changetags": "{{doc-right|changetags}}",
        "right-deletechangetags": "{{doc-right|deletechangetags}}",
-       "grant-generic": "Used if the grant name is not defined. Parameters:\n* $1 - grant name\n\nDefined grants (grant name refers: blockusers, createeditmovepage, ...):\n* {{msg-mw|grant-checkuser}}\n* {{msg-mw|grant-blockusers}}\n* {{msg-mw|grant-createaccount}}\n* {{msg-mw|grant-createeditmovepage}}\n* {{msg-mw|grant-delete}}\n* {{msg-mw|grant-editinterface}}\n* {{msg-mw|grant-editmycssjs}}\n* {{msg-mw|grant-editmyoptions}}\n* {{msg-mw|grant-editmywatchlist}}\n* {{msg-mw|grant-editpage}}\n* {{msg-mw|grant-editprotected}}\n* {{msg-mw|grant-highvolume}}\n* {{msg-mw|grant-oversight}}\n* {{msg-mw|grant-patrol}}\n* {{msg-mw|grant-protect}}\n* {{msg-mw|grant-rollback}}\n* {{msg-mw|grant-sendemail}}\n* {{msg-mw|grant-uploadeditmovefile}}\n* {{msg-mw|grant-uploadfile}}\n* {{msg-mw|grant-basic}}\n* {{msg-mw|grant-viewdeleted}}\n* {{msg-mw|grant-viewmywatchlist}}",
+       "grant-generic": "Used if the grant name is not defined. Parameters:\n* $1 - grant name\n\nDefined grants (grant name refers: blockusers, createeditmovepage, ...):\n* {{msg-mw|grant-checkuser}}\n* {{msg-mw|grant-blockusers}}\n* {{msg-mw|grant-createaccount}}\n* {{msg-mw|grant-createeditmovepage}}\n* {{msg-mw|grant-delete}}\n* {{msg-mw|grant-editinterface}}\n* {{msg-mw|grant-editmycssjs}}\n* {{msg-mw|grant-editmyoptions}}\n* {{msg-mw|grant-editmywatchlist}}\n* {{msg-mw|grant-editpage}}\n* {{msg-mw|grant-editprotected}}\n* {{msg-mw|grant-highvolume}}\n* {{msg-mw|grant-oversight}}\n* {{msg-mw|grant-patrol}}\n* {{msg-mw|grant-privateinfo}}\n* {{msg-mw|grant-protect}}\n* {{msg-mw|grant-rollback}}\n* {{msg-mw|grant-sendemail}}\n* {{msg-mw|grant-uploadeditmovefile}}\n* {{msg-mw|grant-uploadfile}}\n* {{msg-mw|grant-basic}}\n* {{msg-mw|grant-viewdeleted}}\n* {{msg-mw|grant-viewmywatchlist}}",
        "grant-group-page-interaction": "{{Related|grant-group}}",
        "grant-group-file-interaction": "{{Related|grant-group}}",
        "grant-group-watchlist-interaction": "{{Related|grant-group}}",
        "grant-group-high-volume": "{{Related|Grant-group}}",
        "grant-group-customization": "{{Related|Grant-group}}",
        "grant-group-administration": "{{Related|Grant-group}}",
+       "grant-group-private-information": "{{Related|Grant-group}}",
        "grant-group-other": "{{Related|Grant-group}}",
        "grant-blockusers": "Name for grant \"blockusers\".\n{{Related|Grant}}",
-       "grant-createaccount": "Name for grant \"createaccount\".\n{{Related|grant}}",
-       "grant-createeditmovepage": "Name for grant \"createeditmovepage\".\n{{Related|grant}}",
-       "grant-delete": "Name for grant \"delete\".\n{{Related|grant}}",
-       "grant-editinterface": "Name for grant \"editinterface\".\n\n\"JS\" stands for \"JavaScript\".\n{{Related|grant}}",
-       "grant-editmycssjs": "Name for grant \"editmycssjs\".\n\n\"JS\" stands for \"JavaScript\".\n{{Related|grant}}",
-       "grant-editmyoptions": "Name for grant \"editmyoptions\".\n{{Related|grant}}",
-       "grant-editmywatchlist": "Name for grant \"editmywatchlist\".\n{{Related|grant}}\n{{Identical|Edit your watchlist}}",
-       "grant-editpage": "Name for grant \"editpage\".\n{{Related|grant}}",
-       "grant-editprotected": "Name for grant \"editprotected\".\n{{Related|grant}}",
-       "grant-highvolume": "Name for grant \"highvolume\".\n{{Related|grant}}",
-       "grant-oversight": "Name for grant \"oversight\".\n{{Related|grant}}",
-       "grant-patrol": "Name for grant \"patrol\".\n{{Related|grant}}",
-       "grant-protect": "Name for grant \"protect\".\n{{Related|grant}}",
-       "grant-rollback": "Name for grant \"rollback\".\n{{Related|grant}}",
-       "grant-sendemail": "Name for grant \"sendemail\".\n{{Related|grant}}",
-       "grant-uploadeditmovefile": "Name for grant \"uploadeditmovefile\".\n{{Related|grant}}",
-       "grant-uploadfile": "Name for grant \"uploadfile\".\n{{Related|grant}}\n{{Identical|Upload new file}}",
-       "grant-basic": "Name for grant \"basic\".\n{{Related|grant}}",
-       "grant-viewdeleted": "Name for grant \"viewdeleted\".\n{{Related|grant}}",
-       "grant-viewmywatchlist": "Name for grant \"viewmywatchlist\".\n{{Related|grant}}\n{{Identical|View your watchlist}}",
+       "grant-createaccount": "Name for grant \"createaccount\".\n{{Related|Grant}}",
+       "grant-createeditmovepage": "Name for grant \"createeditmovepage\".\n{{Related|Grant}}",
+       "grant-delete": "Name for grant \"delete\".\n{{Related|Grant}}",
+       "grant-editinterface": "Name for grant \"editinterface\".\n\n\"JS\" stands for \"JavaScript\".\n{{Related|Grant}}",
+       "grant-editmycssjs": "Name for grant \"editmycssjs\".\n\n\"JS\" stands for \"JavaScript\".\n{{Related|Grant}}",
+       "grant-editmyoptions": "Name for grant \"editmyoptions\".\n{{Related|Grant}}",
+       "grant-editmywatchlist": "Name for grant \"editmywatchlist\".\n{{Related|Grant}}\n{{Identical|Edit your watchlist}}",
+       "grant-editpage": "Name for grant \"editpage\".\n{{Related|Grant}}",
+       "grant-editprotected": "Name for grant \"editprotected\".\n{{Related|Grant}}",
+       "grant-highvolume": "Name for grant \"highvolume\".\n{{Related|Grant}}",
+       "grant-oversight": "Name for grant \"oversight\".\n{{Related|Grant}}",
+       "grant-patrol": "Name for grant \"patrol\".\n{{Related|Grant}}",
+       "grant-privateinfo": "Name for grant \"privateinfo\".\n{{Related|Grant}}",
+       "grant-protect": "Name for grant \"protect\".\n{{Related|Grant}}",
+       "grant-rollback": "Name for grant \"rollback\".\n{{Related|Grant}}",
+       "grant-sendemail": "Name for grant \"sendemail\".\n{{Related|Grant}}",
+       "grant-uploadeditmovefile": "Name for grant \"uploadeditmovefile\".\n{{Related|Grant}}",
+       "grant-uploadfile": "Name for grant \"uploadfile\".\n{{Related|Grant}}\n{{Identical|Upload new file}}",
+       "grant-basic": "Name for grant \"basic\".\n{{Related|Grant}}",
+       "grant-viewdeleted": "Name for grant \"viewdeleted\".\n{{Related|Grant}}",
+       "grant-viewmywatchlist": "Name for grant \"viewmywatchlist\".\n{{Related|Grant}}\n{{Identical|View your watchlist}}",
        "newuserlogpage": "{{doc-logpage}}\n\nPart of the \"Newuserlog\" extension. It is both the title of [[Special:Log/newusers]] and the link you can see in [[Special:RecentChanges]].",
        "newuserlogpagetext": "Part of the \"Newuserlog\" extension. It is the description you can see on [[Special:Log/newusers]].",
        "rightslog": "{{doc-logpage}}\n\nIn [[Special:Log]]",
        "undeletehistorynoadmin": "Used in [[Special:Undelete]].\n\nSee also:\n* {{msg-mw|Undeletehistory}}\n* {{msg-mw|Undeleterevdel}}",
        "undelete-revision": "Shown in \"View and restore deleted pages\" ([[Special:Undelete/$1]]).\nParameters:\n* $1 - deleted page name\n* $2 - (unused)\n* $3 - username (author of revision, not who deleted it)\n* $4 - date of the revision (localized)\n* $5 - time of the revision (localized)\nExample (in English):\n* Deleted revision of [[Main Page]] (as of 14 September 2013, at 08:17) by [[User:Username|Username]]:",
        "undeleterevision-missing": "Used as warning when undeleting the revision.",
+       "undeleterevision-duplicate-revid": "Used as warning when some revisions could not be undeleted due to <code>rev_id</code> collisions.  Parameters:\n* - Number of revisions that could not be restored for this reason.",
        "undelete-nodiff": "Used in [[Special:Undelete]].",
        "undeletebtn": "Shown on [[Special:Undelete]] as button caption and on [[Special:Log/delete|deletion log]] after each entry (for sysops).\n\n{{Identical|Restore}}",
        "undeletelink": "Display name of link to undelete a page used on [[Special:Log/delete]]\n\n{{Identical|View}}\n{{Identical|Restore}}",
        "sp-contributions-newbies-sub": "Note at the top of the page of results for a search on [[Special:Contributions]] where 'Show contributions for new accounts only' has been selected.",
        "sp-contributions-newbies-title": "The page title in your browser bar, but not the page title.\n\nSee also:\n* {{msg-mw|Sp-contributions-newbies-sub}}",
        "sp-contributions-blocklog": "Used as a display name for a link to the block log on for example [[Special:Contributions/Mediawiki default]]\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-deleted}}\n* {{msg-mw|Sp-contributions-userrights}}\n{{Identical|Block log}}",
-       "sp-contributions-suppresslog": "Used as a display name for a link to log entries of suppressed edits made by that user.\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also {{msg-mw|sp-contributions-deleted}}, {{msg-mw|sp-deletedcontributions-contribs}}, {{msg-mw|contributions}}, {{msg-mw|deletedcontributions-title}}.",
-       "sp-contributions-deleted": "This is a link anchor used in [[Special:Contributions]]/''name'', when user viewing the page has the right to delete pages, or to restore deleted pages.\n\nUsed as link title in [[Special:Contributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-blocklog}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-userrights}}",
+       "sp-contributions-suppresslog": "Used as a display name for a link to log entries of suppressed edits made by that user.\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]]. Parameters:\n* $1 is a plain text username used for GENDER.\nSee also {{msg-mw|sp-contributions-deleted}}, {{msg-mw|sp-deletedcontributions-contribs}}, {{msg-mw|contributions}}, {{msg-mw|deletedcontributions-title}}.",
+       "sp-contributions-deleted": "This is a link anchor used in [[Special:Contributions]]/''name'', when user viewing the page has the right to delete pages, or to restore deleted pages.\n\nUsed as link title in [[Special:Contributions]]. Parameters:\n* $1 is a plain text username used for GENDER.\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-blocklog}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-userrights}}",
        "sp-contributions-uploads": "Used as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-blocklog}}\n* {{msg-mw|Sp-contributions-logs}}\n* {{msg-mw|Sp-contributions-deleted}}\n* {{msg-mw|Sp-contributions-userrights}}\n{{Identical|Upload}}",
        "sp-contributions-logs": "Appears as an action link in the header of the Special:Contributions/''Username'' pages (e.g. \"For Somebody (talk | block log | logs)\").\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|Sp-contributions-talk}}\n* {{msg-mw|Change-blocklink}}\n* {{msg-mw|Unblocklink}}\n* {{msg-mw|Blocklink}}\n* {{msg-mw|Sp-contributions-blocklog}}\n* {{msg-mw|Sp-contributions-uploads}}\n* {{msg-mw|Sp-contributions-deleted}}\n* {{msg-mw|Sp-contributions-userrights}}\n{{Identical|Log}}",
        "sp-contributions-talk": "This is a link anchor used in the [[Special:Contributions]]/''usernamename'' pages.\nThe link appears in a list of similar ones separated by {{msg-mw|pipe-separator}}, e.g. like this:<br />\n( talk | block log | logs | deleted contributions | rights management )\n\nUsed as link title in [[Special:Contributions]] and in [[Special:DeletedContributions]].\n\nSee also:\n* {{msg-mw|change-blocklink}}\n* {{msg-mw|unblocklink}}\n* {{msg-mw|blocklink}}\n* {{msg-mw|sp-contributions-blocklog}}\n* {{msg-mw|sp-contributions-uploads}}\n* {{msg-mw|sp-contributions-logs}}\n* {{msg-mw|sp-contributions-deleted}}\n* {{msg-mw|sp-contributions-userrights}}\n{{Identical|Talk}}",
        "tags-active-yes": "Table cell contents if given tag is \"active\".\n\nSee also:\n* {{msg-mw|Tags-active-no}}\n{{Identical|Yes}}",
        "tags-active-no": "Table cell contents if given tag is not \"active\".\n\nSee also:\n* {{msg-mw|Tags-active-yes}}\n{{Identical|No}}",
        "tags-source-extension": "Table cell contents if given tag can be applied automatically by a software [[mw:Manual:Extensions|extension]].\n\nSee also:\n* {{msg-mw|Tags-source-manual}}\n* {{msg-mw|Tags-source-none}}",
-       "tags-source-manual": "Table cell contents if given tag can be applied by users or bots.\n\nSee also:\n* {{msg-mw|Tags-source-extension}}\n* {{msg-mw|Tags-source-none}}",
+       "tags-source-manual": "\"Applied\" is not past tense, but an adjective that describes an action that sometimes happens, as in the sentence: \"(this tag is usually) applied by users and bots\".\n\nTable cell contents if given tag can be applied by users or bots.\n\nSee also:\n* {{msg-mw|Tags-source-extension}}\n* {{msg-mw|Tags-source-none}}",
        "tags-source-none": "Table cell contents if given tag is no longer in use. (It was applied in the past, but it is currently not applied.)\n\nSee also:\n* {{msg-mw|Tags-source-extension}}\n* {{msg-mw|Tags-source-manual}}",
        "tags-edit": "Used on [[Special:Tags]]. Verb. Used as display text on a link to create/edit a description.\n{{Identical|Edit}}",
        "tags-delete": "Used on [[Special:Tags]]. Verb. Used as display text on a link to delete a tag.\n{{Identical|Delete}}",
index f7b7c94..a5cfc82 100644 (file)
        "sp-contributions-newbies-sub": "С новых учётных записей",
        "sp-contributions-newbies-title": "Вклад с недавно созданных учётных записей",
        "sp-contributions-blocklog": "блокировки",
-       "sp-contributions-suppresslog": "удалённый вклад участника",
-       "sp-contributions-deleted": "удалённые правки",
+       "sp-contributions-suppresslog": "удалённый вклад {{GENDER:$1|участника|участницы}}",
+       "sp-contributions-deleted": "удалённые правки {{GENDER:$1|участника|участницы}}",
        "sp-contributions-uploads": "загрузки",
        "sp-contributions-logs": "журналы",
        "sp-contributions-talk": "обсуждение",
index 87c4234..ff8f1de 100644 (file)
@@ -32,7 +32,8 @@
                        "Roonyh",
                        "Matma Rex",
                        "SusithCM",
-                       "Sandaru"
+                       "Sandaru",
+                       1100100
                ]
        },
        "tog-underline": "සබැඳි යටීර කිරීම:",
        "userlogout": "නික්මීම",
        "notloggedin": "ප්‍රවිසී නැත",
        "userlogin-noaccount": "ගිණුමක් නොමැතිද?",
-       "userlogin-joinproject": "{{SITENAME}}හා එක්වන්න",
+       "userlogin-joinproject": "{{SITENAME}} හා එක්වන්න",
        "nologin": "ඔබ හට ගිණුමක් නොමැතිද? '''$1'''.",
        "nologinlink": "ගිණුමක් තනන්න",
        "createaccount": "අලුත් ගිණුමක් තනන්න",
        "passwordreset-emailtext-user": "{{SITENAME}} හි පරිශීලක $1,{{SITENAME}}($4)සඳහා මුරපදය යලි පිහිටුවීමට ඉල්ලා ඇත.\n\n$2\n\n{{PLURAL:$3|මෙම මුරපදය|මෙම මුරපද}}{{PLURAL:$5|එක් දිනකින්|දවස්$5කින්}}කල් ඉකුත් වනු ඇත.\nඔබ දැන් ඇතුළු වී නව මුරපදයක් තේරිය යුතුය.මෙම ඉල්ලීම වෙන කෙනෙකු විසින් හෝ ඔබට ඔබගේ මුල් මුරපදය මතක නම් හෝ ඔබ තව දුරටත් එය වෙනස් කිරීමට අදහස් නොකරයි නම් හෝ ඔබ මෙම පනිවිඩය නොසලකාහැර ඔබගේ පැරණි මුරපදය භාවිතා කරන්න.",
        "passwordreset-emailelement": "පරිශීලක නාමය: \n$1\n\nතාවකාලික මුරපදය: \n$2",
        "passwordreset-emailsentemail": "මුර-පදය නැවත සකස් කිරීම පිළිබඳව විද්‍යුත් තැපෑලක් යවන ලදී.",
-       "passwordreset-emailsent-capture": "මුර-පදය වෙනස් කිරීම පිළිබඳව විද්‍යුත් තැපෑලක් යවන ලදී, එය පහත දැක්වේ.",
-       "passwordreset-emailerror-capture": "සිහිකැඳවුම් ඊ-තැපෑල ජනිත කරනු ලැබූ අතර, එය පහත දැක්වේ, නමුත් එය {{GENDER:$2|}}පරිශීලකයාට යැවීම අසාර්ථක වුනි: $1",
        "changeemail": "විද්‍යුත් තැපෑල වෙනස් කරන්න හෝ ඉවත් කරන්න",
        "changeemail-header": "ගිණුම් විද්‍යුත් තැපැල් ලිපිනය වෙනස් කරන්න",
        "changeemail-no-info": "මෙම පිටුව සෘජු ලෙස සම්ප්‍රවේශය කෙරුමට පළමුව ඔබ ප්‍රවිෂ්ටව සිටිය යුතුය.",
        "undo-nochange": "මෙම සංස්කරණය දැනටමත් අතහැර දමන ලද කර ඇති බව පෙනී යයි.",
        "undo-summary": " [[Special:Contributions/$2|$2]] මගින් සිදුකල  $1 සංශෝධනය අහෝසි කරන්න ([[User talk:$2|සාකච්ඡා]])",
        "undo-summary-username-hidden": "සැඟවුණු පරිශීලකයෙක් විසින් සංශෝධනය $1 අස් කරන්න",
-       "cantcreateaccounttitle": "ගිණුම තැනිය නොහැක",
        "cantcreateaccount-text": "මෙම IP ලිපිනය ('''$1''') මගින් ගිණුම් තැනීම [[User:$3|$3]] විසින් වාරණය කොට ඇත.\n\n$3 විසින් සපයා ඇති හේතුව ''$2'' වේ",
        "cantcreateaccount-range-text": "ඔබේ IP ලිපිනය ('' '$4' '') ද ඇතුළත් වන පරාසය තුළ IP ලිපිනයන් '' '$1', '' සිට ගිණුම් තැනීම  [[User:$3|$3]] විසින් වාරණය කොට ඇත. $3 විසින් දී ඇති හේතුව '' '$2' වේ",
        "viewpagelogs": "මෙම පිටුව පිලිබඳ සටහන් නරඹන්න",
        "special-characters-title-endash": "en තේජස",
        "special-characters-title-emdash": "em තේජස",
        "special-characters-title-minus": "ඍණ ලකුණ",
-       "api-error-blacklisted": "කරුණාකර වෙනස්, විස්තරාත්මක මාතෘකාවක් තෝරන්න.",
        "randomrootpage": "අහඹු මූල පිටුව"
 }
index f472001..7ef457b 100644 (file)
        "grant-group-high-volume": "Izvajanje visokoobsežnih dejavnosti",
        "grant-group-customization": "Prilagoditve in nastavitve",
        "grant-group-administration": "Izvajanje administrativnih dejanj",
+       "grant-group-private-information": "Dostop do zasebnih podatkov o vas",
        "grant-group-other": "Druga dejavnost",
        "grant-blockusers": "Blokiranje in odblokiranje uporabnikov",
        "grant-createaccount": "Ustvarjanje računov",
        "grant-highvolume": "Visokoobsežno urejanje",
        "grant-oversight": "Skrivanje uporabnikov in zatiranje redakcij",
        "grant-patrol": "Nadzor sprememb strani",
+       "grant-privateinfo": "Dostop do zasebnih podatkov",
        "grant-protect": "Zaščita in odstranitev zaščite strani",
        "grant-rollback": "Razveljavitev sprememb strani",
        "grant-sendemail": "Pošiljanje e-pošte drugim uporabnikom",
        "undeletehistorynoadmin": "Stran je bila izbrisana.\nRazlog za izbris je skupaj s podrobnostmi o uporabnikih, ki so jo urejali pred izbrisom, naveden v prikazanem povzetku.\nDejansko besedilo izbrisanih redakcij je dostopno le administratorjem.",
        "undelete-revision": "Izbrisana redakcija $1 (dne $4 ob $5) uporabnika $3:",
        "undeleterevision-missing": "Napačna ali manjkajoča redakcija.\nMorda imate napačno povezavo ali pa je bila redakcija obnovljena ali odstranjena iz arhiva.",
+       "undeleterevision-duplicate-revid": "$1 {{PLURAL:$1|redakcije|redakcij}} nismo mogli obnoviti, saj je bil {{PLURAL:$1|1=njen|njihov}} <code>rev_id</code> že v uporabi.",
        "undelete-nodiff": "Predhodnih različic ne najdem.",
        "undeletebtn": "Obnovi",
        "undeletelink": "poglej/obnovi",
        "undeletedrevisions": "{{PLURAL:$1|obnovljena $1 redakcija|obnovljeni $1 redakciji|obnovljene $1 redakcije|obnovljenih $1 redakcij}}",
        "undeletedrevisions-files": "$1 {{PLURAL:$1|redakcija|redakciji|redakcije|redakcij}} in $2 {{PLURAL:$2|datoteka|datoteki|datoteke|datotek}} {{PLURAL:$1+$2|obnovljena|obnovljeni|obnovljene|obnovljenih}}",
        "undeletedfiles": "{{PLURAL:$1|obnovljena je $1 datoteka|obnovljeni sta $1 datoteki|obnovljene so $1 datoteke|obnovljenih je $1 datotek}}",
-       "cannotundelete": "Obnova je spodletela:\n$1",
+       "cannotundelete": "Nekatere ali vse obnove so spodletele:\n$1",
        "undeletedpage": "'''Obnovili ste stran $1.'''\n\nNedavna brisanja in obnove so zapisani v [[Special:Log/delete|dnevniku brisanja]].",
        "undelete-header": "Glej [[Special:Log/delete|dnevnik brisanja]] za nedavno izbrisane strani.",
        "undelete-search-title": "Iskanje izbrisanih strani",
        "sp-contributions-newbies-sub": "Prispevki novincev",
        "sp-contributions-newbies-title": "Uporabniški prispevki novih računov",
        "sp-contributions-blocklog": "dnevnik blokiranja",
-       "sp-contributions-suppresslog": "zatrti uporabnikovi prispevki",
-       "sp-contributions-deleted": "izbrisani uporabnikovi prispevki",
+       "sp-contributions-suppresslog": "zatrti {{GENDER:$1|uporabnikovi|uporabničini}} prispevki",
+       "sp-contributions-deleted": "izbrisani zatrti {{GENDER:$1|uporabnikovi|uporabničini}} prispevki",
        "sp-contributions-uploads": "naložene datoteke",
        "sp-contributions-logs": "dnevniki",
        "sp-contributions-talk": "pogovor",
index 3867416..26b3ffd 100644 (file)
        "passwordreset-emailelement": "Корисничко име: \n$1\n\nПривремена лозинка: \n$2",
        "passwordreset-emailsentemail": "Ако је ово имејл адреса повезана са Вашим налогом, подсетник о лозинци ће бити послат на имејл.",
        "passwordreset-emailsentusername": "Ако сте навели имејл адресу приликом регистрације, биће послат имејл за ресетовање лозинке.",
-       "passwordreset-emailsent-capture": "Послат је подсетник преко имејла, који је приказан доле.",
-       "passwordreset-emailerror-capture": "Имејл за ресетовање лозинке, приказан испод је послат, али слање {{GENDER:$2|кориснику|корисници}} није успело: $1",
        "changeemail": "Промени или уклони имејл адресу",
        "changeemail-header": "Попуните овај образац да би сте променили Вашу имејл адресу. Ако жели да ускратите приступ било којој имејл адреси Вашем налогу, оставите празно поље за нову имејл адресу приликом попуњавање обрасца.",
-       "changeemail-passwordrequired": "Морате унети лозинку да би потврдили ову измену.",
        "changeemail-no-info": "Морате бити пријављени да бисте приступили овој страници.",
        "changeemail-oldemail": "Тренутна имејл адреса:",
        "changeemail-newemail": "Нова имејл адреса:",
        "undo-nochange": "Изгледа да је измена већ поништена.",
        "undo-summary": "Поништена измена $1 {{GENDER:$2|корисника|кориснице}} [[Special:Contribs/$2|$2]] ([[User talk:$2|разговор]])",
        "undo-summary-username-hidden": "Поништи измену $1 скривеног корисника",
-       "cantcreateaccounttitle": "Не могу да отворим налог",
        "cantcreateaccount-text": "Отварање налога с ове ИП адресе (<strong>$1</strong>) је блокирао/ла [[User:$3|$3]].\n\nРазлог који је навео/ла $3 је <em>$2</em>",
        "cantcreateaccount-range-text": "Отварање налога са ИП адреса у распону <strong>$1</strong>, који укључује и вашу ИП адресу (<strong>$4</strong>) је блокирао/ла [[User:$3|$3]].\n\nРазлог који је навео/ла $3 је <em>$2</em>",
        "viewpagelogs": "Погледај дневнике ове странице",
        "protectlogpage": "Дневник закључавања",
        "protectlogtext": "Испод је списак заштићених страница.\nПогледајте [[Special:ProtectedPages|списак заштићених страница]] за више детаља.",
        "protectedarticle": "је заштитио „[[$1]]“",
-       "modifiedarticleprotection": "је променио степен заштите за „[[$1]]“",
+       "modifiedarticleprotection": "промењен степен заштите за „[[$1]]“",
        "unprotectedarticle": "је скинуо заштиту са странице „[[$1]]“",
        "movedarticleprotection": "је преместио поставке заштите са „[[$2]]“ на „[[$1]]“",
        "protect-title": "Степен заштите за „$1“",
index 9d11bc5..155e8c6 100644 (file)
        "passwordreset-emailelement": "Korisničko ime: \n$1\n\nPrivremena lozinka: \n$2",
        "passwordreset-emailsentemail": "Podsetnik o lozinci je poslat na vašu adresu.",
        "passwordreset-emailsentusername": "Ako ste naveli imejl adresu prilikom registracije, biće poslat imejl za resetovanje lozinke.",
-       "passwordreset-emailsent-capture": "Poslat je podsetnik preko e-pošte (prikazan dole).",
-       "passwordreset-emailerror-capture": "E-poruka za resetovanje lozinke, prikazana ispod je poslata, ali slanje {{GENDER:$2|korisniku|korisnici}} nije uspelo: $1",
        "changeemail": "Promeni ili ukloni e-adresu",
        "changeemail-header": "Promenite e-adresu naloga",
-       "changeemail-passwordrequired": "Morate uneti lozinku da bi potvrdili ovu izmenu.",
        "changeemail-no-info": "Morate biti prijavljeni da biste pristupili ovoj stranici.",
        "changeemail-oldemail": "Trenutna e-adresa:",
        "changeemail-newemail": "Nova e-adresa:",
        "undo-nochange": "Izgleda da je izmena već poništena.",
        "undo-summary": "Poništena izmena $1 {{GENDER:$2|korisnika|korisnice}} [[Special:Contribs/$2|$2]] ([[User talk:$2|razgovor]])",
        "undo-summary-username-hidden": "Poništi izmenu $1 skrivenog korisnika",
-       "cantcreateaccounttitle": "Ne mogu da otvorim nalog",
        "cantcreateaccount-text": "Otvaranje naloga s ove IP adrese (<strong>$1</strong>) je blokirao/la [[User:$3|$3]].\n\nRazlog koji je naveo/la $3 je <em>$2</em>",
        "cantcreateaccount-range-text": "Otvaranje naloga sa IP adresa u rasponu <strong>$1</strong>, koji uključuje i vašu IP adresu (<strong>$4</strong>) je blokirao/la [[User:$3|$3]].\n\nRazlog koji je naveo/la $3 je <em>$2</em>",
        "viewpagelogs": "Pogledaj dnevnike ove stranice",
        "protectlogpage": "Dnevnik zaključavanja",
        "protectlogtext": "Ispod je spisak zaštićenih stranica.\nPogledajte [[Special:ProtectedPages|spisak zaštićenih stranica]] za više detalja.",
        "protectedarticle": "je zaštitio „[[$1]]“",
-       "modifiedarticleprotection": "je promenio stepen zaštite za „[[$1]]“",
+       "modifiedarticleprotection": "promenjen stepen zaštite za „[[$1]]“",
        "unprotectedarticle": "je skinuo zaštitu sa stranice „[[$1]]“",
        "movedarticleprotection": "je premestio postavke zaštite sa „[[$2]]“ na „[[$1]]“",
        "protect-title": "Stepen zaštite za „$1“",
index 02eec73..3cea9f2 100644 (file)
@@ -72,7 +72,8 @@
                        "Mgr",
                        "Matma Rex",
                        "McDutchie",
-                       "Larske"
+                       "Larske",
+                       "Rockyfelle"
                ]
        },
        "tog-underline": "Stryk under länkar:",
        "tagline": "Från {{SITENAME}}",
        "help": "Hjälp",
        "search": "Sök",
-       "search-ignored-headings": "#<!-- lämna denna rad precis som den är --> <pre>\n# Rubriker som kommer att ignoreras av sökningen.\n# Ändringar till detta kommer att gälla så fort sidan med rubriken är indexerad.\n# Du kan tvinga sidan att indexeras om genom att göra en null-redigering.\n# Syntaxen är som följer:\n#  * Allt från ett \"#\" tecken till slutet av raden är en kommentar.\n#  * Varje icke-tom rad är den exakta titeln som ska ignoreras, shiftläge och allt.\nReferenser\nKällor\nExterna länkar\nSe även\n #</pre> <!-- lämna denna rad precis som den är -->",
+       "search-ignored-headings": "#<!-- lämna denna rad precis som den är --> <pre>\n# Rubriker som kommer att ignoreras av sökningen.\n# Ändringar till detta kommer att gälla så fort sidan med rubriken är indexerad.\n# Du kan tvinga sidan att indexeras om genom att göra en null-redigering.\n# Syntaxen är som följer:\n#  * Allt från ett \"#\" tecken till slutet av raden är en kommentar.\n#  * Varje icke-tom rad är den exakta titeln som ska ignoreras, shiftläge och allt.\nReferenser\nExterna länkar\nSe även\n #</pre> <!-- lämna denna rad precis som den är -->",
        "searchbutton": "Sök",
        "go": "Gå till",
        "searcharticle": "Gå till",
        "passwordreset-invalideamil": "Ogiltig e-postadress",
        "passwordreset-nodata": "Varken ett användarnamn eller en e-postadress angavs",
        "changeemail": "Ändra eller ta bort e-postadress",
-       "changeemail-header": "Fyll i detta formulär för att ändra din e-postadress. Lämna fältet för ny e-postadress tomt när du skickar in formuläret om du vill ta bort en associerad e-postadress från ditt konto.",
+       "changeemail-header": "Fyll i detta formulär för att ändra din e-postadress. Om du vill ta bort en associerad e-postadress från ditt konto lämnar du fältet för ny e-postadress tomt när formuläret skickas in.",
        "changeemail-no-info": "Du måste vara inloggad för att komma åt den här sidan direkt.",
        "changeemail-oldemail": "Nuvarande e-postadress:",
        "changeemail-newemail": "Ny e-postadress:",
        "anontalkpagetext": "----<em>Detta är diskussionssidan för en anonym användare som inte ännu skapat ett konto, eller som inte använder det.</em>\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:CreateAccount|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}} 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].",
+       "missing-revision": "Version #$1 av sidan med namnet \"{{FULLPAGENAME}}\" finns inte.\n\nDetta orsakas vanligen genom att en gammal historiklänk följts 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.",
        "userpage-userdoesnotexist-view": "Kontot \"$1\" är inte registrerat.",
        "blocked-notice-logextract": "Användaren är blockerad.\nOrsaken till senaste blockeringen kan ses nedan:",
        "revdelete-selected-text": "{{PLURAL:$1|Vald version|Valda versioner}} av [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Vald filversion|Valda filversioner}} av [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Vald loggåtgärd|Valda loggåtgärder}}:",
-       "revdelete-text-text": "Raderade sidversioner kommer fortfarande synas i sidans historik, men delar av innehållet kommer inte att bli tillgängligt offentligt.",
+       "revdelete-text-text": "Raderade sidversioner kommer fortfarande synas i sidans historik, men delar av innehållet kommer inte att vara tillgängligt offentligt.",
        "revdelete-text-file": "Raderade filversioner kommer fortfarande synas i filens historik, men delar av innehållet kommer inte att bli tillgängligt offentligt.",
        "logdelete-text": "Raderade logghändelser kommer fortfarande synas i loggarna, men delar av innehållet kommer inte att bli tillgängligt offentligt.",
        "revdelete-text-others": "Andra administratörer kommer fortfarande att kunna komma åt det dolda innehållet och återställa det igen om inte ytterligare begränsningar används.",
        "prefs-email": "Alternativ för e-post",
        "prefs-rendering": "Utseende",
        "saveprefs": "Spara",
-       "restoreprefs": "Återgå till standardinställningar",
+       "restoreprefs": "Återgå till standardinställningar (i alla delar)",
        "prefs-editing": "Redigering",
        "rows": "Rader:",
        "columns": "Kolumner:",
        "grant-group-high-volume": "Utför aktivitet av hög volym",
        "grant-group-customization": "Anpassning och inställningar",
        "grant-group-administration": "Utför administrativa åtgärder",
+       "grant-group-private-information": "Få tillgång till privat data om dig",
        "grant-group-other": "Diverse aktivitet",
        "grant-blockusers": "Blockera och avblockera användare",
        "grant-createaccount": "Skapa konton",
        "grant-highvolume": "Hög volymsredigering",
        "grant-oversight": "Dölj användare och censurera versioner",
        "grant-patrol": "Patrullera ändringar på sidor",
+       "grant-privateinfo": "Få tillgång till privat information",
        "grant-protect": "Skydda och ta bort skydd på sidor",
        "grant-rollback": "Rulla tillbaka ändringar på sidor",
        "grant-sendemail": "Skicka e-post till andra användare",
        "recentchanges-legend-plusminus": "(''±123'')",
        "recentchanges-submit": "Visa",
        "rcnotefrom": "Nedan visas {{PLURAL:$5|ändringen|ändringar}} sedan <strong>$3, $4</strong> (upp till <strong>$1</strong> ändringar visas).",
-       "rclistfrom": "Visa ändringar från och med $2 $3",
+       "rclistfrom": "Visa nya ändringar från och med $2 $3",
        "rcshowhideminor": "$1 mindre ändringar",
        "rcshowhideminor-show": "Visa",
        "rcshowhideminor-hide": "Dölj",
        "lockmanager-fail-svr-release": "Kunde inte frigöra låsen på servern $1.",
        "zip-file-open-error": "Ett fel inträffade när filen öppnades för en ZIP-kontroll.",
        "zip-wrong-format": "Den angivna filen var inte en ZIP-fil.",
-       "zip-bad": "Filen är en skadad eller annars oläsbar ZIP fil.\nDen kan inte säkerhetskontrolleras ordentligt.",
-       "zip-unsupported": "Filen är en ZIP-fil som använder ZIP funktioner som inte stöds av MediaWiki.\nDen kan inte säkerhetskontrolleras ordentligt.",
+       "zip-bad": "Filen är en skadad eller annars oläsbar ZIP-fil.\nDen kan inte säkerhetskontrolleras ordentligt.",
+       "zip-unsupported": "Filen är en ZIP-fil som använder ZIP-funktioner som inte stöds av MediaWiki.\nDen kan inte säkerhetskontrolleras ordentligt.",
        "uploadstash": "Temporära lagringsytan för uppladdningar",
        "uploadstash-summary": "Denna sida ger tillgång till filer som är uppladdade (eller håller på att laddas upp) men som ännu inte är publicerade till wikin. Dessa filer är inte synliga för någon annan än den användare som laddade upp dem.",
        "uploadstash-clear": "Rensa temporärt lagrade filer",
        "uploadstash-errclear": "Rensning av filerna misslyckades.",
        "uploadstash-refresh": "Uppdatera listan över filer",
        "uploadstash-thumbnail": "visa miniatyr",
+       "uploadstash-exception": "Kunde inte lagra uppladdning i stash ($1): \"$2\".",
        "invalid-chunk-offset": "Ogiltig segmentsförskjutning",
        "img-auth-accessdenied": "Åtkomst nekad",
        "img-auth-nopathinfo": "PATH_INFO saknas.\nDin server är inte inställd för att ge denna information.\nDen kan vara CGI-baserad och stöder inte img_auth.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Se bildbehörighet.]",
        "apisandbox-api-disabled": "API är inaktiverat på denna webbplats.",
        "apisandbox-intro": "Använd den här sidan för att experimentera med <strong>MediaWikis API för webbtjänster</strong>.\nSe [[mw:API:Main page|API-dokumentationen]] för ytterligare detaljer kring API-användningen. Exempel: [https://www.mediawiki.org/wiki/API#A_simple_example få innehållet från en huvudsida]. Välj en handling för att se fler exempel.\n\nObservera att även om detta är en sandlåda kan handlingar du utför på denna sida påverka wikin.",
        "apisandbox-fullscreen": "Utvidga panel",
-       "apisandbox-fullscreen-tooltip": "Utvidga sandlådspanelen för att fylla webbläsarens fönster.",
+       "apisandbox-fullscreen-tooltip": "Utvidga sandlådspanelen till att fylla webbläsarens fönster.",
        "apisandbox-unfullscreen": "Visa sida",
        "apisandbox-unfullscreen-tooltip": "Förminska sandlådspanelen så MediaWikis navigeringslänkar syns.",
        "apisandbox-submit": "Utför begäran",
        "watchnologin": "Inte inloggad",
        "addwatch": "Lägg till i bevakningslistan",
        "addedwatchtext": "\"[[:$1]]\" har lagts till i din [[Special:Watchlist|bevakningslista]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" och dess associerade sida har lagts till i din [[Special:Watchlist|bevakningslista]].",
        "addedwatchtext-short": "Sidan \"$1\" har lagts till i din bevakningslista.",
        "removewatch": "Ta bort från bevakningslistan",
        "removedwatchtext": "\"[[:$1]]\" och dess diskussionssida har tagits bort från [[Special:Watchlist|din bevakningslista]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" och dess associerade sida har tagits bort från din [[Special:Watchlist|bevakningslista]].",
        "removedwatchtext-short": "Sidan \"$1\" har tagits bort från din bevakningslista.",
        "watch": "Bevaka",
        "watchthispage": "Bevaka denna sida",
        "undeletehistorynoadmin": "Den här sidan har blivit raderad. Anledningen till detta anges i sammanfattningen nedan, tillsammans med uppgifter om de användare som redigerat sidan innan den raderades. Enbart administratörerna har tillgång till den raderade texten.",
        "undelete-revision": "Raderad version av $1 (från den $4 kl. $5) av $3.",
        "undeleterevision-missing": "Versionen finns inte eller är felaktig. Versionen kan ha återställts eller tagits bort från arkivet, du kan också ha följt en felaktig länk.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|En sidversion|$1 sidversioner}} kunde inte återställas, eftersom dess <code>rev_id</code> redan användes.",
        "undelete-nodiff": "Ingen tidigare version hittades.",
        "undeletebtn": "Återställ",
        "undeletelink": "visa/återställ",
        "undeletedrevisions": "{{PLURAL:$1|en version återställd|$1 versioner återställda}}",
        "undeletedrevisions-files": "$1 {{PLURAL:$1|version|versioner}} och $2 {{PLURAL:$2|fil|filer}} återställda",
        "undeletedfiles": "{{PLURAL:$1|en fil återställd|$1 filer återställda}}",
-       "cannotundelete": "Återställning misslyckades:\n$1",
+       "cannotundelete": "En del eller alla återställningar misslyckades:\n$1",
        "undeletedpage": "'''$1 har återställts'''\n\nSe [[Special:Log/delete|raderingsloggen]] för en förteckning över de senaste raderingarna och återställningarna.",
        "undelete-header": "Se [[Special:Log/delete|raderingsloggen]] för nyligen raderade sidor.",
        "undelete-search-title": "Sök efter raderade sidor",
        "sp-contributions-newbies-sub": "Från nya konton",
        "sp-contributions-newbies-title": "Bidrag från nya konton",
        "sp-contributions-blocklog": "blockeringslogg",
-       "sp-contributions-suppresslog": "undanhållna användarbidrag",
-       "sp-contributions-deleted": "raderade användarbidrag",
+       "sp-contributions-suppresslog": "censurerade {{GENDER:$1|användarbidrag}}",
+       "sp-contributions-deleted": "raderade {{GENDER:$1|användarbidrag}}",
        "sp-contributions-uploads": "uppladdningar",
        "sp-contributions-logs": "loggar",
        "sp-contributions-talk": "diskussion",
index ccd1f6c..f80b4cd 100644 (file)
        "passwordreset-emailelement": "பயனர் பெயர்:  \n$1\n\nதற்காலிகக் கடவுச்சொல்: \n$2",
        "passwordreset-emailsentemail": "இது உங்கள் கணக்கிற்கான பதிவு செய்யப்பட்ட மின்னஞ்சலாயின், கடவுச்சொல் மீட்டமைக்கும் மின்னஞ்சல் அனுப்பப்படும்",
        "passwordreset-emailsentusername": "இது உங்கள் கணக்கிற்கான பதிவு செய்யப்பட்ட மின்னஞ்சலாயின், கடவுச்சொல் மீட்டமைக்கும் மின்னஞ்சல் அனுப்பப்படும்",
-       "passwordreset-emailsent-capture": "கீழே காண்பிக்கப்பட்டுள்ளது போல் கடவுச்சொல் மீட்டமைக்கும் மின்னஞ்சல் அனுப்பப்பட்டது.",
-       "passwordreset-emailerror-capture": "கடவுச்சொல் மீட்டமைக்கும் மின்னஞ்சல்  உருவாக்கப்பட்டுவிட்டது, அது கீழே காட்டப்பட்டுள்ளது, ஆனால் {{GENDER:$2|user}} அனுப்புவது தோல்வியடைந்தது:$1",
        "changeemail": "மின்னஞ்சல் முகவரியை மாற்று / நீக்கு",
        "changeemail-header": "இந்த படிவத்தை உங்கள் மின்னஞ்சல் முகவரியை மாற்ற பூர்த்தி செய்யவும். நீங்கள் இந்த மாற்றத்தை உறுதிசெய்ய உங்கள் கடவுச்சொல்லை உள்ளிட வேண்டிவரும்.  உங்கள் கணக்கிலிருந்து ஏதாவது மின்னஞ்சலை நீக்க விரும்பினால், படிவத்தை சமர்ப்பிக்கும்போது மின்னஞ்சல் முகவரியை காலியாக விடவும்.",
-       "changeemail-passwordrequired": "இந்த மாற்றத்தை சேமிக்க உங்கள் கடவுச்சொல் தேவைப்படுகிறது.",
        "changeemail-no-info": "இப்பக்கத்தை நேரடியாக அணுகுவதற்கு நீங்கள் புகுபதிகை செய்திருக்கவேண்டும்.",
        "changeemail-oldemail": "தற்பொழுதுள்ள மின்னஞ்சல் முகவரி:",
        "changeemail-newemail": "புதிய மின்னஞ்சல் முகவரி:",
        "minoredit": "இது ஒரு சிறு தொகுப்பு",
        "watchthis": "இக்கட்டுரையைக் கவனிக்கவும்",
        "savearticle": "பக்கத்தைச் சேமி",
+       "publishpage": "பக்கத்தைப் பதிப்பிடுக",
+       "publishchanges": "மாற்றங்களைப் பதிப்பிடுக",
        "preview": "முன்தோற்றம்",
        "showpreview": "முன்தோற்றம் காட்டு",
        "showdiff": "மாற்றங்களைக் காட்டு",
        "undo-nochange": "திருத்தங்கள் ஏற்கனவே நீக்கப்பட்டதாக தோன்றுகிறது.",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|Talk]]) பயனரால் செய்யப்பட்ட திருத்தம் $1 இல்லாது செய்யப்பட்டது",
        "undo-summary-username-hidden": "மறை பயனரால் செய்யப்பட்ட மீள்பார்வை $1 ஐ நீக்கு",
-       "cantcreateaccounttitle": "கணக்கைத் தொடக்க முடியாது",
        "cantcreateaccount-text": "இந்த இணைய விதிமுறை இலக்க முகவரியிலிருந்து (IP address) ('''$1''') பயனர் கணக்குகள் தொடங்குவதை பயனர் [[User:$3|$3]] தடை செய்துள்ளார்.\n\nஇதற்காக $3 கொடுத்துள்ள காரணங்கள்  ''$2''",
        "cantcreateaccount-range-text": "இந்த இணைய விதிமுறை இலக்க முகவரி அளவில் உள்ள(IP address) <strong>$1</strong>,  உங்கள் முகவரி (<strong>$4</strong>) உட்பட, பயனர் கணக்குகள் தொடங்குவதை [[User:$3|$3]] தடை செய்துள்ளார்.\n\nஇதற்காக $3 கொடுத்துள்ள காரணங்கள் <em>$2</em>",
        "viewpagelogs": "இப்பக்கத்துக்கான பதிகைகளைப் பார்",
index f9744d9..8368ac5 100644 (file)
@@ -31,6 +31,7 @@
        "tog-hideminor": "ఇటీవలి మార్పులలో చిన్న మార్పులను దాచు",
        "tog-hidepatrolled": "ఇటీవలి మార్పులలో నిఘా ఉన్న మార్పులను దాచు",
        "tog-newpageshidepatrolled": "కొత్త పేజీల జాబితా నుంచి నిఘా ఉన్న పేజీలను దాచు",
+       "tog-hidecategorization": "పేజీ వర్గీకరణను దాచు",
        "tog-extendwatchlist": "కేవలం ఇటీవలి మార్పులే కాక, మార్పులన్నీ చూపించటానికి నా వీక్షణా జాబితాను పెద్దది చేయి",
        "tog-usenewrc": "ఇటీవలి మార్పులు మరియు వీక్షణ జాబితాలలో మార్పులను పేజీ వారీగా చూపించు",
        "tog-numberheadings": "శీర్షికలకు అప్రమేయంగా వరుస సంఖ్యలు చేర్చు",
@@ -41,6 +42,7 @@
        "tog-watchdefault": "నేను మార్చే పేజీలను మరియు దస్త్రాలను నా వీక్షణ జాబితాకు చేర్చు",
        "tog-watchmoves": "నేను తరలించిన పేజీలను మరియు దస్త్రాలను నా వీక్షణ జాబితాకు చేర్చు",
        "tog-watchdeletion": "నేను తొలగించిన పేజీలను మరియు దస్త్రాలను నా వీక్షణ జాబితాకు చేర్చు",
+       "tog-watchuploads": "నేను ఎక్కించే కొత్త దస్త్రాలను నా వీక్షణ జాబితాకు చేర్చు",
        "tog-watchrollback": "నేను పునస్స్థాపించిన పేజీలను నా వీక్షణ జాబితాకు జోడించు",
        "tog-minordefault": "అప్రమేయంగా నా మార్పులను చిన్న మార్పులుగా గుర్తించు",
        "tog-previewontop": "వ్యాసం మార్పుల మునుచూపును ఎడిట్ పెట్టె పైన చూపు",
@@ -60,6 +62,7 @@
        "tog-watchlisthideliu": "లాగిన్ ఐన వాడుకరులు చేసే మార్పులను వీక్షణా జాబితాలో చూపించకు",
        "tog-watchlisthideanons": "అజ్ఞాత వాడుకరుల మార్పులను వీక్షణా జాబితాలో చూపించకు",
        "tog-watchlisthidepatrolled": "నిఘా ఉన్న మార్పులను వీక్షణజాబితా నుంచి దాచిపెట్టు",
+       "tog-watchlisthidecategorization": "పేజీ వర్గీకరణను దాచు",
        "tog-ccmeonemails": "నేను ఇతర వాడుకరులకు పంపించే ఈ-మెయిళ్ల కాపీలను నాకు కూడా పంపు",
        "tog-diffonly": "తేడాల కింద, పేజీలోని సమాచారాన్ని చూపించొద్దు",
        "tog-showhiddencats": "దాచిన వర్గాలను చూపించు",
        "protectedinterface": "ఈ పేజీ, ఈ వికీ యొక్క సాఫ్టువేరు ఇంటరుఫేసుకు చెందిన టెక్స్టును అందిస్తుంది. దుశ్చర్యల నివారణ కోసమై దీన్ని సంరక్షించాం. వికీలన్నిటిలోను అనువాదాలను చేర్చాలన్నా, మార్చాలన్నా మీడియావికీ స్థానికీకరణ ప్రాజెక్టైన [https://translatewiki.net/ translatewiki.net] ను వాడండి.",
        "editinginterface": "<strong>హెచ్చరిక:</strong> సాఫ్టువేరుకు ఇంటరుఫేసు టెక్స్టును అందించేందుకు పనికొచ్చే పేజీని మీరు సరిదిద్దుతున్నారు.\nఈ పేజీలో చేసే మార్పుల వల్ల ఇతర వాడుకరులకు ఇంటరుఫేసు కనబడే విధానంలో తేడావస్తుంది.",
        "translateinterface": "అన్ని వికీలలో కనిపించేలా అనువాదాలు చేర్చాలన్నా, మార్చాలన్నా, దయచేసి [https://translatewiki.net/ translatewiki.net] ను వాడండి. ఇది మీడియావికీ స్థానికీకరణ ప్రాజెక్టు.",
-       "cascadeprotected": "à°\95à°¿à°\82ది {{PLURAL:$1|à°ªà±\87à°\9cà±\80ని|à°ªà±\87à°\9cà±\80లనà±\81}} à°\95ాసà±\8dà°\95à±\87à°¡à°¿à°\82à°\97à±\81 à°\86à°ªà±\8dà°·à°¨à±\81à°¤à±\8b à°\9aà±\87సి à°¸à°\82à°°à°\95à±\8dà°·à°¿à°\82à°\9aారà±\81. à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤ à°ªà±\87à°\9cà±\80, à°\88 à°ªà±\87à°\9cà±\80à°²à±\8dà°²à±\8b à°\87à°\82à°\95à±\8dà°²à±\82à°¡à±\81 à°\85యి à°\89à°\82ది à°\95ాబà°\9fà±\8dà°\9fà°¿, à°¦à°¿à°¦à±\8dà°¦à±\81బాà°\9fà±\81 à°\9aà±\87à°¸à±\87 à°µà±\80à°²à±\81 à°²à±\87à°\95à±\81à°\82à°¡à°¾ à°\87ది à°\95à±\82à°¡à°¾ à°°à°\95à±\8dషణలà±\8b à°\89à°\82ది.\n$2",
+       "cascadeprotected": "à°\95à°¿à°\82ది {{PLURAL:$1|à°ªà±\87à°\9cà±\80ని|à°ªà±\87à°\9cà±\80లనà±\81}} à°\95ాసà±\8dà°\95à±\87à°¡à°¿à°\82à°\97à±\81 à°\86à°ªà±\8dà°·à°¨à±\81à°¤à±\8b à°¸à°\82à°°à°\95à±\8dà°·à°¿à°\82à°\9aబడిà°\82ది. à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤ à°ªà±\87à°\9cà±\80, à°\88 à°ªà±\87à°\9cà±\80à°²à±\8dà°²à±\8b à°\9fà±\8dరానà±\8dà°¸à±\8dâ\80\8cà°\95à±\8dà°²à±\82à°¡à±\81 à°\85యి à°\89à°\82ది à°\95ాబà°\9fà±\8dà°\9fà°¿, à°¦à°¿à°¦à±\8dà°¦à±\81బాà°\9fà±\81 à°\9aà±\87à°¸à±\87 à°µà±\80à°²à±\81 à°²à±\87à°\95à±\81à°\82à°¡à°¾ à°\87ది à°\95à±\82à°¡à°¾ à°°à°\95à±\8dషణలà±\8b à°\89à°\82ది:\n$2",
        "namespaceprotected": "'''$1''' నేంస్పేసులో మార్పులు చేయటానికి మీకు అనుమతి లేదు.",
        "customcssprotected": "ఈ CSS పేజీని మార్చేందుకు మీకు అనుమతి లేదు. ఎందుకంటే వేరే వాడుకరి యొక్క వ్యక్తిగత సెట్టింగులు అందులో ఉన్నాయి.",
        "customjsprotected": "ఈ JavaScript పేజీని మార్చేందుకు మీకు అనుమతి లేదు. ఎందుకంటే వేరే వాడుకరి యొక్క వ్యక్తిగత సెట్టింగులు అందులో ఉన్నాయి.",
        "virus-scanfailed": "స్కాన్ విఫలమైంది (సంకేతం $1)",
        "virus-unknownscanner": "అజ్ఞాత యాంటీవైరస్:",
        "logouttext": "<strong>ఇప్పుడు మీరు లాగౌటయ్యారు.</strong>\n\nఅయితే, ఓ గమనిక.. మీ విహారిణిలోని కోశాన్ని ఖాళీ చేసేవరకూ కొన్ని పేజీలు మీరింకా లాగినై ఉన్నట్లుగానే చూపించవచ్చు.",
+       "cannotlogoutnow-title": "ఇప్పుడు లాగౌట్ అవలేరు",
+       "cannotlogoutnow-text": "$1 ను వాడుతూండగా లాగౌట్ అవలేరు.",
        "welcomeuser": "స్వాగతం, $1!",
        "welcomecreation-msg": "మీ ఖాతాని సృష్టించాం.\nమీ [[Special:Preferences|{{SITENAME}} అభిరుచులను]] మార్చుకోవడం మరువకండి.\nతెలుగు వికీపీడియాలో తెలుగులోనే రాయాలి. వికీలో రచనలు చేసే ముందు, కింది సూచనలను గమనించండి.\nతెలుగు {{SITENAME}}లో తెలుగులోనే రాయాలి. వికీలో రచనలు చేసే ముందు, కింది సూచనలను గమనించండి.\n*వికీని త్వరగా అర్థం చేసుకునేందుకు [[వికీపీడియా:5 నిమిషాల్లో వికీ|5 నిమిషాల్లో వికీ]] పేజీని చూడండి.\n*తెలుగులో రాసేందుకు ఇంగ్లీషు అక్షరాల ఉచ్ఛారణతో తెలుగు టైపు చేసే [[వికీపీడియా:టైపింగు సహాయం| టైపింగ్  సహాయం]] వాడవచ్చు. మరిన్ని ఉపకరణాల కొరకు [[కీ బోర్డు]] మరియు   తెరపై తెలుగు సరిగా లేకపోతే[[వికీపీడియా:Setting up your browser for Indic scripts|ఈ పేజీ]]  చూడండి.",
        "yourname": "వాడుకరి పేరు:",
        "remembermypassword": "ఈ కంప్యూటరులో నా ప్రవేశాన్ని గుర్తుంచుకో (గరిష్ఠంగా $1 {{PLURAL:$1|రోజు|రోజుల}}కి)",
        "userlogin-remembermypassword": "నన్ను లాగిన్ చేసే ఉంచు",
        "userlogin-signwithsecure": "సురక్షిత కనెక్షను వాడు",
+       "cannotloginnow-title": "ఇప్పుడు లాగిన్ అవలేరు",
+       "cannotloginnow-text": "$1 ను వాడుతూండగా లాగౌట్ అవలేరు.",
        "yourdomainname": "మీ డోమైను",
        "password-change-forbidden": "ఈ వికీలో మీరు సంకేతపదాలను మార్చలేరు.",
        "externaldberror": "డేటాబేసు అధీకరణలో లోపం జరిగింది లేదా మీ బయటి ఖాతాను తాజాకరించడానికి మీకు అనుమతి లేదు.",
        "login": "లాగినవండి",
+       "login-security": "మీ ఐడీని ధ్రువపరచుకోండి",
        "nav-login-createaccount": "లాగినవండి / ఖాతాని సృష్టించుకోండి",
        "userlogin": "లాగినవండి / ఖాతాను సృష్టించుకోండి",
        "userloginnocreate": "లాగినవండి",
        "userlogin-resetpassword-link": "మీ సంకేతపదాన్ని మర్చిపోయారా?",
        "userlogin-helplink2": "లాగినవడంలో సహాయం",
        "userlogin-loggedin": "మీరు ఈసరికే {{GENDER:$1|$1}} గా లాగిన్ అయి ఉన్నారు.\nవేరే వాడుకరిగా లాగినయేందుకు కింది ఫారమును వాడండి.",
+       "userlogin-reauth": "మీరు {{GENDER:$1|$1}} అని నిర్ధారించుకునేందుకు మళ్ళీ లాగిన్ అవాలి.",
        "userlogin-createanother": "మరొక ఖాతాను సృష్టించండి",
        "createacct-emailrequired": "ఈమెయిలు చిరునామా",
        "createacct-emailoptional": "ఈమెయిలు చిరునామా (ఐచ్చికం)",
        "createacct-reason-ph": "మీరు మరో ఖాతాను ఎందుకు సృష్టించుకుంటున్నారు",
        "createacct-submit": "మీ ఖాతాను సృష్టించుకోండి",
        "createacct-another-submit": "ఖాతాను సృష్టించు",
+       "createacct-continue-submit": "ఖాతా సృష్టిని కొనసాగించండి",
+       "createacct-another-continue-submit": "ఖాతా సృష్టిని కొనసాగించండి",
        "createacct-benefit-heading": "{{SITENAME}}ను తయారుచేస్తున్నది మీలాంటి వారే.",
        "createacct-benefit-body1": "{{PLURAL:$1|మార్పు|మార్పులు}}",
        "createacct-benefit-body2": "{{PLURAL:$1|పేజీ|పేజీలు}}",
        "createacct-benefit-body3": "ఇటీవలి {{PLURAL:$1|సమర్పకుడు|సమర్పకులు}}",
        "badretype": "మీరు ఇచ్చిన రెండు సంకేతపదాలు ఒకదానితో మరొకటి సరిపోలడం లేదు.",
+       "usernameinprogress": "ఈ వాడుకరి పేరుతో ఖాతా సృష్టించుకోవడం పురోగతిలో ఉంది. కాస్త ఆగండి.",
        "userexists": "ఇచ్చిన వాడుకరిపేరు ఇప్పటికే వాడుకలో ఉంది.\nవేరే పేరును ఎంచుకోండి.",
        "loginerror": "లాగిన్ లోపం",
        "createacct-error": "ఖాతా సృష్టించడంలో లోపం",
        "nocookiesnew": "ఖాతాని సృష్టించాం, కానీ మీరు ఇంకా లోనికి ప్రవేశించలేదు.\nవాడుకరుల ప్రవేశానికి {{SITENAME}} కూకీలను వాడుతుంది.\nమీరు కూకీలని అచేతనం చేసివున్నారు.\nదయచేసి వాటిని చేతనంచేసి, మీ కొత్త వాడుకరి పేరు మరియు సంకేతపదాలతో లోనికి ప్రవేశించండి.",
        "nocookieslogin": "వాడుకరుల ప్రవేశానికై {{SITENAME}} కూకీలను వాడుతుంది.\nమీరు కుకీలని అచేతనం చేసివున్నారు.\nవాటిని చేతనంచేసి ప్రయత్నించండి.",
        "nocookiesfornew": "మూలాన్ని కనుక్కోలేకపోయాం కాబట్టి, ఈ వాడుకరి ఖాతాను సృష్టించలేకపోయాం.\nమీ కంప్యూటర్లో కూకీలు చేతనమై ఉన్నాయని నిశ్చయించుకొని, ఈ పేజీని తిరిగి లోడు చేసి, మళ్ళీ ప్రయత్నించండి.",
+       "createacct-loginerror": "ఖాతా విజయవంతంగా సృష్టించబడింది, కానీ ఆటోమాటిగ్గా లాగిన్ అవలేరు.  స్వయంగా మీరే [[Special:UserLogin|లాగినవండి]].",
        "noname": "మీరు సరైన వాడుకరి పేరు ఇవ్వలేదు.",
-       "loginsuccesstitle": "à°ªà±\8dà°°à°µà±\87à°¶à°\82 à°µà°¿à°\9cయవà°\82తమà±\88à°\82ది",
+       "loginsuccesstitle": "లాà°\97ినయà±\8dయారà±\81",
        "loginsuccess": "<strong>మీరు ఇప్పుడు {{SITENAME}}లోనికి \"$1\"గా ప్రవేశించారు.</strong>",
-       "nosuchuser": "\"$1\" à°\85à°¨à±\87 à°ªà±\87à°°à±\81à°¤à±\8b à°µà°¾à°¡à±\81à°\95à°°à±\81à°²à±\81 à°²à±\87à°°à±\81.\nవాడà±\81à°\95à°°à°¿ పేర్లు కేస్ సెన్సిటివ్.\nఅక్షరక్రమం సరిచూసుకోండి, లేదా [[Special:CreateAccount|కొత్త ఖాతా సృష్టించుకోండి]].",
+       "nosuchuser": "\"$1\" à°\85à°¨à±\87 à°ªà±\87à°°à±\81à°¤à±\8b à°µà°¾à°¡à±\81à°\95à°°à°¿ à°\8eవరà±\82 à°²à±\87à°°à±\81.\nవాడà±\81à°\95à°°à°¿పేర్లు కేస్ సెన్సిటివ్.\nఅక్షరక్రమం సరిచూసుకోండి, లేదా [[Special:CreateAccount|కొత్త ఖాతా సృష్టించుకోండి]].",
        "nosuchusershort": "\"$1\" పేరుతో వాడుకరి ఎవరూ లేరు. పేరు సరి చూసుకోండి.",
        "nouserspecified": "వాడుకరి పేరును తప్పనిసరిగా ఇవ్వాలి.",
        "login-userblocked": "ఈ వాడుకరిని నిరోధించారు. ప్రవేశానికి అనుమతి లేదు.",
        "wrongpasswordempty": "ఖాళీ సంకేతపదం ఇచ్చారు. మళ్ళీ ప్రయత్నించండి.",
        "passwordtooshort": "సంకేతపదం కనీసం {{PLURAL:$1|1 అక్షరం|$1 అక్షరాల}} నిడివి ఉండాలి.",
        "passwordtoolong": "సంకేతపదంలో {{PLURAL:$1|1 అక్షరం|$1 అక్షరాల}} కన్నా ఎక్కువ ఉండకూడదు.",
+       "passwordtoopopular": "మామూలుగా వాడే సంకేతపదాలను వాడే వీల్లేదు. మరింత విశిష్టమైన సంకేతపదాన్ని ఎంచుకోండి.",
        "password-name-match": "మీ సంకేతపదం మీ వాడుకరిపేరుకి భిన్నంగా ఉండాలి.",
        "password-login-forbidden": "ఈ వాడుకరిపేరు మరియు సంకేతపదాలను ఉపయోగించడం నిషిద్ధం.",
        "mailmypassword": "సంకేతపదాన్ని మార్చు",
        "noemail": "వాడుకరి \"$1\" కు ఈమెయిలు చిరునామా నమోదయి లేదు.",
        "noemailcreate": "మీరు సరైన ఈమెయిల్ చిరునామాని ఇవ్వాలి",
        "passwordsent": "\"$1\" కొరకు నమోదైన ఈ-మెయిలు చిరునామాకి కొత్త సంకేతపదాన్ని పంపించాం.\nఅది అందిన తర్వాత ప్రవేశించి చూడండి.",
-       "blocked-mailpassword": "దిదà±\8dà°¦à±\81బాà°\9fà±\8dà°²à±\81 à°\9aà±\86à°¯à±\8dà°¯à°\95à±\81à°\82à°¡à°¾ à°®à±\80 à°\90à°ªà±\80à°\85à°¡à±\8dà°°à°¸à±\81à°¨à±\81 à°¨à°¿à°°à±\8bధిà°\82à°\9aà°¾à°\82. à°\85à°\82à°\9aà±\87à°¤, à°¦à±\81à°¶à±\8dà°\9aà°°à±\8dయల à°¨à°¿à°µà°¾à°°à°£ à°\95à±\8bà°¸à°\82 à°\97ానà±\81, à°®à°°à°\9aà°¿à°ªà±\8bయిన à°¸à°\82à°\95à±\87తపదానà±\8dని à°ªà±\8aà°\82à°¦à±\87 à°µà±\80à°²à±\81 à°\88 à°\90à°ªà±\80à°\95à°¿ à°²à±\87à°¦à±\81.",
+       "blocked-mailpassword": "దిద్దుబాట్లు చెయ్యకుండా మీ ఐపీఅడ్రసును నిరోధించాం. దుశ్చర్యల నివారణ కోసం గాను, మరచిపోయిన సంకేతపదాన్ని పొందే వీలు ఈ ఐపీకి లేదు.",
        "eauthentsent": "ఇచ్చిన ఈ-మెయిలు అడ్రసుకు ధృవీకరణ మెయిలు పంపించాం.\nఇకపై మేము ఆ ఖాతాకు మెయిలు పంపాలంటే, ముందుగా మీరు ఆ మెయిల్లో సూచించినట్లుగా చేసి, ఈ చిరునామా మీదేనని ధృవీకరించాలి.",
        "throttled-mailpassword": "గడచిన {{PLURAL:$1|ఒక గంటలో|$1 గంటల్లో}} సంకేతపదం మార్చినట్లుగా ఒక మెయిలు పంపించివున్నాం.\nదుశ్చర్యలను నివారించేందుకు గాను, {{PLURAL:$1|ఒక గంటకు|$1 గంటలకు}} ఒక్కసారి మాత్రమే సంకేతపదం మార్పు మెయిలు పంపిస్తాము.",
        "mailerror": "మెయిలు పంపించడంలో లోపం: $1",
        "createacct-another-realname-tip": "అసలు పేరు ఐచ్ఛికం.\nమీరు దాన్ని ఇస్తే, వాడుకరి పనుల శ్రేయస్సు ఆ పేరుకు ఆపాదించబడుతుంది.",
        "pt-login": "లాగినవండి",
        "pt-login-button": "లాగినవండి",
+       "pt-login-continue-button": "లాగిన్ అవడాన్ని కొనసాగించండి",
        "pt-createaccount": "ఖాతా సృష్టించుకోండి",
        "pt-userlogout": "లాగౌటవండి",
        "php-mail-error-unknown": "PHP యొక్క mail() ఫంక్షన్‍లో ఏదో తెలియని లోపం దొర్లింది",
        "newpassword": "కొత్త సంకేతపదం:",
        "retypenew": "సంకేతపదం, మళ్ళీ",
        "resetpass_submit": "సంకేతపదాన్ని మార్చి లాగినవండి",
-       "changepassword-success": "à°®à±\80 à°¸à°\82à°\95à±\87తపదà°\82 à°µà°¿à°\9cయవà°\82à°¤à°\82à°\97à°¾ à°®à°¾à°°à±\8dà°\9aబడిà°\82ది.",
+       "changepassword-success": "à°®à±\80 à°¸à°\82à°\95à±\87తపదà°\82 à°®à°¾à°°à±\8dà°\9aబడిà°\82ది!",
        "changepassword-throttled": "కొద్దిసేపటిగా మీరు చాలా లాగిన్ ప్రయత్నాలు చేసారు.\nమళ్ళీ ప్రయత్నించే ముందు $1 ఆగండి.",
+       "botpasswords-label-appid": "బాట్ పేరు:",
+       "botpasswords-label-create": "సృష్టించు",
+       "botpasswords-label-update": "తాజాకరించు",
+       "botpasswords-label-cancel": "రద్దుచేయి",
+       "botpasswords-label-delete": "తొలగించు",
+       "botpasswords-label-resetpassword": "సంకేతపదాన్ని మార్చు",
+       "botpasswords-label-grants": "వర్తించే గ్రాంట్లు:",
+       "botpasswords-label-restrictions": "వాడుక పరిమితులు:",
+       "botpasswords-label-grants-column": "గ్రాంటు చేసాం",
+       "botpasswords-bad-appid": "బాట్ పేరు \"$1\" సరైనది కాదు.",
+       "botpasswords-insert-failed": "బాట్ పేరు \"$1\"ను చేర్చలేకపోయాం. దీన్ని ఇంతకు ముందే చేర్చారా ఏంటి?",
+       "botpasswords-update-failed": "బాట్ పేరు \"$1\" ను తాజాకరించలేకపోయాం. దీన్ని తొలగించారా?",
+       "botpasswords-created-title": "బాట్ సంకేతపదాన్ని సృష్టించాం",
+       "botpasswords-created-body": "వాడుకరి \"$2\" కు చెందిన \"$1\" అనే బాట్‌కు బాట్ సంకేతపదాన్ని సృష్టించాం.",
+       "botpasswords-updated-title": "బాట్ సంకేతపదాన్ని తాజాకరించాం",
+       "botpasswords-updated-body": "వాడుకరి \"$2\" కు చెందిన \"$1\" అనే బాట్‌ యొక్క బాట్ సంకేతపదాన్ని తాజాకరించాం.",
+       "botpasswords-deleted-title": "బాట్ సంకేతపదాన్ని తొలగించాం",
+       "botpasswords-deleted-body": "వాడుకరి \"$2\" కు చెందిన \"$1\" అనే బాట్‌ యొక్క బాట్ సంకేతపదాన్ని తొలగించాం.",
+       "botpasswords-newpassword": "<strong>$1</strong> తో లాగినయేందుకు కొత్త సంకేతపదం <strong>$2</strong>. <em>భావి ఉపయోగం కోసం దీన్ని జాగ్రత్త చేసుకోండి.</em>",
+       "botpasswords-not-exist": "వాడుకరి \"$1\" కి \"$2\" అనే బాట్ సంకేతపదం లేదు.",
        "resetpass_forbidden": "సంకేతపదాలను మార్చటం కుదరదు",
+       "resetpass_forbidden-reason": "సంకేతపదాలు మార్చజాలరు: $1",
        "resetpass-no-info": "ఈ పేజీని నేరుగా చూడటానికి మీరు లాగినయి వుండాలి.",
        "resetpass-submit-loggedin": "సంకేతపదాన్ని మార్చు",
        "resetpass-submit-cancel": "రద్దుచేయి",
-       "resetpass-wrong-oldpass": "తపà±\8dà°ªà±\81à°¡à±\81 à°¤à°¾à°¤à±\8dà°\95ాలిà°\95 à°²à±\87దా à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤ à°¸à°\82à°\95à±\87తపదà°\82.\nà°®à±\80à°°à±\81 à°®à±\80 à°¸à°\82à°\95à±\87తపదానà±\8dని à°\87à°ªà±\8dà°ªà°\9fà°¿à°\95à±\87 à°µà°¿à°\9cయవà°\82à°¤à°\82à°\97à°¾ à°®à°¾à°°à±\8dà°\9aà±\81à°\95à±\8aనివà±\81à°\82à°¡à°µà°\9aà±\8dà°\9aà±\81 à°²à±\87దా à°\95à±\8aà°¤à±\8dà°¤ à°¤à°¾à°¤à±\8dà°\95ాలిà°\95 à°¸à°\82à°\95à±\87తపదà°\82 à°\95à±\8bà°¸à°\82 à°\85à°­à±\8dయరà±\8dథిà°\82à°\9aారు.",
+       "resetpass-wrong-oldpass": "తపà±\8dà°ªà±\81à°¡à±\81 à°¤à°¾à°¤à±\8dà°\95ాలిà°\95 à°²à±\87దా à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤ à°¸à°\82à°\95à±\87తపదà°\82.\nà°®à±\80à°°à±\81 à°®à±\80 à°¸à°\82à°\95à±\87తపదానà±\8dని à°\87à°ªà±\8dà°ªà°\9fà°¿à°\95à±\87 à°®à°¾à°°à±\8dà°\9aà±\81à°\95à±\8aని à°\89à°\82à°¡à°µà°\9aà±\8dà°\9aà±\81 à°²à±\87దా à°\95à±\8aà°¤à±\8dà°¤ à°¤à°¾à°¤à±\8dà°\95ాలిà°\95 à°¸à°\82à°\95à±\87తపదà°\82 à°\95à±\8bà°¸à°\82 à°\85à°­à±\8dయరà±\8dథిà°\82à°\9aà°¿ à°\89à°\82à°¡à°µà°\9aà±\8dà°\9aు.",
        "resetpass-recycled": "మీ ప్రస్తుత సంకేతపదాన్ని వేరే సంకేతపదంతో మార్చుకోండి",
        "resetpass-temp-emailed": "మీరు మీ ఈమెయిలుకు పంపించిన తాత్కాలిక కోడుతో లాగినయ్యారు. లాగిన్ను పూర్తి చేసేందుకు, ఇక్కడ మీరు తప్పనిసరిగా సంకేతపదం మార్చుకోవాలి:",
        "resetpass-temp-password": "తాత్కాలిక సంకేతపదం:",
        "passwordreset-emailtext-ip": "ఎవరో (బహుశా మీరే, ఐపీ అడ్రసు $1 నుంచి)  {{SITENAME}} ($4) లో మీ సంకేతపదాన్ని మార్చమంటూ అడిగారు. కింది వాడుకరి {{PLURAL:$3|ఖాతా|ఖాతాలు}}\nఈ ఈమెయిలు చిరునామాతో అనుసంధింపబడి ఉన్నాయి:\n\n$2\n\n{{PLURAL:$3|ఈ సంకేతపదానికి|ఈ సంకేతపదాలకు}} {{PLURAL:$5|ఒక్కరోజులో|$5 రోజుల్లో}} కాలం చెల్లుతుంది.\nఇప్పుడు మీరు లాగినై కొత్త సంకేతపదాన్ని ఎంచుకోవాల్సి ఉంటుంది. ఈ అభ్యర్ధన చేసింది మరెవరైనా అయినా, లేక మీ అసలు సంకేతపదం మీకు గుర్తొచ్చి దాన్ని మార్చాల్సిన అవసరం లేదని అనుకున్నా, మీరీ సందేశాన్ని పట్టించుకోనక్కర్లేదు. పాత సంకేతపదాన్నే వాడుకోవచ్చు.",
        "passwordreset-emailtext-user": "{{SITENAME}} లోని వాడుకరి $1, {{SITENAME}} ($4) లోని మీ సంకేతపదాన్ని మార్చమంటూ అడిగారు. కింది వాడుకరి {{PLURAL:$3|ఖాతా|ఖాతాలు}}\nఈ ఈమెయిలు అడ్రసుతో అనుసంధింపబడి ఉన్నాయి:\n\n$2\n\n{{PLURAL:$3|ఈ తాత్కాలిక సంకేతపదానికి|ఈ తాత్కాలిక సంకేతపదాలకు}} {{PLURAL:$5|ఒక్క రోజులో|$5 రోజుల్లో}} కాలం చెల్లుతుంది.\nఇప్పుడు మీరు లాగినై కొత్త సంకేతపదాన్ని ఎంచుకోవాల్సి ఉంటుంది. ఈ అభ్యర్ధన చేసింది మరెవరైనా అయినా, లేక మీ అసలు సంకేతపదం మీకు గుర్తొచ్చి దాన్ని మార్చాల్సిన అవసరం లేదని అనుకున్నా, మీరీ సందేశాన్ని పట్టించుకోనక్కర్లేదు. పాత సంకేతపదాన్నే వాడుకోవచ్చు.",
        "passwordreset-emailelement": "వాడుకరిపేరు: \n$1\n\nతాత్కాలిక సంకేతపదం: \n$2",
-       "passwordreset-emailsentemail": "సంకేతపదం మార్పు ఈమెయిలును పంపించాం.",
-       "changeemail": "ఈ-మెయిలు చిరునామా మార్పు",
-       "changeemail-header": "ఖాతా ఈ-మెయిల్ చిరునామాని మార్చండి",
+       "passwordreset-emailsentemail": "ఈ ఈమెయిలు చిరునామా మీ ఖాతాకు అనుసంధించి ఉంటే, సంకేతపదం మార్పు ఈమెయిలు పంపించబడుతుంది.",
+       "passwordreset-emailsentusername": "ఈ వాడుకరిపేరుకు ఏదైనా ఈమెయిలు చిరునామా అనుసంధించి ఉంటే, సంకేతపదం మార్పు ఈమెయిలు పంపించబడుతుంది.",
+       "passwordreset-emailsent-capture2": "సంకేతపదం మార్పు {{PLURAL:$1|ఈమెయిలును|ఈమెయిళ్ళను}} పంపించాం. {{PLURAL:$1|వాడుకరిపేరు, సంకేతపదాన్ని|వాడుకరిపేర్లు, సంకేతపదాల జాబితాను}} కింద చూపించాం.",
+       "passwordreset-emailerror-capture2": "{{GENDER:$2|వాడుకరికి}} ఈమెయిలు పంపడం విఫలమైంది: $1 {{PLURAL:$3|వాడుకరిపేరు, సంకేతపదాన్ని|వాడుకరిపేర్లు, సంకేతపదాల జాబితాను}} కింద చూపించాం.",
+       "passwordreset-invalideamil": "తప్పు ఈ-మెయిలు చిరునామా",
+       "passwordreset-nodata": "వాడుకరిపేరుగానీ, ఈ-మెయిలు చిరునామా గానీ ఇవ్వలేదు",
+       "changeemail": "ఈ-మెయిలు చిరునామా మార్పు లేదా తొలగింపు",
+       "changeemail-header": "మీ ఈ-మెయిల్ చిరునామాను మార్చుకునేందుకు ఈ ఫారమును నింపండి. అసలు మీ ఖాతాకు ఈ-మెయిలు చిరునామా దేన్నీ జోడించ వద్దనుకుంటే, కొత్త ఈ-మెయిలు చిరునామాను ఖాళీగా ఉంచి, ఫారాన్ని సమర్పించండి.",
        "changeemail-no-info": "ఈ పేజీని నేరుగా చూడటానికి మీరు లాగినయి వుండాలి.",
        "changeemail-oldemail": "ప్రస్తుత ఈ-మెయిలు చిరునామా:",
        "changeemail-newemail": "కొత్త ఈ-మెయిలు చిరునామా:",
+       "changeemail-newemail-help": "ఈ-మెయిలు చిరునామాను తొలగించాం.",
        "changeemail-none": "(ఏమీలేదు)",
        "changeemail-password": "మీ {{SITENAME}} సంకేతపదం:",
        "changeemail-submit": "ఈ-మెయిల్ మార్చు",
        "changeemail-throttled": "మరీ ఎక్కువగా లాగిన్ ప్రయత్నాలు చేసారు.\nమళ్ళీ ప్రయత్నించే ముందు $1 ఆగండి.",
+       "changeemail-nochange": "వేరే ఈ-మెయిలు చిరునామా ఇవ్వండి.",
        "resettokens": "టోకెన్ ను రీసెట్ చెయ్యి",
        "resettokens-text": "మీ ఖాతాకు అనుబంధంగా ఉన్న గోపనీయ డేటాను చూపించే టోకెన్లను మీరు ఇక్కడ రీసెట్ చెయ్యవచ్చు.\n\nమీరా టోకెన్లను పొరపాటున ఎవరికైనా ఇచ్చి ఉన్నా, లేక మీ ఖాతా వివరాలు మరెవరికైనా తెలిసిపోయినా మీరీ పని చెయ్యాలి.",
        "resettokens-no-tokens": "రీసెట్ చేసేందుకు టోకెన్లేమీ లేవు.",
        "minoredit": "ఇది ఒక చిన్న మార్పు",
        "watchthis": "ఈ పుట మీద కన్నేసి ఉంచు",
        "savearticle": "పేజీని భద్రపరచు",
+       "savechanges": "మార్పులను భద్రపరచు",
+       "publishpage": "పేజీని ప్రచురించు",
+       "publishchanges": "మార్పులను ప్రచురించు",
        "preview": "మునుజూపు",
        "showpreview": "మునుజూపు చూపు",
        "showdiff": "తేడాలను చూపించు",
        "missingsummary": "<strong>గుర్తు చేస్తున్నాం:</strong> మీరు దిద్దుబాటు సారాంశమేమీ ఇవ్వలేదు. పేజీని మళ్ళీ భద్రపరచమని చెబితే సారాంశమేమీ లేకుండానే దిద్దుబాటును భద్రపరుస్తాం.",
        "selfredirect": "<strong>హెచ్చరిక:</strong> మీరు ఈ పేజీని దానికే దారిమార్పు చేస్తున్నారు. బహుశా మీరు తప్పు దారిమార్పును సూచించి ఉండవచ్చు, లేదా మీరు తప్పుడు పేజీని మారుస్తున్నారు. \nమీరు \"{{int:savearticle}}\" ను నొక్కితే దారిమార్పు పేజీ ఖచ్చితంగా సృష్టించబడుతుంది.",
        "missingcommenttext": "కింద ఓ వ్యాఖ్య రాయండి.",
-       "missingcommentheader": "<strong>గుర్తు చేస్తున్నాం:</strong> ఈ వ్యాఖ్యకు మీరు విషయం/శీర్షిక పెట్టలేదు.\n\"{{int:savearticle}}\"ని మళ్ళీ నొక్కితే, అది లేకుండానే మీ మార్పును భద్రపరుస్తాం.",
+       "missingcommentheader": "<strong>గుర్తు చేస్తున్నాం:</strong> ఈ వ్యాఖ్యకు మీరు విషయం పెట్టలేదు.\n\"{{int:savearticle}}\"ని మళ్ళీ నొక్కితే, అది లేకుండానే మీ మార్పును భద్రపరుస్తాం.",
        "summary-preview": "సారాంశం మునుజూపు:",
        "subject-preview": "విషయపు మునుజూపు:",
        "previewerrortext": "మీ మార్పులు మునుజూపు చూడటంలో తప్పిదమయింది.",
        "accmailtext": "[[User talk:$1|$1]] కొరకు ఒక యాదృచ్ఛిక సంకేతపదాన్ని $2కి పంపించాం. లాగినయ్యాక, ''[[Special:ChangePassword|సంకేతపదాన్ని మార్చుకోండి]]'' అనే పేజీలో ఈ సంకేతపదాన్ని మార్చుకోవచ్చు.",
        "newarticle": "(కొత్తది)",
        "newarticletext": "ఈ లింకుకు సంబంధించిన పేజీ లేనే లేదు.\nకింది పెట్టెలో మీ రచనను టైపు చేసి ఆ పేజీని సృష్టించండి (దీనిపై సమాచారం కొరకు [$1 సహాయం పేజీ] చూడండి). మీరిక్కడికి పొరపాటున వచ్చి ఉంటే, మీ బ్రౌజరు <strong>back</strong> మీట నొక్కండి.",
-       "anontalkpagetext": "----\n<em>à°\87ది à°\92à°\95 à°\85à°\9cà±\8dà°\9eాత à°µà°¾à°¡à±\81à°\95à°°à°¿ à°\9aà°°à±\8dà°\9aà°¾ à°ªà±\87à°\9cà±\80. à°\86 à°µà°¾à°¡à±\81à°\95à°°à°¿ à°\87à°\82à°\95à°¾ à°¤à°¨à°\95à±\88 à°\96ాతానà±\81 à°¸à±\83à°·à±\8dà°\9fà°¿à°\82à°\9aà±\81à°\95à±\8bà°²à±\87à°¦à±\81, à°²à±\87దా à°\96ాతా à°\89à°¨à±\8dనా à°¦à°¾à°¨à°¿à°¨à°¿ à°\89పయà±\8bà°\97à°¿à°\82à°\9aà°¡à°\82 à°²à±\87à°¦à±\81.</em>\nà°\85à°\82à°\9aà±\87à°¤, à°\85తణà±\8dణి/à°\86à°®à±\86à°¨à±\81 à°\97à±\81à°°à±\8dతిà°\82à°\9aడానిà°\95à°¿ à°\90.à°ªà±\80. à°\9aà°¿à°°à±\81నామానà±\81 à°µà°¾à°¡à°¾à°²à±\8dసి à°µà°\9aà±\8dà°\9aà°¿à°\82ది. \nà°\92à°\95à±\87 à°\90.à°ªà±\80. à°\9aà°¿à°°à±\81నామాని చాలా మంది వాడుకరులు ఉపయోగించే అవకాశం ఉంది. \nమీరూ అజ్ఞాత వాడుకరి అయితే, మీకు సంబంధంలేని వ్యాఖ్యలు మిమ్మల్ని ఉద్దేశించినట్టుగా అనిపిస్తే, భవిష్యత్తులో ఇతర అజ్ఞాత వాడుకరులతో అయోమయం లేకుండా ఉండటానికి, [[Special:CreateAccount|ఖాతాను సృష్టించుకోండి]] లేదా [[Special:UserLogin|లాగినవండి]].''",
+       "anontalkpagetext": "----\n<em>à°\87ది à°\92à°\95 à°\85à°\9cà±\8dà°\9eాత à°µà°¾à°¡à±\81à°\95à°°à°¿ à°\9aà°°à±\8dà°\9aà°¾ à°ªà±\87à°\9cà±\80. à°\86 à°µà°¾à°¡à±\81à°\95à°°à°¿ à°\87à°\82à°\95à°¾ à°¤à°¨à°\95à±\88 à°\96ాతానà±\81 à°¸à±\83à°·à±\8dà°\9fà°¿à°\82à°\9aà±\81à°\95à±\8bà°²à±\87à°¦à±\81, à°²à±\87దా à°\96ాతా à°\89à°¨à±\8dనా à°¦à°¾à°¨à°¿à°¨à°¿ à°\89పయà±\8bà°\97à°¿à°\82à°\9aà°¡à°\82 à°²à±\87à°¦à±\81.</em>\nà°\85à°\82à°\9aà±\87à°¤, à°\85తణà±\8dణి/à°\86à°®à±\86à°¨à±\81 à°\97à±\81à°°à±\8dతిà°\82à°\9aడానిà°\95à°¿ à°\90.à°ªà±\80. à°\9aà°¿à°°à±\81నామానà±\81 à°µà°¾à°¡à°¾à°²à±\8dసి à°µà°\9aà±\8dà°\9aà°¿à°\82ది. \nà°\86 à°\90.à°ªà±\80. à°\9aà°¿à°°à±\81నామానà±\81 చాలా మంది వాడుకరులు ఉపయోగించే అవకాశం ఉంది. \nమీరూ అజ్ఞాత వాడుకరి అయితే, మీకు సంబంధంలేని వ్యాఖ్యలు మిమ్మల్ని ఉద్దేశించినట్టుగా అనిపిస్తే, భవిష్యత్తులో ఇతర అజ్ఞాత వాడుకరులతో అయోమయం లేకుండా ఉండటానికి, [[Special:CreateAccount|ఖాతాను సృష్టించుకోండి]] లేదా [[Special:UserLogin|లాగినవండి]].''",
        "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}}|ఈ పేజీ శీర్షిక కోసం వెతకవచ్చు]], లేదా <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} సంబంధిత చిట్టాలలో వెతకవచ్చు]</span>, కానీ ఈ పేజీని సృష్టించడానికి మీకు అనుమతి లేదు.",
        "missing-revision": "\"{{FULLPAGENAME}}\" అనే పేజీ యొక్క కూర్పు #$1 ఉనికిలో లేదు. సాధారణంగా ఏదైనా తొలగించబడిన పేజీ యొక్క కాలం చెల్లిన చరితం లింకును నొక్కినపుడు ఇది జరుగుతుంది. వివరాలు [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} తొలగింపు లాగ్] లో దొరుకుతాయి.",
        "previewnote": "<strong>ఇది మునుజూపు మాత్రమేనని గుర్తుంచుకోండి.</strong>\nమీ మార్పులు ఇంకా భద్రమవ్వలేదు!",
        "continue-editing": "సరిదిద్దే చోటుకి వెళ్ళండి",
        "previewconflict": "భద్రపరచిన తరువాత పై టెక్స్ట్‌ ఏరియాలోని టెక్స్టు ఇలాగ కనిపిస్తుంది.",
-       "session_fail_preview": "<strong>క్షమించండి! సెషను డేటా పోవడం వలన మీ మార్పులను స్వీకరించలేకపోతున్నాం.</strong>\nమళ్ళీ ప్రయత్నించండి.\nఅయినా పని జరక్కపోతే, ఓసారి [[Special:UserLogout|లాగౌటై]] మళ్ళీ లాగినయి ప్రయత్నించండి.",
-       "session_fail_preview_html": "<strong>సారీ! సెషను డేటా పోవడం వలన మీ దిద్దుబాటును ప్రాసెస్ చెయ్యలేలేక పోతున్నాం.</strong>\n\n''{{SITENAME}}లో ముడి HTML సశక్తమై ఉంది కాబట్టి, జావాస్క్రిప్టు దాడుల నుండి రక్షణగా మునుజూపును దాచేశాం.''\n\n<strong>మీరు చేసినది సరైన దిద్దుబాటే అయితే, మళ్ళీ ప్రయత్నించండి. అయినా పనిచెయ్యకపోతే, ఓ సారి [[Special:UserLogout|లాగౌటై]], మళ్ళీ లాగినయి చూడండి.</strong>",
+       "session_fail_preview": "సారీ! సెషను డేటా పోవడం వలన మీ మార్పులను ప్రాసెస్ చెయ్యలేకపోయాం.\n\nబహుశా మీరు లాగౌటయ్యారేమో. <strong>లాగినయ్యే ఉన్నారని నిర్ధారించుకుని, మళ్ళీ ప్రయత్నించండి.</strong> అయినా పని చెయ్యకపోతే, ఓసారి [[Special:UserLogout|లాగౌటై]], మళ్ళీ లాగినయి ప్రయత్నించండి. మీ బ్రౌజరు ఈ సైటు యొక్క కూకీలను అనుమతిస్తుందని కూడా నిర్ధారించుకోండి.",
+       "session_fail_preview_html": "<strong>సారీ! సెషను డేటా పోవడం వలన మీ దిద్దుబాటును ప్రాసెస్ చెయ్యలేలేక పోతున్నాం.</strong>\n\n<em>{{SITENAME}}లో ముడి HTML సశక్తమై ఉంది కాబట్టి, జావాస్క్రిప్టు దాడుల నుండి రక్షణగా మునుజూపును దాచేశాం.</em>\n\n<strong>మీరు చేసినది సరైన దిద్దుబాటే అయితే, మళ్ళీ ప్రయత్నించండి.</strong> అయినా పనిచెయ్యకపోతే, ఓ సారి [[Special:UserLogout|లాగౌటై]], మళ్ళీ లాగినయి చూడండి. మీ బ్రౌజరు ఈ సైటు యొక్క కూకీలను అనుమతిస్తుందని కూడా నిర్ధారించుకోండి.",
        "token_suffix_mismatch": "'''మీ క్లయంటు, దిద్దుబాటు టోకెన్‌లోని వ్యాకరణ గుర్తులను గజిబిజి చేసింది కాబట్టి మీ దిద్దుబాటును తిరస్కరించాం. పేజీలోని పాఠ్యాన్ని చెడగొట్టకుండా ఉండేందుకు గాను, ఆ దిద్దుబాటును రద్దు చేశాం. వెబ్‌లో ఉండే లోపభూయిష్టమైన అజ్ఞాత ప్రాక్సీ సర్వీసులను వాడినపుడు ఒక్కోసారి ఇలా జరుగుతుంది.'''",
        "edit_form_incomplete": "’’’ఈ ఎడిట్ ఫారంలోని కొన్ని భాగాలు సర్వరును చేరలేదు; మీ మార్పుచేర్పులు భద్రంగా ఉన్నాయని ధృవపరచుకుని, మళ్ళీ ప్రయత్నించండి.’’’",
        "editing": "$1 ని సవరిస్తున్నారు",
        "rightslogtext": "ఇది వాడుకరుల హక్కులకు జరిగిన మార్పుల చిట్టా.",
        "action-read": "ఈ పేజీని చదివే",
        "action-edit": "ఈ పేజీని సవరించే",
-       "action-createpage": "à°ªà±\87à°\9cà±\80లనà±\81 సృష్టించే",
-       "action-createtalk": "à°\9aà°°à±\8dà°\9aాపà±\87à°\9cà±\80లనà±\81 సృష్టించే",
+       "action-createpage": "à°\88 à°ªà±\87à°\9cà±\80ని సృష్టించే",
+       "action-createtalk": "à°\88 à°\9aà°°à±\8dà°\9aాపà±\87à°\9cà±\80ని సృష్టించే",
        "action-createaccount": "ఈ వాడుకరి ఖాతాని సృష్టించే",
        "action-history": "ఈ పేజీ యొక్క చరిత్రని చూడండి",
        "action-minoredit": "ఈ మార్పుని చిన్నదిగా గుర్తించే",
        "action-viewmyprivateinfo": "మీ గోపనీయ సమాచారాన్ని చూడండి",
        "action-editmyprivateinfo": "మీ గోపనీయ సమాచారాన్ని సరిదిద్దండి",
        "action-editcontentmodel": "పేజీ యొక్క కంటెంటు మోడలును సవరించు",
-       "action-managechangetags": "à°¡à±\87à°\9fాబà±\87à°¸à±\81à°²à±\8b à°\9fà±\8dయాà°\97à±\81లనà±\81 à°\9aà±\87à°°à±\8dà°\9aà±\87 à°²à±\87దా à°¤à±\8aà°²à°\97à°¿à°\82à°\9aే",
+       "action-managechangetags": "à°\9fà±\8dయాà°\97à±\81లనà±\81 à°\9aà±\87à°°à±\8dà°\9aà±\87, (à°\85)à°\9aà±\87తనà°\82 à°\9aà±\87à°¸ే",
        "action-applychangetags": "మీ మార్పులతో ట్యాగులను ఆపాదించే",
+       "action-deletechangetags": "డేటాబేసు నుండి ట్యాగులను తొలగించే",
        "nchanges": "{{PLURAL:$1|ఒక మార్పు|$1 మార్పులు}}",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|చివరి సందర్శన తరువాత}}, $1",
        "enhancedrc-history": "చరితం",
        "recentchanges-legend-heading": "<strong>సూచిక :</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|కొత్త పేజీల జాబితా]]ను కూడా చూడండి)",
        "recentchanges-submit": "చూపించు",
-       "rcnotefrom": "<strong>$2</strong> నుండి జరిగిన మార్పులు (<strong>$1</strong> వరకు) కింద చూపబడ్డాయి.",
+       "rcnotefrom": "<strong>$3, $4</strong> తరువాత జరిగిన {{PLURAL:$5|మార్పు|మార్పులు}} కింద ఇచ్చాం (<strong>$1</strong> దాకా చూపించాం).",
        "rclistfrom": "$3, $2 కు ముందు  జరిగిన మార్పులను చూపించు",
        "rcshowhideminor": "చిన్న మార్పులను $1",
        "rcshowhideminor-show": "చూపించు",
        "newpageletter": "కొ",
        "boteditletter": "బా",
        "number_of_watching_users_pageview": "[వీక్షిస్తున్న సభ్యులు: {{PLURAL:$1|ఒక్కరు|$1}}]",
-       "rc_categories": "ఈ వర్గాలకు పరిమితం చెయ్యి (\"|\" తో వేరు చెయ్యండి)",
-       "rc_categories_any": "ఏదయినా",
+       "rc_categories": "ఈ వర్గాలకు పరిమితం చెయ్యి (\"|\" తో వేరు చెయ్యండి):",
+       "rc_categories_any": "à°\8eà°\82à°\9aà±\81à°\95à±\81à°¨à±\8dనది à°\8fదయినా",
        "rc-change-size-new": "మార్పు తర్వాత $1 {{PLURAL:$1|బైటు|బైట్లు}}",
        "newsectionsummary": "/* $1 */ కొత్త విభాగం",
        "rc-enhanced-expand": "వివరాలను చూపించు",
        "recentchangeslinked-summary": "ఏదైనా పేజీకి లింకై ఉన్న పేజీల్లో (లేదా ఏదైనా వర్గంలోని పేజీల్లో) జరిగిన ఇటీవలి మార్పుల జాబితా ఇది.  [[Special:Watchlist|మీ వీక్షణ జాబితా]]లో ఉన్న పేజీలు <strong>బొద్దు</strong>గా ఉంటాయి.",
        "recentchangeslinked-page": "పేజీ పేరు:",
        "recentchangeslinked-to": "లేదంటే, ఇచ్చిన పేజీకి లింకయివున్న పేజీలలో జరిగిన మార్పులను చూపించు",
+       "recentchanges-page-added-to-category": "[[:$1]] ను వర్గానికి చేర్చాం",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] వర్గానికి చేర్చబడింది, [[Special:WhatLinksHere/$1|ఈ పేజీ ఇతర పేజీల్లో చేర్చబడింది]]",
+       "recentchanges-page-removed-from-category": "[[:$1]] వర్గం నుండి తీసివేయబడింది",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] వర్గం నుండి తీసివేయబడింది, [[Special:WhatLinksHere/$1|ఈ పేజీ ఇతర పేజీల్లో చేర్చబడింది]]",
        "upload": "దస్త్రపు ఎక్కింపు",
        "uploadbtn": "దస్త్రాన్ని ఎక్కించు",
        "reuploaddesc": "మళ్ళీ అప్‌లోడు ఫారంకు వెళ్ళు.",
        "uploaderror": "ఎక్కింపు లోపం",
        "upload-recreate-warning": "<strong>హెచ్చరిక: ఆ పేరుతో ఉన్న దస్త్రాన్ని తరలించడం లేదా తొలగించడం జరిగింది.</strong>\n\nమీ సౌకర్యం కోసం ఈ పేజీ యొక్క తొలగింపు మరియు తరలింపు చిట్టాని ఇక్కడ ఇస్తున్నాం:",
        "uploadtext": "దస్త్రాలను ఎక్కించడానికి ఈ కింది ఫారాన్ని ఉపయోగించండి.\nగతంలో ఎక్కించిన దస్త్రాలను చూడడానికి లేదా వెతకడానికి [[Special:FileList|ఎక్కించిన దస్త్రాల యొక్క జాబితా]]కు వెళ్ళండి, (పునః)ఎక్కింపులు [[Special:Log/upload|ఎక్కింపుల చిట్టా]] లోనూ తొలగింపులు [[Special:Log/delete|తొలగింపుల చిట్టా]] లోనూ కూడా నమోదవుతాయి.\n\nఒక దస్త్రాన్ని ఏదైనా పుటలో చేర్చడానికి, కింద చూపిన వాటిలో ఏదేనీ విధంగా లింకుని వాడండి:\n* దస్త్రపు పూర్తి కూర్పుని వాడడానికి '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>'''\n* ఎడమ వైపు మార్జినులో 200 పిక్సెళ్ళ వెడల్పుగల బొమ్మ  మరియు 'ప్రత్యామ్నాయ పాఠ్యం' అన్న వివరణతో గల పెట్టె కోసం  '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|ప్రత్యామ్నాయ పాఠ్యం]]</nowiki></code>'''\n* దస్త్రాన్ని చూపించకుండా నేరుగా లింకు ఇవ్వడానికి '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>'''",
-       "upload-permitted": "à°\85à°¨à±\81మతిà°\82à°\9aà±\87 à°«à±\88à°²à±\81 à°°à°\95ాలà±\81: $1.",
+       "upload-permitted": "à°\85à°¨à±\81మతిà°\82à°\9aబడిన à°«à±\88à°²à±\81 {{PLURAL:$2|à°°à°\95à°\82|à°°à°\95ాలà±\81}}: $1.",
        "upload-preferred": "అనుమతించే ఫైలు రకాలు: $1.",
-       "upload-prohibited": "నిషà±\87ధిà°\82à°\9aà°¿à°¨ à°«à±\88à°²à±\81 à°°à°\95ాలà±\81: $1.",
+       "upload-prohibited": "నిషà±\87ధిà°\82à°\9aబడిన à°«à±\88à°²à±\81 {{PLURAL:$2|à°°à°\95à°\82|à°°à°\95ాలà±\81}}: $1.",
        "uploadlogpage": "ఎక్కింపుల చిట్టా",
        "uploadlogpagetext": "ఇటీవల జరిగిన ఫైలు అప్‌లోడుల జాబితా ఇది.\nమరింత దృశ్యాత్మకంగా చూడటం కోసం [[Special:NewFiles|కొత్త ఫైళ్ళ కొలువు]]కు వెళ్ళండి.",
        "filename": "ఫైలు పేరు",
        "largefileserver": "ఈ ఫైలు సైజు సర్వరులో విధించిన పరిమితి కంటే ఎక్కువగా ఉంది.",
        "emptyfile": "మీరు అప్‌లోడు చేసిన ఫైలు ఖాళీగా ఉన్నట్లుంది. ఫైలు పేరును ఇవ్వడంలో స్పెల్లింగు తప్పు దొర్లి ఉండొచ్చు. మీరు అప్‌లోడు చెయ్యదలచింది ఇదో కాదో నిర్ధారించుకోండి.",
        "windows-nonascii-filename": "దస్త్రాల పేర్లలో ప్రత్యేక అక్షరాలకు ఈ వికీలో అనుకూలత లేదు.",
-       "fileexists": "ఈ పేరుతో ఒక ఫైలు ఇప్పటికే ఉంది. దీనిని మార్చాలో లేదో తెలియకపోతే ఫైలు <strong>[[:$1]]</strong>ను చూడండి.\n[[$1|thumb]]",
+       "fileexists": "ఈ పేరుతో ఒక ఫైలు ఇప్పటికే ఉంది. దీనిని మార్చాలో లేదో {{GENDER:|మీకు}} తెలియకపోతే ఫైలు <strong>[[:$1]]</strong>ను చూడండి.\n[[$1|thumb]]",
        "filepageexists": "ఈ ఫైలు కొరకు వివరణ పేజీని <strong>[[:$1]]</strong> వద్ద ఈసరికే సృష్టించారు, కానీ ఆ పేరుతో ప్రస్తుతం ఫైలేదీ లేదు.\nమీరు ఇస్తున్న సంగ్రహం ఆ వివరణ పేజీలో కనబడదు. \nమీ సంగ్రహం అక్కడ కనబడాలంటే, నేరుగా అక్కడే చేర్చాలి.\n[[$1|thumb]]",
-       "fileexists-extension": "à°\87à°\9fà±\81à°µà°\82à°\9fà°¿ à°ªà±\87à°°à±\81à°¤à±\8bà°\9fà±\87 à°®à°°à±\8b à°«à±\88à°²à±\81 à°\89à°\82ది: [[$2|thumb]]\n* à°\8eà°\95à±\8dà°\95à°¿à°¸à±\8dà°¤à±\81à°¨à±\8dà°¨ à°«à±\88à°²à±\81 à°ªà±\87à°°à±\81: <strong>[[:$1]]</strong>\n* à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤à°\82 à°\89à°¨à±\8dà°¨ à°«à±\88à°²à±\81 à°ªà±\87à°°à±\81: <strong>[[:$2]]</strong>\nమరà±\8b à°ªà±\87à°°à±\81 à°\8eà°\82à°\9aà±\81à°\95à±\8bà°\82à°¡à°¿.",
+       "fileexists-extension": "à°\87à°\9fà±\81à°µà°\82à°\9fà°¿ à°ªà±\87à°°à±\81à°¤à±\8bà°\9fà±\87 à°®à°°à±\8b à°«à±\88à°²à±\81 à°\89à°\82ది: [[$2|thumb]]\n* à°\8eà°\95à±\8dà°\95à°¿à°¸à±\8dà°¤à±\81à°¨à±\8dà°¨ à°«à±\88à°²à±\81 à°ªà±\87à°°à±\81: <strong>[[:$1]]</strong>\n* à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤à°\82 à°\89à°¨à±\8dà°¨ à°«à±\88à°²à±\81 à°ªà±\87à°°à±\81: <strong>[[:$2]]</strong>\nమరిà°\82à°¤ à°µà±\88విధà±\8dయమà±\88à°¨ à°ªà±\87à°°à±\81 à°\8eà°\82à°\9aà±\81à°\95à±\81à°\82à°\9fారా?",
        "fileexists-thumbnail-yes": "ఈ ఫైలు కుదించిన బొమ్మ లాగా ఉంది ''(థంబ్‌నెయిలు)''. [[$1|thumb]]\n<strong>[[:$1]]</strong> ఫైలు చూడండి.\nగుర్తు పెట్టబడిన ఫైలు అసలు సైజే అది అయితే, మరో థంబ్‌నెయిలును అప్‌లోడు చెయ్యాల్సిన అవసరం లేదు.",
        "file-thumbnail-no": "ఫైలు పేరు <strong>$1</strong> తో మొదలవుతోంది.\nఅది పరిమాణం తగ్గించిన ''(నఖచిత్రం)'' లాగా అనిపిస్తోంది.\nఈ బొమ్మ యొక్క పూర్తి స్పష్టత కూర్పు ఉంటే, దాన్ని ఎగుమతి చెయ్యండి. లేదా ఫైలు పేరును మార్చండి.",
        "fileexists-forbidden": "ఈ పేరుతో ఇప్పటికే ఒక ఫైలు ఉంది, దాన్ని తిరగరాయలేరు.\nమీరు ఇప్పటికీ ఈ ఫైలుని ఎగుమతి చేయాలనుకుంటే, వెనక్కి వెళ్ళి మరో పేరుతో ఎగుమతి చేయండి. [[File:$1|thumb|center|$1]]",
        "undeletedrevisions": "{{PLURAL:$1|ఒక సంచిక|$1 సంచికల}} పునఃస్థాపన జరిగింది",
        "undeletedrevisions-files": "{{PLURAL:$1|ఒక కూర్పు|$1 కూర్పులు}} మరియు {{PLURAL:$2|ఒక ఫైలు|$2 ఫైళ్ళ}}ను పునస్థాపించాం",
        "undeletedfiles": "{{PLURAL:$1|ఒక ఫైలును|$1 ఫైళ్లను}} పునఃస్థాపించాం",
-       "cannotundelete": "తొలగింపు రద్దు విఫలమైంది:\n$1",
+       "cannotundelete": "తొలగింపు రద్దులు పూర్తిగానో, కొన్నిగానీ విఫలమయ్యాయి:\n$1",
        "undeletedpage": "'''$1 ను పునస్థాపించాం'''\n\nఇటీవల జరిగిన తొలగింపులు, పునస్థాపనల కొరకు [[Special:Log/delete|తొలగింపు చిట్టా]]ని చూడండి.",
        "undelete-header": "ఇటీవల తొలగించిన పేజీల కొరకు [[Special:Log/delete|తొలగింపు చిట్టా]]ని చూడండి.",
        "undelete-search-title": "తొలగించిన పేజీల అన్వేషణ",
        "blanknamespace": "(మొదటి)",
        "contributions": "{{GENDER:$1|వాడుకరి}} రచనలు",
        "contributions-title": "$1 యొక్క మార్పులు-చేర్పులు",
-       "mycontris": "à°¯à±\8bà°\97దానములు",
+       "mycontris": "నా à°®à°¾à°°à±\8dà°ªులు",
        "anoncontribs": "యోగదానములు",
        "contribsub2": "{{GENDER:$3|$1}} ($2) కొరకు",
        "contributions-userdoesnotexist": "వాడుకరి ఖాతా \"$1\" నమోదుకాలేదు.",
        "sp-contributions-newbies-sub": "కొత్తవారి కోసం",
        "sp-contributions-newbies-title": "కొత్త ఖాతాల వాడుకరుల మార్పుచేర్పులు",
        "sp-contributions-blocklog": "నిరోధాల చిట్టా",
-       "sp-contributions-suppresslog": "అణచిపెట్టబడిన వాడుకరి రచనలు",
-       "sp-contributions-deleted": "తొలగించబడిన వాడుకరి రచనలు",
+       "sp-contributions-suppresslog": "అణచిపెట్టబడిన {{GENDER:$1|వాడుకరి}} రచనలు",
+       "sp-contributions-deleted": "తొలగించబడిన {{GENDER:$1|వాడుకరి}} రచనలు",
        "sp-contributions-uploads": "ఎక్కింపులు",
        "sp-contributions-logs": "చిట్టాలు",
        "sp-contributions-talk": "చర్చ",
index c2c40dc..66e7a0e 100644 (file)
@@ -85,7 +85,8 @@
                        "Imabadplayer",
                        "İnternion",
                        "Hbseren",
-                       "Kumkumuk"
+                       "Kumkumuk",
+                       "Basak"
                ]
        },
        "tog-underline": "Bağlantıların altını çiz:",
        "print": "Yazdır",
        "view": "Görüntüle",
        "view-foreign": "$1 üzerinde gör",
-       "edit": "Değiştir",
+       "edit": "Düzenle",
        "edit-local": "Yerel açıklamayı düzenle",
        "create": "Oluştur",
        "create-local": "Yerel açıklama ekle",
        "savearticle": "Sayfayı kaydet",
        "savechanges": "Değişiklikleri kaydet",
        "publishpage": "Sayfayı yayımla",
+       "publishchanges": "Değişiklikleri yayımla",
        "preview": "Önizleme",
        "showpreview": "Önizlemeyi göster",
        "showdiff": "Değişiklikleri göster",
index 8cee4bc..f81a37c 100644 (file)
        "watchthis": "Спостерігати за цією сторінкою",
        "savearticle": "Зберегти сторінку",
        "savechanges": "Зберегти зміни",
-       "publishpage": "Ð\9eпÑ\83блÑ\96кÑ\83вати сторінку",
-       "publishchanges": "Ð\9eпÑ\83блÑ\96кÑ\83вати зміни",
+       "publishpage": "Ð\97беÑ\80егти сторінку",
+       "publishchanges": "Ð\97беÑ\80егти зміни",
        "preview": "Попередній перегляд",
        "showpreview": "Попередній перегляд",
        "showdiff": "Показати зміни",
        "grant-group-high-volume": "Виконувати великий обсяг діяльності",
        "grant-group-customization": "Налаштування і переваги",
        "grant-group-administration": "Виконувати адміністративні дії",
+       "grant-group-private-information": "Доступ до приватних даних про Вас",
        "grant-group-other": "Різна діяльність",
        "grant-blockusers": "Блокувати і розблокувати користувачів",
        "grant-createaccount": "Створювати облікові записи",
        "grant-highvolume": "Редагування у великих обсягах",
        "grant-oversight": "Приховувати користувачів і версії",
        "grant-patrol": "Патрулювати зміни на сторінках",
+       "grant-privateinfo": "Доступ до приватних даних",
        "grant-protect": "Захищати і знімати захист сторінок",
        "grant-rollback": "Відкочувати зміни на сторінках",
        "grant-sendemail": "Надсилати пошту іншим користувачам",
        "undeletehistorynoadmin": "Стаття вилучена. Причина вилучення та список користувачів, що редагували статтю до вилучення, вказані нижче. Текст вилученої статті можуть переглянути лише адміністратори.",
        "undelete-revision": "Вилучена версія $1 (від $4 $5) користувача $3:",
        "undeleterevision-missing": "Невірна версія. Помилкове посилання, або вказану версію сторінки вилучено з архіву.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Одну версію|$1 версії|$1 версій}} не вдалося відновити, оскільки {{PLURAL:$1|її|їхній}} <code>rev_id</code> вже використовується.",
        "undelete-nodiff": "Не знайдена попередня версія.",
        "undeletebtn": "Відновити",
        "undeletelink": "переглянути/відновити",
        "undeletedrevisions": "$1 {{PLURAL:$1|редагування|редагування|редагувань}} відновлено",
        "undeletedrevisions-files": "$1 {{PLURAL:$1|версія|версії|версій}} та $2 {{PLURAL:$2|файл|файли|файлів}} відновлено",
        "undeletedfiles": "$1 {{PLURAL:$1|файл|файли|файлів}} відновлено",
-       "cannotundelete": "Ð\9fомилка Ð²Ñ\96дновленнÑ\8f:\n$1",
+       "cannotundelete": "ЧаÑ\81Ñ\82ина Ð°Ð±Ð¾ Ð²Ñ\81Ñ\8f Ð¿Ñ\80оÑ\86едÑ\83Ñ\80а Ð²Ñ\96дновленнÑ\8f Ð·Ð°Ð·Ð½Ð°Ð»Ð° Ð½ÐµÐ²Ð´Ð°Ñ\87Ñ\96:\n$1",
        "undeletedpage": "'''Сторінка «$1» відновлена'''\n\nДив. [[Special:Log/delete|список вилучень]], щоб дізнатися про останні вилучення та відновлення.",
        "undelete-header": "Список нещодавно вилучених сторінок можна переглянути в [[Special:Log/delete|журналі вилучень]].",
        "undelete-search-title": "Пошук видалених сторінок",
        "sp-contributions-newbies-sub": "Внесок новачків",
        "sp-contributions-newbies-title": "Внесок з нових облікових записів",
        "sp-contributions-blocklog": "журнал блокувань",
-       "sp-contributions-suppresslog": "вилÑ\83Ñ\87ений Ð²Ð½ÐµÑ\81ок ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а",
-       "sp-contributions-deleted": "вилучені редагування користувача",
+       "sp-contributions-suppresslog": "пÑ\80иÑ\85ований Ð²Ð½ÐµÑ\81ок {{GENDER:$1|коÑ\80иÑ\81Ñ\82Ñ\83ваÑ\87а|коÑ\80иÑ\81Ñ\82Ñ\83ваÑ\87ки}}",
+       "sp-contributions-deleted": "вилучені редагування {{GENDER:$1|користувача|користувачки}}",
        "sp-contributions-uploads": "завантаження",
        "sp-contributions-logs": "журнали",
        "sp-contributions-talk": "обговорення",
index b00ef27..7503b40 100644 (file)
        "shortpages": "چھوٹے صفحات",
        "longpages": "طویل ترین صفحات",
        "deadendpages": "مردہ صفحات",
-       "protectedpages": "محفوظ شدہ صفحات",
+       "protectedpages": "محفوظ کردہ صفحات",
        "protectedpages-noredirect": "رجوع مکررات چھپائیں",
        "protectedpages-timestamp": "وقت کی مہر",
        "protectedpages-page": "صفحہ",
index 7b604e7..71b389f 100644 (file)
        "minoredit": "Bu kichik tahrir",
        "watchthis": "Sahifani kuzatish",
        "savearticle": "Saqla",
+       "publishpage": "Sahifani chop et",
+       "publishchanges": "Oʻzgarishlarni chop et",
        "preview": "Ko‘rib chiqish",
        "showpreview": "Koʻrib chiqish",
        "showdiff": "Kiritilgan o‘zgarishlar",
        "undo-success": "Tahrirni bekor qilish imkoniyati bor. Iltimos, solishtirish oynasini koʻrib chiqib, aynan shu oʻzgarishlarni bekor qilmoqchiligingizga ishonch hosil qiling va undan keyin «Saqla» tugmasini bosing.",
        "undo-failure": "Keyingi tahrirlar bilan chalkashib ketgani sababli, ushbu tahrirni alohida oʻzini bekor qilishni iloji yoʻq.",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|mun.]]) tomonidan qilingan $1-sonli tahrir qaytarildi",
-       "cantcreateaccounttitle": "Ro‘yxatdan o‘tib bo‘lmadi",
        "cantcreateaccount-text": "[[User:$3|$3]] ushbu IP manzil (<strong>$1</strong>) orqali ro‘yxatdan o‘tishni bloklab qo‘ygan.\n\n$3 <em>$2</em>ni sabab qilib ko‘rsatdi",
        "cantcreateaccount-range-text": "[[User:$3|$3]] <strong>$1</strong> sohaga tegishli IP manzillar, shu jumladan sizning IP manzilingiz (<strong>$4</strong>), orqali ro‘yxatdan o‘tishni bloklab qo‘ygan.\n\n$3 <em>$2</em>ni sabab qilib ko‘rsatdi",
        "viewpagelogs": "Ushbu sahifaga doir qaydlarni koʻrsat",
index 4edc5d8..e9877a5 100644 (file)
        "createacct-emailoptional": "电子信地址(填弗填由你)",
        "createacct-email-ph": "畀你侬个电子信地址打进去",
        "createacct-another-email-ph": "电子信地址打进去",
-       "createaccountmail": "用临时随便密码发到指定个电子信地址",
+       "createaccountmail": "拿临时随机密码发到指定个电邮地址",
        "createacct-realname": "真名字(随意)",
        "createaccountreason": "理由:",
        "createacct-reason": "理由:",
        "passwordreset-emailtitle": "{{SITENAME}}上个账号详细信息",
        "passwordreset-emailelement": "用户名:\n$1\n\n临时密码:\n$2",
        "changeemail": "更改或删脱电子邮箱地址",
-       "changeemail-passwordrequired": "侬需要输入密码来确认本次更改。",
        "changeemail-no-info": "侬必须登录著才好直接进入箇只页面。",
        "changeemail-oldemail": "当前电子邮件地址:",
        "changeemail-newemail": "新个电子邮件地址:",
        "session_fail_preview": "弗好意思!由于会话数据落失,我伲弗好处理侬个编辑。\n\n侬作兴已经登出哉。<strong>请核实侬啊曾登录勒上,再试一遍</strong>。如果仍旧弗来事,请[[Special:UserLogout|登出]]著再重新登录,并确保侬个浏览器允许本站个cookie。",
        "session_fail_preview_html": "弗好意思!因为会话数据落失,我伲弗好处理侬个编辑。\n\n<em>由于{{SITENAME}}允许使用原始个HTML,为著防范JavaScript攻击,预览已经囥脱。</em>\n\n<strong>如果箇是一趟合法个编辑,请再试一遍。</strong>如果仍旧弗来事,请[[Special:UserLogout|登出]]著再重新登录,并确保侬个浏览器允许本站个cookie。",
        "token_suffix_mismatch": "<strong>由于侬用户端里向个编辑令牌毁损仔一些标点符号字元,为防止编辑个文字损坏,侬个编辑已经畀回头。</strong>箇种情况通常出现垃拉使用含有交关bug、以网络为主个匿名代理服务个辰光。",
-       "editing": "来里编写$1",
+       "editing": "来里编写“$1”",
        "creating": "创建“$1”",
-       "editingsection": "来里编辑$1(段落)",
+       "editingsection": "来里编写“$1”(段落)",
        "editingcomment": "垃许编辑 $1 (新段落)",
        "editconflict": "编辑冲突: $1",
        "explainconflict": "有人垃拉侬开始编辑之后更改仔页面。上头个文字框内显示个是箇歇本页个内容。侬个修改显示垃拉下底只文字框里向。侬应当拿侬个修改合并到现有个文本里向。<strong>只有</strong>上头文字框里向个内容会得垃侬点击“{{int:savearticle}}”之后畀保存。",
        "node-count-exceeded-category": "页面个节点数超出限制",
        "parser-unstrip-recursion-limit": "递归超过限制 ($1)",
        "converter-manual-rule-error": "来手动语言转换规则当中查着错误",
-       "undo-success": "箇只编辑可以撤销。\n请检查下头个比较,确定侬确实想撤销,然后保存下底个更改完成撤销编辑。",
+       "undo-success": "箇只编辑可以撤销。请检查下头个比较,确定侬确实想撤销,再保存下底个更改完成撤销编辑。",
        "undo-failure": "由于相互冲突个中途编辑,箇只编辑弗好撤销。",
        "undo-norev": "由于其版本弗存在或已删除,此编辑弗好撤销。",
        "undo-nochange": "箇届编辑看出来已经畀撤销。",
        "undo-summary": "撤销由[[Special:Contributions/$2|$2]]([[User talk:$2|讨论]])作出个版本$1",
-       "cantcreateaccounttitle": "弗好开户",
        "cantcreateaccount-text": "从箇只IP地址 (<b>$1</b>) 创建账户已经畀[[User:$3|$3]]禁止。\n\n$3封禁个原因是''$2''",
        "viewpagelogs": "望箇页日志",
        "nohistory": "该只页面呒不编辑历史。",
        "rc-enhanced-hide": "拿细节囥脱",
        "recentchangeslinked": "搭界个改动",
        "recentchangeslinked-feed": "搭界个改动",
-       "recentchangeslinked-toolbox": "相关变化",
+       "recentchangeslinked-toolbox": "搭界个改动",
        "recentchangeslinked-title": "搭“$1”有关个改动",
        "recentchangeslinked-summary": "箇页列出个是对链到某只指定页面个页面近段辰光个修订(或者是对指定分类个成员)。\n徕[[Special:Watchlist|你侬个关注表]]里个页用'''粗体'''显示。",
        "recentchangeslinked-page": "页面名称:",
        "undelete-search-submit": "搜尋",
        "namespace": "名字空间:",
        "invert": "反选择",
-       "tooltip-invert": "æ\89\93ä¸\8aæ\89\8eå\8b¾æ\9d¥å\9b¥è\84±é\80\89å®\9aå\90\8då­\97空é\97´ä¸ªæ\94¹å\8a¨ï¼\88å¦\82æ\9e\9cå\8b¾é\80\89æ\9c\89å\85³名字空间,箇么一道囥脱)",
-       "namespace_association": "æ\9c\89å\85³个名字空间",
+       "tooltip-invert": "æ\89\93ä¸\8aæ\89\8eå\8b¾æ\9d¥å\9b¥è\84±é\80\89å®\9aå\90\8då­\97空é\97´ä¸ªæ\94¹å\8a¨ï¼\88å¦\82æ\9e\9cå\8b¾é\80\89æ\90­ç\95\8c个名字空间,箇么一道囥脱)",
+       "namespace_association": "æ\90­ç\95\8c个名字空间",
        "tooltip-namespace_association": "打上扎勾来加上搭选定名字空间搭界个讨论或主题名字空间",
        "blanknamespace": "(主)",
        "contributions": "{{GENDER:$1|用户}}贡献",
        "year": "从箇年往前:",
        "sp-contributions-newbies": "只显示新用户个贡献",
        "sp-contributions-blocklog": "查封记录",
-       "sp-contributions-deleted": "删脱个用户贡献",
+       "sp-contributions-deleted": "删脱个{{GENDER:$1|用户}}贡献",
        "sp-contributions-talk": "讲张",
        "sp-contributions-search": "寻贡献记录",
        "sp-contributions-username": "IP地址要勿用户名:",
        "sp-contributions-toponly": "只显示阿末只版本个编辑",
        "sp-contributions-submit": "搜寻",
-       "whatlinkshere": "有啥链到箇里",
+       "whatlinkshere": "链进来点啥",
        "whatlinkshere-title": "链接到“$1”个页面",
        "whatlinkshere-page": "页面:",
        "linkshere": "下头个页链到[[:$1]]:",
-       "nolinkshere": "呒有页链到 '''[[:$1]]'''。",
+       "nolinkshere": "呒不页面链到<strong>[[:$1]]</strong>。",
        "isredirect": "转戳页",
        "istemplate": "包括",
        "isimage": "文件鏈接",
        "tooltip-ca-nstab-category": "望分类页",
        "tooltip-minoredit": "标作小编写",
        "tooltip-save": "保存侬个修改",
+       "tooltip-publish": "发布侬个改动",
        "tooltip-preview": "预览倷个更改。请勒拉保存前头用用俚。",
        "tooltip-diff": "显示侬对文本个修改",
        "tooltip-compareselectedversions": "查看本页面两只选定个修订版个差异。",
index 4285cee..73f4629 100644 (file)
        "otherlanguages": "Àwọn èdè míràn",
        "redirectedfrom": "(Àtúnjúwe láti $1)",
        "redirectpagesub": "Ojúewé àtúnjúwe",
-       "redirectto": "àtúnjúwe sí",
+       "redirectto": "Ã\80túnjúwe sí:",
        "lastmodifiedat": "Àtunṣe ojúewé yi gbẹ̀yìn wáyé ni ago $2, ọjọ́ọdún $1.",
        "viewcount": "A ti wo ojúewé yi ni {{PLURAL:$1|ẹ̀kan péré|iye ìgbà $1}}.",
        "protectedpage": "Ojúewé oníàbò",
        "nstab-template": "Àdàkọ",
        "nstab-help": "Ojúewé ìrànlọ́wọ́",
        "nstab-category": "Ẹ̀ka",
+       "mainpage-nstab": "Ojúewé Àkọ́kọ́",
        "nosuchaction": "Kò sí irú ìgbéṣe báun",
        "nosuchactiontext": "Ìgbéṣe tí URL yìí tọ́kasí kò tọ́.\nÓ ṣe é ṣe kó jẹ́ pé ẹ ṣe àṣìṣe URL ọ̀hún, tàbí kó jẹ́ pé ẹ tẹ̀lé ìjápọ̀ tí kò tọ́.\nÓ sì le jẹ́ pé kòkòrò wà nínú software tí {{SITENAME}} nlò.",
        "nosuchspecialpage": "Kò sí irú ojúewé pàtàkì báun",
        "subject": "Orí ọ̀rọ̀/àkọlé:",
        "minoredit": "Àtúnṣe kékeré nìyí",
        "watchthis": "M'ójútó ojúewé yìí",
-       "savearticle": "Ṣe àtẹ̀jáde ojú ewé",
+       "savearticle": "Ìdásí ojúewé",
        "publishpage": "Ṣàtẹ̀jáde ojú ewé",
        "publishchanges": "Ṣàtẹ̀jáde àtúnṣe",
        "preview": "Àyẹ̀wò",
        "shown-title": "{{PLURAL:$1|Ìfihàn èsì $1|Ìfihàn àwọn èsì $1}} nínú ojúewé kọ̀ọ̀kan",
        "viewprevnext": "Ẹ wo ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''Ojúewé tó ún jẹ́ \"[[:$1]]\" wà lórí wiki yìí'''",
-       "searchmenu-new": "'''Dá ojúewé \"[[:$1]]\" sí orí wiki yìí!'''",
+       "searchmenu-new": "<strong>Dá ojúewé \"[[:$1]]\" sí orí wiki yìí!</strong> {{PLURAL:$2|0=|Wo ojúewé tí a wá rí pẹ̀lú ìṣewárí rẹ.|Wo àwọn èsì ìṣewárí tí a rí.}}",
        "searchprofile-articles": "Àwọn ojúewé Àkóónú",
        "searchprofile-images": "Amóhùnmáwòrán",
        "searchprofile-everything": "Èyíkéyìí",
        "searchrelated": "tóbáramu",
        "searchall": "gbogbo",
        "showingresults": "Ìfihàn nísàlẹ̀ títí dé {{PLURAL:$1|èsì '''1'''|àwọn èsì '''$1'''}} láti ìbẹ̀rẹ̀ ní #'''$2'''.",
+       "search-showingresults": "{{PLURAL:$4|Èsì <strong>$1</strong> fún <strong>$3</strong>|Àwọn èsì <strong>$1 - $2</strong> fún <strong>$3</strong>}}",
        "search-nonefound": "Kò sí àwọn èsì kankan tóbáramu mọ́ ìtọrọ.",
        "powersearch-legend": "Àwárí kíkúnrẹ́rẹ́",
        "powersearch-ns": "Àwárí nínú orúkọàyè:",
        "search-external": "Àwárí lóde",
        "searchdisabled": "Ṣíṣàwárí nínú {{SITENAME}} wà ní dídálẹ́kun.\nNí báyìí ná ẹ le ṣàwárí lọ́dọ̀ Google.\nÀkíyèsí pé àwọn atọ́ka wọn fún àkóónú {{SITENAME}} le mọ́ jẹ́ tuntun.",
        "search-error": "Àṣìṣe ṣẹlẹ̀ fún ìwárí: $1",
-       "preferences": "Ã\80wá»\8dn Ã Ã yò",
+       "preferences": "Ã\80wá»\8dn Ã¬fẹÌ\81ràn",
        "mypreferences": "Àwọn ìfẹ́ràn",
        "prefs-edits": "Iye àwọn àtúnṣe:",
        "prefsnologintext2": "Ẹ jọ̀wọ́ ẹ $1 láti ṣe ìyípadà àwọn ìfẹ́ràn yín.",
        "whatlinkshere-links": "← àwọn ìjápọ̀",
        "whatlinkshere-hideredirs": "$1 àtúnjúwe",
        "whatlinkshere-hidetrans": "$1 ìkómọ́ra",
-       "whatlinkshere-hidelinks": "$1 Àwọn ìjápọ̀",
+       "whatlinkshere-hidelinks": "Ìjápọ̀ $1",
        "whatlinkshere-hideimages": "$1 àwọn ìjápọ̀ fáìlì",
        "whatlinkshere-filters": "Ajọ̀",
        "autoblockid": "Ìdínàaláraẹni #$1",
        "javascripttest-qunit-intro": "Ẹ wo [$1 ìwé aṣàlàyé ìdánwò] ní mediawiki.org.",
        "tooltip-pt-userpage": "Ojúewé oníṣe rẹ",
        "tooltip-pt-anonuserpage": "Ojúewé oníṣe fún àdírẹ́ẹ̀sì IP tí ẹ únlò láti ṣàtúnṣe",
-       "tooltip-pt-mytalk": "Ojúewé ọ̀rọ̀ rẹ",
+       "tooltip-pt-mytalk": "Ojúewé ọ̀rọ̀ {{GENDER:|rẹ}}",
        "tooltip-pt-anontalk": "Ọ̀rọ̀ nípa àtúnṣe láti àdírẹ́ẹ̀sì IP yìí",
        "tooltip-pt-preferences": "Àwọn ìfẹ́ràn rẹ",
        "tooltip-pt-watchlist": "Àkójọ àwọn ojúewé tí ẹ̀ ún mójútó bóyá wọ́nyí padà",
-       "tooltip-pt-mycontris": "Àkójọ àwọn àfikún rẹ",
+       "tooltip-pt-mycontris": "Àtójọ àwọn àfikún {{GENDER:|rẹ}}",
        "tooltip-pt-login": "A gbà yín níyànjú kí ẹwọlé, bótilẹ̀jẹ́pẹ́ kò pọndandan.",
        "tooltip-pt-logout": "Ìjáde",
        "tooltip-pt-createaccount": "Ó dára kí ẹ dá àkópamọ́ kí ẹ sì ṣe ìtẹ̀jáwọlé, ṣùgbọ́n kò pọn dandan",
        "tooltip-ca-talk": "Ìfọ̀rọ̀wérọ̀ nípa ohun inú ojúewé yìí",
-       "tooltip-ca-edit": "Ẹ le ṣe àtúnṣe sí ojúewé yìí.\nẸ jọ̀wọ́ ẹ lo bọtini àyẹ̀wò kí ẹ tó fipamọ́.",
+       "tooltip-ca-edit": "S'àtúnṣe ojúewé yi",
        "tooltip-ca-addsection": "Ẹ bẹ̀rẹ̀ abẹlẹ tuntun",
        "tooltip-ca-viewsource": "Àbò wà lórí ojúewé yìí.\nẸ le wo àmìọ̀rọ̀ rẹ̀.",
        "tooltip-ca-history": "Àwọn àtúnṣe tókọjá sí ojúewé yìí",
        "tooltip-t-recentchangeslinked": "Àwọn àtúnṣe tuntun nínú àwọn ojúewé tójápọ̀ láti inú ojúewé yìí",
        "tooltip-feed-rss": "RSS feed fùn ojúewé yìí",
        "tooltip-feed-atom": "Atom feed fún ojúewé yìí",
-       "tooltip-t-contributions": "Ẹ wo àkójọ àwọn àfikún oníṣe yìí",
+       "tooltip-t-contributions": "Àtòjọ àwọn àfikún {{GENDER:$1|oníṣe yìí}}",
        "tooltip-t-emailuser": "Ẹ fi e-mail ránṣẹ́ sí oníṣe yìí",
        "tooltip-t-upload": "Ìrùsókè àwọn fáìlì",
        "tooltip-t-specialpages": "Àkójọ gbogbo àwọn ojúewé pàtàkì",
        "tooltip-ca-nstab-main": "Ìfihàn inú ojúewé",
        "tooltip-ca-nstab-user": "Ẹ wo ojúewé oníṣe",
        "tooltip-ca-nstab-media": "Ẹ wò ojúewé amóhùnmáwòrán",
-       "tooltip-ca-nstab-special": "Ojúewé yìí ṣe pàtàkì, ẹ kò le è ṣ'àtúnṣe rẹ̀",
+       "tooltip-ca-nstab-special": "Ojúewé pàtàkì nì yí, kò le è ṣeẹ́túnṣe",
        "tooltip-ca-nstab-project": "Ẹ wo ojúewé iṣẹ́ọwọ́",
        "tooltip-ca-nstab-image": "Ẹ wo ojúewé faili",
        "tooltip-ca-nstab-mediawiki": "Iwo ìránṣẹ́ sístẹ́mù",
        "revdelete-uname-unhid": "orúkọ oníṣe kò pamọ́",
        "revdelete-restricted": "ṣe ìmúlò ìpàlà fún àwọn olúmójútó",
        "revdelete-unrestricted": "yọ ìpàlà fún àwọn olúmójútó",
-       "logentry-move-move": "$1 ṣeyípòdà ojúewé $3 sí $4",
+       "logentry-move-move": "$1 {{GENDER:$2|ṣeyípòdà}} ojúewé $3 sí $4",
        "logentry-move-move-noredirect": "$1 ṣeyípòdà ojúewé $3 sí $4 láìfi àtúnjúwe sílẹ̀",
        "logentry-move-move_redir": "$1 ṣeyípòdà ojúewé $3 sí $4 lórí àtúnjúwe",
        "logentry-move-move_redir-noredirect": "$1 ṣeyípòdà ojúewé $3 sí $4 lórí àtúnjúwe láìfi àtúnjúwe sílẹ̀",
index d3c04f8..3956e0d 100644 (file)
        "history": "页面历史",
        "history_short": "历史",
        "updatedmarker": "更新于我上次访问后",
-       "printableversion": "打印版本",
+       "printableversion": "打印版本",
        "permalink": "固定链接",
        "print": "打印",
        "view": "查看",
        "powersearch-togglenone": "全不选",
        "powersearch-remember": "记住选择用于以后的搜索",
        "search-external": "外部搜索",
-       "searchdisabled": "{{SITENAME}}的搜索已被禁用。您可以暂时使用搜索引擎进行搜索,须注意他们索引的{{SITENAME}}内容可能不是最新的。",
+       "searchdisabled": "{{SITENAME}}的搜索已被禁用。您可以暂时使用搜索引擎进行搜索,须注意索引的{{SITENAME}}内容可能不是最新的。",
        "search-error": "搜索时发生错误:$1",
        "preferences": "设置",
        "mypreferences": "参数设置",
        "grant-group-high-volume": "执行大量活动",
        "grant-group-customization": "自定义与设置",
        "grant-group-administration": "执行管理操作",
+       "grant-group-private-information": "访问有关您的私有数据",
        "grant-group-other": "杂项活动",
        "grant-blockusers": "封禁与解封用户",
        "grant-createaccount": "创建账户",
        "grant-highvolume": "大容量编辑",
        "grant-oversight": "隐藏用户和阻止修订",
        "grant-patrol": "巡查对页面的更改",
+       "grant-privateinfo": "访问私有信息",
        "grant-protect": "保护页面和取消页面保护",
        "grant-rollback": "回退对页面的更改",
        "grant-sendemail": "给其他用户发送电子邮件",
        "trackingcategories-disabled": "分类被禁用",
        "mailnologin": "无电子邮件地址",
        "mailnologintext": "您必须[[Special:UserLogin|登录]]并在您的[[Special:Preferences|系统设置]]中拥有有效的电子邮件地址才能向其他用户发送电子邮件。",
-       "emailuser": "ç\94µé\82®è\81\94ç³»",
+       "emailuser": "ç\94µé\82®è\81\94ç»\9cæ­¤ç\94¨æ\88·",
        "emailuser-title-target": "电邮联系该{{GENDER:$1|用户}}",
        "emailuser-title-notarget": "电邮联系",
        "emailpagetext": "您可以使用下面的表格发送电子邮件信息至该{{GENDER:$1|用户}}。您在[[Special:Preferences|系统设置]]中输入的电子邮件地址将显示为邮件的“发件人”地址,所以该用户将可以直接回复您。",
        "undeletehistorynoadmin": "这个页面已被删除。删除原因显示在下方编辑摘要中,被删除前的所有版本文本连同删除前贡献用户的细节信息只对管理员可见。",
        "undelete-revision": "$1由$3(在$4 $5)所编写的已删除版本:",
        "undeleterevision-missing": "无效或丢失的版本。您可能使用了错误的链接,或者此版本已经被从存档中恢复或移除。",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|$1个修订版本}}不能被恢复,因为{{PLURAL:$1|它|它们}}的<code>rev_id</code>已在使用中。",
        "undelete-nodiff": "找不到先前的版本。",
        "undeletebtn": "还原",
        "undeletelink": "查看/还原",
        "undeletedrevisions": "还原{{PLURAL:$1|$1个版本}}",
        "undeletedrevisions-files": "还原{{PLURAL:$1|$1个版本}}和{{PLURAL:$2|$2个文件}}",
        "undeletedfiles": "还原{{PLURAL:$1|$1个文件}}",
-       "cannotundelete": "恢复删除失败:\n$1",
+       "cannotundelete": "部分或全部还原删除失败:$1",
        "undeletedpage": "<strong>$1已经被还原</strong>\n\n最近的删除和还原记录请见[[Special:Log/delete|删除日志]]。",
        "undelete-header": "如要查询最近的记录请参阅[[Special:Log/delete|删除日志]]。",
        "undelete-search-title": "搜索已删除页面",
        "sp-contributions-newbies-sub": "新账户的贡献",
        "sp-contributions-newbies-title": "新账户的用户贡献",
        "sp-contributions-blocklog": "封禁日志",
-       "sp-contributions-suppresslog": "被隐藏的用户贡献",
-       "sp-contributions-deleted": "被删除的用户贡献",
+       "sp-contributions-suppresslog": "被屏蔽的{{GENDER:$1|用户}}贡献",
+       "sp-contributions-deleted": "被删除的{{GENDER:$1|用户}}贡献",
        "sp-contributions-uploads": "上传",
        "sp-contributions-logs": "日志",
        "sp-contributions-talk": "讨论",
        "sp-contributions-userrights": "用户权限管理",
-       "sp-contributions-blocked-notice": "è¿\99ä½\8dç\94¨æ\88·ç\8e°æ\97¶æ­£å\9c¨è¢«å°\81é\94\81中ã\80\82\næ\9c\80è¿\91ç\9a\84å°\81é\94\81æ\97¥å¿\97项ç\9b®å\9c¨ä¸\8bé\9d¢æ\8f\90ä¾\9b以便参考:",
-       "sp-contributions-blocked-notice-anon": "è¿\99个IPå\9c°å\9d\80ç\8e°æ\97¶æ­£å\9c¨è¢«å°\81é\94\81中ã\80\82\næ\9c\80è¿\91ç\9a\84å°\81é\94\81æ\97¥å¿\97项ç\9b®å\9c¨ä¸\8bé\9d¢æ\8f\90ä¾\9b以便参考:",
+       "sp-contributions-blocked-notice": "è¿\99ä½\8dç\94¨æ\88·ç\9b®å\89\8dæ­£å\9c¨è¢«å°\81ç¦\81ã\80\82æ\9c\80è¿\91ç\9a\84å°\81ç¦\81æ\97¥å¿\97è®°å½\95å\9c¨ä¸\8bé\9d¢æ\8f\90ä¾\9b以ä¾\9b参考:",
+       "sp-contributions-blocked-notice-anon": "è¿\99个IPå\9c°å\9d\80ç\9b®å\89\8dæ­£å\9c¨è¢«å°\81ç¦\81ã\80\82æ\9c\80è¿\91ç\9a\84å°\81ç¦\81æ\97¥å¿\97è®°å½\95å\9c¨ä¸\8bé\9d¢æ\8f\90ä¾\9b以ä¾\9b参考:",
        "sp-contributions-search": "搜索贡献",
        "sp-contributions-username": "IP地址或用户名:",
        "sp-contributions-toponly": "仅显示最后版本的编辑",
        "dberr-info": "(无法访问数据库:$1)",
        "dberr-info-hidden": "(无法访问数据库)",
        "dberr-usegoogle": "在此期间您可以尝试用 Google 来搜索。",
-       "dberr-outofdate": "须注意他们索引出来的内容可能不是最新的。",
+       "dberr-outofdate": "须注意索引出来的内容可能不是最新的。",
        "dberr-cachederror": "这是所请求页面的缓存副本,可能不是最新的。",
        "htmlform-invalid-input": "您输入的内容存在问题",
        "htmlform-select-badoption": "您指定的值不是有效选项。",
        "revdelete-uname-unhid": "公开用户名",
        "revdelete-restricted": "应用对管理员的限制",
        "revdelete-unrestricted": "删除对管理员的限制",
-       "logentry-block-block": "$1{{GENDER:$2|封禁了}}{{GENDER:$4|$3}},期限$5 $6",
+       "logentry-block-block": "$1{{GENDER:$2|封禁了}}{{GENDER:$4|$3}},期限$5 $6",
        "logentry-block-unblock": "$1{{GENDER:$2|解封了}}{{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1将{{GENDER:$4|$3}}的封禁设置{{GENDER:$2|更改为}}持续时间$5 $6",
        "logentry-suppress-block": "$1{{GENDER:$2|封禁了}}{{GENDER:$4|$3}},持续时间$5 $6",
        "log-action-filter-upload-upload": "新上传",
        "log-action-filter-upload-overwrite": "重新上传",
        "authmanager-authn-not-in-progress": "身份验证尚未进行,或会话数据丢失。请从头重新开始。",
-       "authmanager-authn-no-primary": "提供的证书不能被验证。",
+       "authmanager-authn-no-primary": "提供的凭据不能通过验证。",
        "authmanager-authn-no-local-user": "提供的证书没有与该wiki上的任何用户相关联。",
        "authmanager-authn-no-local-user-link": "提供的证书有效,但没有与该wiki上的任何用户相关联。请通过不同方式登录,或创建一个新用户,然后您将拥有一个把您之前的证书链接到对应账户的选项。",
        "authmanager-authn-autocreate-failed": "所有账户的自动创建失败:$1",
index 310d8dc..e58564c 100644 (file)
        "sp-contributions-newbies-sub": "新帳號的貢獻",
        "sp-contributions-newbies-title": "新帳號的使用者貢獻",
        "sp-contributions-blocklog": "封鎖記錄",
-       "sp-contributions-suppresslog": "已禁止顯示的使用者貢獻",
-       "sp-contributions-deleted": "已刪除的使用者貢獻",
+       "sp-contributions-suppresslog": "已禁止顯示的{{GENDER:$1|使用者}}貢獻",
+       "sp-contributions-deleted": "已刪除的{{GENDER:$1|使用者}}貢獻",
        "sp-contributions-uploads": "上傳",
        "sp-contributions-logs": "日誌",
        "sp-contributions-talk": "對話",
index 7d79818..e778856 100644 (file)
@@ -8,6 +8,7 @@
  *
  */
 
+$fallback = 'sk';
 $fallback8bitEncoding = 'cp1250';
 
 $namespaceNames = [
index 299fd13..1fa701e 100644 (file)
@@ -33,6 +33,8 @@
  * @author לערי ריינהארט
  */
 
+$fallback = 'cs';
+
 $specialPageAliases = [
        'Activeusers'               => [ 'AktívniPoužívatelia' ],
        'Allmessages'               => [ 'VšetkySprávy' ],
index 8368aab..ab316c0 100644 (file)
@@ -907,7 +907,7 @@ abstract class Maintenance {
 
                // Description ...
                if ( $this->mDescription ) {
-                       $this->output( "\n" . $this->mDescription . "\n" );
+                       $this->output( "\n" . wordwrap( $this->mDescription, $screenWidth ) . "\n" );
                }
                $output = "\nUsage: php " . basename( $this->mSelf );
 
index 6931259..2da45ca 100644 (file)
 require_once __DIR__ . '/cleanupTable.inc';
 
 /**
- * Maintenance script to clean up broken page links when somebody turns on $wgCapitalLinks.
+ * Maintenance script to clean up broken page links when somebody turns
+ * on or off $wgCapitalLinks.
  *
  * @ingroup Maintenance
  */
 class CapsCleanup extends TableCleanup {
 
        private $user;
+       private $namespace;
 
        public function __construct() {
                parent::__construct();
@@ -47,25 +49,66 @@ class CapsCleanup extends TableCleanup {
        }
 
        public function execute() {
-               global $wgCapitalLinks;
-
-               if ( $wgCapitalLinks ) {
-                       $this->error( "\$wgCapitalLinks is on -- no need for caps links cleanup.", true );
-               }
-
                $this->user = User::newSystemUser( 'Conversion script', [ 'steal' => true ] );
 
                $this->namespace = intval( $this->getOption( 'namespace', 0 ) );
+
+               if ( MWNamespace::isCapitalized( $this->namespace ) ) {
+                       $this->output( "Will be moving pages to first letter capitalized titles" );
+                       $callback = 'processRowToUppercase';
+               } else {
+                       $this->output( "Will be moving pages to first letter lowercase titles" );
+                       $callback = 'processRowToLowercase';
+               }
+
                $this->dryrun = $this->hasOption( 'dry-run' );
 
                $this->runTable( [
                        'table' => 'page',
                        'conds' => [ 'page_namespace' => $this->namespace ],
                        'index' => 'page_id',
-                       'callback' => 'processRow' ] );
+                       'callback' => $callback ] );
        }
 
-       protected function processRow( $row ) {
+       protected function processRowToUppercase( $row ) {
+               global $wgContLang;
+
+               $current = Title::makeTitle( $row->page_namespace, $row->page_title );
+               $display = $current->getPrefixedText();
+               $lower = $row->page_title;
+               $upper = $wgContLang->ucfirst( $row->page_title );
+               if ( $upper == $lower ) {
+                       $this->output( "\"$display\" already uppercase.\n" );
+
+                       return $this->progress( 0 );
+               }
+
+               $target = Title::makeTitle( $row->page_namespace, $upper );
+               if ( $target->exists() ) {
+                       // Prefix "CapsCleanup" to bypass the conflict
+                       $target = Title::newFromText( __CLASS__ . '/' . $display );
+               }
+               $ok = $this->movePage(
+                       $current,
+                       $target,
+                       'Converting page title to first-letter uppercase',
+                       false
+               );
+               if ( $ok ) {
+                       $this->progress( 1 );
+                       if ( $row->page_namespace == $this->namespace ) {
+                               $talk = $target->getTalkPage();
+                               $row->page_namespace = $talk->getNamespace();
+                               if ( $talk->exists() ) {
+                                       return $this->processRowToUppercase( $row );
+                               }
+                       }
+               }
+
+               return $this->progress( 0 );
+       }
+
+       protected function processRowToLowercase( $row ) {
                global $wgContLang;
 
                $current = Title::makeTitle( $row->page_namespace, $row->page_title );
@@ -79,35 +122,51 @@ class CapsCleanup extends TableCleanup {
                }
 
                $target = Title::makeTitle( $row->page_namespace, $lower );
-               $targetDisplay = $target->getPrefixedText();
                if ( $target->exists() ) {
+                       $targetDisplay = $target->getPrefixedText();
                        $this->output( "\"$display\" skipped; \"$targetDisplay\" already exists\n" );
 
                        return $this->progress( 0 );
                }
 
-               if ( $this->dryrun ) {
-                       $this->output( "\"$display\" -> \"$targetDisplay\": DRY RUN, NOT MOVED\n" );
-                       $ok = true;
-               } else {
-                       $mp = new MovePage( $current, $target );
-                       $status = $mp->move( $this->user, 'Converting page titles to lowercase', true );
-                       $ok = $status->isOK() ? 'OK' : $status->getWikiText( false, false, 'en' );
-                       $this->output( "\"$display\" -> \"$targetDisplay\": $ok\n" );
-               }
+               $ok = $this->movePage( $current, $target, 'Converting page titles to lowercase', true );
                if ( $ok === true ) {
                        $this->progress( 1 );
                        if ( $row->page_namespace == $this->namespace ) {
                                $talk = $target->getTalkPage();
                                $row->page_namespace = $talk->getNamespace();
                                if ( $talk->exists() ) {
-                                       return $this->processRow( $row );
+                                       return $this->processRowToLowercase( $row );
                                }
                        }
                }
 
                return $this->progress( 0 );
        }
+
+       /**
+        * @param Title $current
+        * @param Title $target
+        * @param string $reason
+        * @param bool $createRedirect
+        * @return bool Success
+        */
+       private function movePage( Title $current, Title $target, $reason, $createRedirect ) {
+               $display = $current->getPrefixedText();
+               $targetDisplay = $target->getPrefixedText();
+
+               if ( $this->dryrun ) {
+                       $this->output( "\"$display\" -> \"$targetDisplay\": DRY RUN, NOT MOVED\n" );
+                       $ok = 'OK';
+               } else {
+                       $mp = new MovePage( $current, $target );
+                       $status = $mp->move( $this->user, $reason, $createRedirect );
+                       $ok = $status->isOK() ? 'OK' : $status->getWikiText( false, false, 'en' );
+                       $this->output( "\"$display\" -> \"$targetDisplay\": $ok\n" );
+               }
+
+               return $ok === 'OK';
+       }
 }
 
 $maintClass = "CapsCleanup";
index bc1b34a..94b7fb4 100644 (file)
@@ -71,6 +71,9 @@ class DeprecatedInterfaceFinder extends FileAwareNodeVisitor {
         * indicating that it is a hard-deprecated interface.
         */
        public function isHardDeprecated( PhpParser\Node $node ) {
+               if ( !$node->stmts ) {
+                       return false;
+               }
                foreach ( $node->stmts as $stmt ) {
                        if (
                                $stmt instanceof PhpParser\Node\Expr\FuncCall
@@ -142,7 +145,7 @@ class FindDeprecated extends Maintenance {
                $files = $this->getFiles();
                $chunkSize = ceil( count( $files ) / 72 );
 
-               $parser = new PhpParser\Parser( new PhpParser\Lexer\Emulative );
+               $parser = ( new PhpParser\ParserFactory )->create( PhpParser\ParserFactory::PREFER_PHP7 );
                $traverser = new PhpParser\NodeTraverser;
                $finder = new DeprecatedInterfaceFinder;
                $traverser->addVisitor( $finder );
diff --git a/maintenance/hhvm/makeRepo.php b/maintenance/hhvm/makeRepo.php
new file mode 100644 (file)
index 0000000..a0fe381
--- /dev/null
@@ -0,0 +1,161 @@
+<?php
+
+require __DIR__ . '/../Maintenance.php';
+
+class HHVMMakeRepo extends Maintenance {
+       function __construct() {
+               parent::__construct();
+               $this->addDescription( 'Compile PHP sources for this MediaWiki instance, ' .
+                       'and generate an HHVM bytecode file to be used with HHVM\'s ' .
+                       'RepoAuthoritative mode. The MediaWiki core installation path and ' .
+                       'all registered extensions are automatically searched for the file ' .
+                       'extensions *.php, *.inc, *.php5 and *.phtml.' );
+               $this->addOption( 'output', 'Output filename', true, true, 'o' );
+               $this->addOption( 'input-dir', 'Add an input directory. ' .
+                       'This can be specified multiple times.', false, true, 'd', true );
+               $this->addOption( 'exclude-dir', 'Directory to exclude. ' .
+                       'This can be specified multiple times.', false, true, false, true );
+               $this->addOption( 'extension', 'Extra file extension', false, true, false, true );
+               $this->addOption( 'hhvm', 'Location of HHVM binary', false, true );
+               $this->addOption( 'base-dir', 'The root of all source files. ' .
+                       'This must match hhvm.server.source_root in the server\'s configuration file. ' .
+                       'By default, the MW core install path will be used.',
+                       false, true );
+               $this->addOption( 'verbose', 'Log level 0-3', false, true, 'v' );
+       }
+
+       private static function startsWith( $subject, $search ) {
+               return substr( $subject, 0, strlen( $search ) === $search );
+       }
+
+       function execute() {
+               global $wgExtensionCredits, $IP;
+
+               $dirs = [ $IP ];
+
+               foreach ( $wgExtensionCredits as $type => $extensions ) {
+                       foreach ( $extensions as $extension ) {
+                               if ( isset( $extension['path'] )
+                                       && !self::startsWith( $extension['path'], $IP )
+                               ) {
+                                       $dirs[] = dirname( $extension['path'] );
+                               }
+                       }
+               }
+
+               $dirs = array_merge( $dirs, $this->getOption( 'input-dir', [] ) );
+               $fileExts =
+                       [
+                               'php' => true,
+                               'inc' => true,
+                               'php5' => true,
+                               'phtml' => true
+                       ] +
+                       array_flip( $this->getOption( 'extension', [] ) );
+
+               $dirs = array_unique( $dirs );
+
+               $baseDir = $this->getOption( 'base-dir', $IP );
+               $excludeDirs = array_map( 'realpath', $this->getOption( 'exclude-dir', [] ) );
+
+               if ( $baseDir !== '' && substr( $baseDir, -1 ) !== '/' ) {
+                       $baseDir .= '/';
+               }
+
+               $unfilteredFiles = [ "$IP/LocalSettings.php" ];
+               foreach ( $dirs as $dir ) {
+                       $this->appendDir( $unfilteredFiles, $dir );
+               }
+
+               $files = [];
+               foreach ( $unfilteredFiles as $file ) {
+                       $dotPos = strrpos( $file, '.' );
+                       $slashPos = strrpos( $file, '/' );
+                       if ( $dotPos === false || $slashPos === false || $dotPos < $slashPos ) {
+                               continue;
+                       }
+                       $extension = substr( $file, $dotPos + 1 );
+                       if ( !isset( $fileExts[$extension] ) ) {
+                               continue;
+                       }
+                       $canonical = realpath( $file );
+                       foreach ( $excludeDirs as $excluded ) {
+                               if ( self::startsWith( $canonical, $excluded ) ) {
+                                       continue 2;
+                               }
+                       }
+                       if ( self::startsWith( $file, $baseDir ) ) {
+                               $file = substr( $file, strlen( $baseDir ) );
+                       }
+                       $files[] = $file;
+               }
+
+               $files = array_unique( $files );
+
+               print "Found " . count( $files ) . " files in " .
+                       count( $dirs ) . " directories\n";
+
+               $tmpDir = wfTempDir() . '/mw-make-repo' . mt_rand( 0, 1<<31 );
+               if ( !mkdir( $tmpDir ) ) {
+                       $this->error( 'Unable to create temporary directory', 1 );
+               }
+               file_put_contents( "$tmpDir/file-list", implode( "\n", $files ) );
+
+               $hhvm = $this->getOption( 'hhvm', 'hhvm' );
+               $verbose = $this->getOption( 'verbose', 3 );
+               $cmd = wfEscapeShellArg(
+                       $hhvm,
+                       '--hphp',
+                   '--target', 'hhbc',
+                       '--format', 'binary',
+                       '--force', '1',
+                       '--keep-tempdir', '1',
+                       '--log', $verbose,
+                       '-v', 'AllVolatile=true',
+                       '--input-dir', $baseDir,
+                       '--input-list', "$tmpDir/file-list",
+                       '--output-dir', $tmpDir );
+               print "$cmd\n";
+               passthru( $cmd, $ret );
+               if ( $ret ) {
+                       $this->cleanupTemp( $tmpDir );
+                       $this->error( "Error: HHVM returned error code $ret", 1 );
+               }
+               if ( !rename( "$tmpDir/hhvm.hhbc", $this->getOption( 'output' ) ) ) {
+                       $this->cleanupTemp( $tmpDir );
+                       $this->error( "Error: unable to rename output file", 1 );
+               }
+               $this->cleanupTemp( $tmpDir );
+               return 0;
+       }
+
+       private function cleanupTemp( $tmpDir ) {
+               if ( file_exists( "$tmpDir/hhvm.hhbc" ) ) {
+                       unlink( "$tmpDir/hhvm.hhbc" );
+               }
+               if ( file_exists( "$tmpDir/Stats.js" ) ) {
+                       unlink( "$tmpDir/Stats.js" );
+               }
+
+               unlink( "$tmpDir/file-list" );
+               rmdir( $tmpDir );
+       }
+
+       private function appendDir( &$files, $dir ) {
+               $iter = new RecursiveIteratorIterator(
+                       new RecursiveDirectoryIterator(
+                               $dir,
+                               FilesystemIterator::UNIX_PATHS
+                       ),
+                       RecursiveIteratorIterator::LEAVES_ONLY
+               );
+               foreach ( $iter as $file => $fileInfo ) {
+                       if ( $fileInfo->isFile() ) {
+                               $files[] = $file;
+                       }
+               }
+       }
+}
+
+$maintClass = 'HHVMMakeRepo';
+require RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/hhvm/run-server b/maintenance/hhvm/run-server
new file mode 100755 (executable)
index 0000000..2d71b87
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/hhvm -f
+<?php
+
+require __DIR__ . '/../Maintenance.php';
+
+class RunHipHopServer extends Maintenance {
+       function __construct() {
+               parent::__construct();
+       }
+
+       function execute() {
+               global $IP;
+
+               passthru(
+                       'cd ' . wfEscapeShellArg( $IP ) . " && " .
+                       wfEscapeShellArg(
+                               'hhvm',
+                               '-c', __DIR__."/server.conf",
+                               '--mode=server',
+                               '--port=8080'
+                       ),
+                       $ret
+               );
+               exit( $ret );
+       }
+}
+$maintClass = 'RunHipHopServer';
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/hhvm/server.conf b/maintenance/hhvm/server.conf
new file mode 100644 (file)
index 0000000..558bdad
--- /dev/null
@@ -0,0 +1,30 @@
+Log {
+       Level = Warning
+       UseLogFile = true
+       NativeStackTrace = true
+       InjectedStackTrace = true
+}
+Debug {
+       FullBacktrace = true
+       ServerStackTrace = true
+       ServerErrorMessage = true
+       TranslateSource = true
+}
+Server {
+       EnableStaticContentCache = false
+       EnableStaticContentFromDisk = true
+       AlwaysUseRelativePath = true
+}
+VirtualHost {
+       * {
+               ServerName = localhost
+               Pattern = .
+               RewriteRules {
+                       * {
+                               pattern = ^/wiki/(.*)$
+                               to = /index.php?title=$1
+                               qsa = true
+                       }
+               }
+       }
+}
diff --git a/maintenance/hiphop/run-server b/maintenance/hiphop/run-server
deleted file mode 100755 (executable)
index 2d71b87..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/hhvm -f
-<?php
-
-require __DIR__ . '/../Maintenance.php';
-
-class RunHipHopServer extends Maintenance {
-       function __construct() {
-               parent::__construct();
-       }
-
-       function execute() {
-               global $IP;
-
-               passthru(
-                       'cd ' . wfEscapeShellArg( $IP ) . " && " .
-                       wfEscapeShellArg(
-                               'hhvm',
-                               '-c', __DIR__."/server.conf",
-                               '--mode=server',
-                               '--port=8080'
-                       ),
-                       $ret
-               );
-               exit( $ret );
-       }
-}
-$maintClass = 'RunHipHopServer';
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/hiphop/server.conf b/maintenance/hiphop/server.conf
deleted file mode 100644 (file)
index 558bdad..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Log {
-       Level = Warning
-       UseLogFile = true
-       NativeStackTrace = true
-       InjectedStackTrace = true
-}
-Debug {
-       FullBacktrace = true
-       ServerStackTrace = true
-       ServerErrorMessage = true
-       TranslateSource = true
-}
-Server {
-       EnableStaticContentCache = false
-       EnableStaticContentFromDisk = true
-       AlwaysUseRelativePath = true
-}
-VirtualHost {
-       * {
-               ServerName = localhost
-               Pattern = .
-               RewriteRules {
-                       * {
-                               pattern = ^/wiki/(.*)$
-                               to = /index.php?title=$1
-                               qsa = true
-                       }
-               }
-       }
-}
index bdbb347..aea966f 100644 (file)
@@ -139,6 +139,7 @@ class RefreshImageMetadata extends Maintenance {
                        }
 
                        foreach ( $res as $row ) {
+                               // LocalFile will upgrade immediately here if obsolete
                                $file = $repo->newFileFromRow( $row );
                                if ( $file->getUpgraded() ) {
                                        // File was upgraded.
index 68e0fad..9a9d84d 100644 (file)
@@ -5,7 +5,7 @@ you can override classes used by the installer.
 You can override 3 classes:
 * LocalSettingsGenerator - generates LocalSettings.php
 * WebInstaller - web installer UI
-* CliInstaller - command line installer
+* CliInstaller - command-line installer
 
 Example override:
 
index 0d8cfd6..d2ee1cd 100644 (file)
@@ -1429,10 +1429,6 @@ return [
                'scripts' => 'resources/src/mediawiki/mediawiki.experiments.js',
                'targets' => [ 'desktop', 'mobile' ],
        ],
-       'mediawiki.raggett' => [
-               'styles' => 'resources/src/mediawiki/mediawiki.raggett.css',
-               'targets' => [ 'desktop', 'mobile' ],
-       ],
 
        /* MediaWiki Action */
 
index b31fe82..c3a287d 100644 (file)
@@ -68,6 +68,9 @@ return call_user_func( function () {
                        'es5-shim',
                        'oojs',
                        'oojs-ui-core.styles',
+                       'oojs-ui.styles.icons',
+                       'oojs-ui.styles.indicators',
+                       'oojs-ui.styles.textures',
                        'mediawiki.language',
                ],
                'targets' => [ 'desktop', 'mobile' ],
@@ -78,14 +81,6 @@ return call_user_func( function () {
                'styles' => 'resources/src/oojs-ui-local.css', // HACK, see inside the file
                'skinStyles' => $getSkinSpecific( 'core' ),
                'targets' => [ 'desktop', 'mobile' ],
-               // ResourceLoaderImageModule doesn't support 'skipFunction', so instead we set this up so that
-               // this module is skipped together with its dependencies. Nothing else depends on these modules.
-               'dependencies' => [
-                       'oojs-ui.styles.icons',
-                       'oojs-ui.styles.indicators',
-                       'oojs-ui.styles.textures',
-               ],
-               'skipFunction' => 'resources/src/oojs-ui-styles-skip.js',
        ];
 
        // Additional widgets and layouts module.
diff --git a/resources/assets/licenses/README b/resources/assets/licenses/README
new file mode 100644 (file)
index 0000000..dae2549
--- /dev/null
@@ -0,0 +1,4 @@
+These license icons are used in LocalSettings.php files that are generated by
+the installer. Although "Public domain" has been removed from the installer as
+an option, the public-domain.png image needs to remain here to support older
+installations that refer to it in LocalSettings.php.
index d2a998c..999fae0 100644 (file)
@@ -4,7 +4,8 @@
                        "Calak",
                        "Muhammed taha",
                        "Serwan",
-                       "Pirehelokan"
+                       "Pirehelokan",
+                       "Sarchia"
                ]
        },
        "ooui-toolbar-more": "زیاتر",
@@ -16,5 +17,7 @@
        "ooui-dialog-process-dismiss": "لێگەڕان",
        "ooui-dialog-process-retry": "دیسان ھەوڵ بدە",
        "ooui-dialog-process-continue": "درێژە بدە",
-       "ooui-selectfile-placeholder": "ھیچ فایلێک ھەڵنەبژێراوە"
+       "ooui-selectfile-button-select": "پەڕگەیەک دەستنیشان بکە",
+       "ooui-selectfile-placeholder": "ھیچ فایلێک ھەڵنەبژێراوە",
+       "ooui-selectfile-dragdrop-placeholder": "پەڕگەکان بخەرە ئێرە"
 }
index 30e3efa..e193fb0 100644 (file)
@@ -8,12 +8,18 @@
                        "Palnatoke",
                        "Simeondahl",
                        "Tehnix",
-                       "Macofe"
+                       "Macofe",
+                       "Peter Alberti"
                ]
        },
        "ooui-outline-control-move-down": "Flyt ned",
        "ooui-outline-control-move-up": "Flyt op",
        "ooui-toolbar-more": "Mere",
        "ooui-toolgroup-expand": "Mere",
+       "ooui-toolgroup-collapse": "Færre",
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Afbryd",
+       "ooui-dialog-process-error": "Noget gik galt",
+       "ooui-dialog-process-retry": "Prøv igen",
        "ooui-dialog-process-continue": "Fortsæt"
 }
index 881ff67..bf6b087 100644 (file)
@@ -6,11 +6,24 @@
                        "Kghbln",
                        "Marmase",
                        "Mirzali",
-                       "Se4598"
+                       "Se4598",
+                       "Kumkumuk"
                ]
        },
        "ooui-outline-control-move-down": "Bendi bere cêr",
        "ooui-outline-control-move-up": "Bendi bere cor",
        "ooui-outline-control-remove": "Obcey wedare",
-       "ooui-toolbar-more": "Zewbi"
+       "ooui-toolbar-more": "Zewbi",
+       "ooui-toolgroup-expand": "Dehana",
+       "ooui-toolgroup-collapse": "Deha tayn",
+       "ooui-dialog-message-accept": "TEMAM",
+       "ooui-dialog-message-reject": "Bıtexelne",
+       "ooui-dialog-process-error": "Tayê çi ğelet şi...",
+       "ooui-dialog-process-dismiss": "Racın",
+       "ooui-dialog-process-retry": "Fına bıcerbın",
+       "ooui-dialog-process-continue": "Dewam ke",
+       "ooui-selectfile-button-select": "Yu dosya weçinê",
+       "ooui-selectfile-not-supported": "Dosya weçinayış desteg nêvine na",
+       "ooui-selectfile-placeholder": "Dosya nêwçineya",
+       "ooui-selectfile-dragdrop-placeholder": "Dosya tiyara ake"
 }
index 6a38d0d..b272331 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:22Z
+ * Date: 2016-08-16T21:13:48Z
  */
 ( function ( OO ) {
 
index 72591cc..c13ac7a 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-element-hidden {
        display: none !important;
@@ -16,7 +16,8 @@
        cursor: pointer;
        display: inline-block;
        vertical-align: middle;
-       font: inherit;
+       font-family: inherit;
+       font-size: inherit;
        line-height: normal;
        white-space: nowrap;
        -webkit-touch-callout: none;
        color: #d45353;
 }
 .oo-ui-fieldLayout-messages .oo-ui-labelWidget {
-       padding: 0;
-       line-height: 1.875em;
+       padding: 0.1em 0;
+       line-height: 1.5em;
        vertical-align: middle;
 }
 .oo-ui-actionFieldLayout {
 }
 .oo-ui-menuSelectWidget {
        position: absolute;
+       width: 100%;
+       z-index: 4;
        background-color: #ffffff;
        margin-top: -1px;
        border: 1px solid #cccccc;
 .oo-ui-dropdownWidget.oo-ui-widget-enabled .oo-ui-dropdownWidget-handle {
        cursor: pointer;
 }
-.oo-ui-dropdownWidget > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-dropdownWidget:last-child {
        margin-right: 0;
 }
        max-width: 50em;
        margin-right: 0.5em;
 }
-.oo-ui-comboBoxInputWidget > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
        cursor: pointer;
 }
 .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget {
        margin-right: 0;
 }
+.oo-ui-progressBarWidget {
+       max-width: 50em;
+       background-color: #ffffff;
+       border: 1px solid #cccccc;
+       border-radius: 0.25em;
+       overflow: hidden;
+}
+.oo-ui-progressBarWidget-bar {
+       height: 1em;
+       border-right: 1px solid #cccccc;
+       -webkit-transition: width 250ms ease, margin-left 250ms ease;
+          -moz-transition: width 250ms ease, margin-left 250ms ease;
+               transition: width 250ms ease, margin-left 250ms ease;
+       background-color: #cde7f4;
+       background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #eaf4fa), color-stop(100%, #b0d9ee));
+       background-image: -webkit-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
+       background-image:    -moz-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
+       background-image:         linear-gradient(to bottom, #eaf4fa 0, #b0d9ee 100%);
+       -ms-filter: "progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffeaf4fa', endColorstr='#ffb0d9ee' )";
+}
+.oo-ui-progressBarWidget-indeterminate .oo-ui-progressBarWidget-bar {
+       -webkit-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+          -moz-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+               animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+       width: 40%;
+       margin-left: -10%;
+       border-left: 1px solid #a6cee1;
+}
+.oo-ui-progressBarWidget.oo-ui-widget-disabled {
+       opacity: 0.6;
+}
+@-webkit-keyframes oo-ui-progressBarWidget-slide {
+       from {
+               margin-left: -40%;
+       }
+       to {
+               margin-left: 100%;
+       }
+}
+@-moz-keyframes oo-ui-progressBarWidget-slide {
+       from {
+               margin-left: -40%;
+       }
+       to {
+               margin-left: 100%;
+       }
+}
+@keyframes oo-ui-progressBarWidget-slide {
+       from {
+               margin-left: -40%;
+       }
+       to {
+               margin-left: 100%;
+       }
+}
index 23ecccd..4e8f65c 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-element-hidden {
        display: none !important;
@@ -16,7 +16,8 @@
        cursor: pointer;
        display: inline-block;
        vertical-align: middle;
-       font: inherit;
+       font-family: inherit;
+       font-size: inherit;
        line-height: normal;
        white-space: nowrap;
        -webkit-touch-callout: none;
@@ -62,6 +63,7 @@
        margin-left: 0;
 }
 .oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+       margin-right: 0.25em;
        margin-left: 0.46875em;
 }
 .oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button .oo-ui-indicatorElement-indicator {
 .oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #d9d9d9;
        border-color: #d9d9d9;
-       box-shadow: none;
 }
 .oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
        background-color: #999999;
        color: #ffffff;
+       border-color: #999999;
+       z-index: 3;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button:focus {
+       border-color: #347bff;
 }
 .oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
        color: #347bff;
 }
 .oo-ui-fieldLayout-messages .oo-ui-labelWidget {
        display: table-cell;
-       padding: 0;
-       line-height: 1.875;
+       padding: 0.1em 0;
+       line-height: 1.5;
        vertical-align: middle;
 }
 .oo-ui-actionFieldLayout {
        border-bottom-right-radius: 2px;
        border-top-right-radius: 2px;
 }
+.oo-ui-buttonGroupWidget.oo-ui-widget-enabled .oo-ui-buttonElement .oo-ui-buttonElement-button:focus {
+       border-color: #347bff;
+       z-index: 3;
+}
 .oo-ui-popupWidget {
        position: absolute;
        /* @noflip */
 }
 .oo-ui-menuSelectWidget {
        position: absolute;
+       width: 100%;
+       z-index: 4;
        background-color: #ffffff;
        margin-top: -1px;
        border: 1px solid #aaaaaa;
        position: relative;
        width: 100%;
        max-width: 50em;
-       background-color: #ffffff;
        margin-right: 0.5em;
 }
 .oo-ui-dropdownWidget-handle {
 .oo-ui-dropdownWidget.oo-ui-widget-enabled .oo-ui-dropdownWidget-handle {
        cursor: pointer;
 }
-.oo-ui-dropdownWidget > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-dropdownWidget:last-child {
        margin-right: 0;
 }
 .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
        margin: 0 1em;
 }
-.oo-ui-dropdownWidget:hover .oo-ui-dropdownWidget-handle {
+.oo-ui-dropdownWidget.oo-ui-widget-enabled .oo-ui-dropdownWidget-handle {
+       background-color: #ffffff;
+       -webkit-transition: border-color 100ms;
+          -moz-transition: border-color 100ms;
+               transition: border-color 100ms;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-enabled:hover .oo-ui-dropdownWidget-handle {
        border-color: #aaaaaa;
 }
 .oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
        max-width: 50em;
        margin-right: 0.5em;
 }
-.oo-ui-comboBoxInputWidget > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-comboBoxInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
        cursor: pointer;
 }
 .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget {
        margin-right: 0;
 }
+.oo-ui-progressBarWidget {
+       max-width: 50em;
+       background-color: #ffffff;
+       border: 1px solid #cccccc;
+       border-radius: 2px;
+       overflow: hidden;
+}
+.oo-ui-progressBarWidget-bar {
+       background-color: #dddddd;
+       height: 1em;
+       -webkit-transition: width 200ms, margin-left 200ms;
+          -moz-transition: width 200ms, margin-left 200ms;
+               transition: width 200ms, margin-left 200ms;
+}
+.oo-ui-progressBarWidget-indeterminate .oo-ui-progressBarWidget-bar {
+       -webkit-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+          -moz-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+               animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+       width: 40%;
+       margin-left: -10%;
+       border-left-width: 1px;
+}
+.oo-ui-progressBarWidget.oo-ui-widget-disabled {
+       opacity: 0.6;
+}
+@-webkit-keyframes oo-ui-progressBarWidget-slide {
+       from {
+               margin-left: -40%;
+       }
+       to {
+               margin-left: 100%;
+       }
+}
+@-moz-keyframes oo-ui-progressBarWidget-slide {
+       from {
+               margin-left: -40%;
+       }
+       to {
+               margin-left: 100%;
+       }
+}
+@keyframes oo-ui-progressBarWidget-slide {
+       from {
+               margin-left: -40%;
+       }
+       to {
+               margin-left: 100%;
+       }
+}
index 4d32961..cd1a3de 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:22Z
+ * Date: 2016-08-16T21:13:48Z
  */
 ( function ( OO ) {
 
@@ -2026,6 +2026,7 @@ OO.ui.mixin.ButtonElement.prototype.toggleFramed = function ( framed ) {
 OO.ui.mixin.ButtonElement.prototype.setActive = function ( value ) {
        this.active = !!value;
        this.$element.toggleClass( 'oo-ui-buttonElement-active', this.active );
+       this.updateThemeClasses();
        return this;
 };
 
@@ -7325,6 +7326,103 @@ OO.ui.FloatingMenuSelectWidget.prototype.toggle = function ( visible ) {
        return this;
 };
 
+/**
+ * Progress bars visually display the status of an operation, such as a download,
+ * and can be either determinate or indeterminate:
+ *
+ * - **determinate** process bars show the percent of an operation that is complete.
+ *
+ * - **indeterminate** process bars use a visual display of motion to indicate that an operation
+ *   is taking place. Because the extent of an indeterminate operation is unknown, the bar does
+ *   not use percentages.
+ *
+ * The value of the `progress` configuration determines whether the bar is determinate or indeterminate.
+ *
+ *     @example
+ *     // Examples of determinate and indeterminate progress bars.
+ *     var progressBar1 = new OO.ui.ProgressBarWidget( {
+ *         progress: 33
+ *     } );
+ *     var progressBar2 = new OO.ui.ProgressBarWidget();
+ *
+ *     // Create a FieldsetLayout to layout progress bars
+ *     var fieldset = new OO.ui.FieldsetLayout;
+ *     fieldset.addItems( [
+ *        new OO.ui.FieldLayout( progressBar1, {label: 'Determinate', align: 'top'}),
+ *        new OO.ui.FieldLayout( progressBar2, {label: 'Indeterminate', align: 'top'})
+ *     ] );
+ *     $( 'body' ).append( fieldset.$element );
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).
+ *  To create a determinate progress bar, specify a number that reflects the initial percent complete.
+ *  By default, the progress bar is indeterminate.
+ */
+OO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.ProgressBarWidget.parent.call( this, config );
+
+       // Properties
+       this.$bar = $( '<div>' );
+       this.progress = null;
+
+       // Initialization
+       this.setProgress( config.progress !== undefined ? config.progress : false );
+       this.$bar.addClass( 'oo-ui-progressBarWidget-bar' );
+       this.$element
+               .attr( {
+                       role: 'progressbar',
+                       'aria-valuemin': 0,
+                       'aria-valuemax': 100
+               } )
+               .addClass( 'oo-ui-progressBarWidget' )
+               .append( this.$bar );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );
+
+/* Static Properties */
+
+OO.ui.ProgressBarWidget.static.tagName = 'div';
+
+/* Methods */
+
+/**
+ * Get the percent of the progress that has been completed. Indeterminate progresses will return `false`.
+ *
+ * @return {number|boolean} Progress percent
+ */
+OO.ui.ProgressBarWidget.prototype.getProgress = function () {
+       return this.progress;
+};
+
+/**
+ * Set the percent of the process completed or `false` for an indeterminate process.
+ *
+ * @param {number|boolean} progress Progress percent or `false` for indeterminate
+ */
+OO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {
+       this.progress = progress;
+
+       if ( progress !== false ) {
+               this.$bar.css( 'width', this.progress + '%' );
+               this.$element.attr( 'aria-valuenow', this.progress );
+       } else {
+               this.$bar.css( 'width', '' );
+               this.$element.removeAttr( 'aria-valuenow' );
+       }
+       this.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', progress === false );
+};
+
 /**
  * InputWidget is the base class for all input widgets, which
  * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox inputs},
@@ -8590,7 +8688,8 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
        // Events
        this.$input.on( {
                keypress: this.onKeyPress.bind( this ),
-               blur: this.onBlur.bind( this )
+               blur: this.onBlur.bind( this ),
+               focus: this.onFocus.bind( this )
        } );
        this.$input.one( {
                focus: this.onElementAttach.bind( this )
@@ -8602,6 +8701,7 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
                change: 'onChange',
                disable: 'onDisable'
        } );
+       this.on( 'change', OO.ui.debounce( this.onDebouncedChange.bind( this ), 250 ) );
 
        // Initialization
        this.$element
@@ -8744,6 +8844,16 @@ OO.ui.TextInputWidget.prototype.onBlur = function () {
        this.setValidityFlag();
 };
 
+/**
+ * Handle focus events.
+ *
+ * @private
+ * @param {jQuery.Event} e Focus event
+ */
+OO.ui.TextInputWidget.prototype.onFocus = function () {
+       this.setValidityFlag( true );
+};
+
 /**
  * Handle element attach events.
  *
@@ -8765,10 +8875,19 @@ OO.ui.TextInputWidget.prototype.onElementAttach = function () {
  */
 OO.ui.TextInputWidget.prototype.onChange = function () {
        this.updateSearchIndicator();
-       this.setValidityFlag();
        this.adjustSize();
 };
 
+/**
+ * Handle debounced change events.
+ *
+ * @param {string} value
+ * @private
+ */
+OO.ui.TextInputWidget.prototype.onDebouncedChange = function () {
+       this.setValidityFlag();
+};
+
 /**
  * Handle disable events.
  *
index ff18605..ab1e9ea 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:22Z
+ * Date: 2016-08-16T21:13:48Z
  */
 ( function ( OO ) {
 
@@ -48,9 +48,7 @@ OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
        if ( element.supports( [ 'hasFlag' ] ) ) {
                isFramed = element.supports( [ 'isFramed' ] ) && element.isFramed();
                isActive = element.supports( [ 'isActive' ] ) && element.isActive();
-               if (
-                       ( isFramed && ( isActive || element.isDisabled() || element.hasFlag( 'primary' ) ) )
-               ) {
+               if ( isFramed && ( isActive || element.isDisabled() || element.hasFlag( 'primary' ) ) ) {
                        // Button with a dark background, use white icon
                        variants.invert = true;
                } else if ( !isFramed && element.isDisabled() ) {
index d69ebfa..75fd654 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-popupTool .oo-ui-popupWidget-popup,
 .oo-ui-popupTool .oo-ui-popupWidget-anchor {
index 5b60528..0b55308 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-popupTool .oo-ui-popupWidget-popup,
 .oo-ui-popupTool .oo-ui-popupWidget-anchor {
        line-height: 2.1;
        padding: 0 0.4em;
 }
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
+       color: #555555;
+}
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
-       color: #555555;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled {
-       box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled.oo-ui-tool-active {
        background-color: #e5e5e5;
+       box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
 }
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled:hover {
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled.oo-ui-tool-active:hover {
        background-color: #eeeeee;
 }
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title {
-       color: #cccccc;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
-       opacity: 0.2;
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled.oo-ui-tool-active:active {
+       background-color: #e5e5e5;
 }
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
        opacity: 0.7;
 .oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
        opacity: 0.9;
 }
-.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:active {
-       background-color: #e7e7e7;
-}
-.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title,
+.oo-ui-barToolGroup.oo-ui-widget-disabled .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
        color: #cccccc;
 }
-.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-iconElement-icon {
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-iconElement-icon,
+.oo-ui-barToolGroup.oo-ui-widget-disabled .oo-ui-tool > .oo-ui-tool-link .oo-ui-iconElement-icon {
        opacity: 0.2;
 }
 .oo-ui-popupToolGroup {
 .oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
        margin-right: 1.75em;
 }
-.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:hover {
-       background-color: #eeeeee;
-}
-.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:active {
-       background-color: #e5e5e5;
-}
 .oo-ui-popupToolGroup-handle {
        padding: 0.3125em;
        height: 2.5em;
 .oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
        left: 0;
 }
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:hover {
+       background-color: #eeeeee;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:active {
+       background-color: #e5e5e5;
+}
 .oo-ui-popupToolGroup-header {
        line-height: 2.6;
        margin: 0 0.6em;
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:active {
-       background-color: #e7e7e7;
-}
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
        opacity: 0.9;
 }
 .oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
-       color: #cccccc;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-accel {
-       color: #dddddd;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
-       opacity: 0.2;
-}
-.oo-ui-listToolGroup.oo-ui-widget-disabled {
+.oo-ui-listToolGroup.oo-ui-widget-disabled,
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-title,
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-accel {
        color: #cccccc;
 }
 .oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-iconElement-icon {
        opacity: 0.2;
 }
 .oo-ui-menuToolGroup .oo-ui-tool {
 .oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
-       color: #cccccc;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
-       opacity: 0.2;
-}
-.oo-ui-menuToolGroup.oo-ui-widget-disabled {
+.oo-ui-menuToolGroup.oo-ui-widget-disabled,
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-title {
        color: #cccccc;
 }
 .oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-iconElement-icon {
        opacity: 0.2;
 }
 .oo-ui-toolbar {
index 5254c76..18fda57 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:22Z
+ * Date: 2016-08-16T21:13:48Z
  */
 ( function ( OO ) {
 
index a267b7f..b0e87af 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-draggableElement-handle,
 .oo-ui-draggableElement-handle.oo-ui-widget {
 .oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement {
        display: inline-block;
 }
-.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous > .oo-ui-panelLayout-scrollable {
        overflow-y: hidden;
 }
        padding: 0;
        background-color: transparent;
 }
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
-       position: relative;
-}
 .oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
 .oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
        position: static;
        left: 2.25em;
        margin-left: -2px;
 }
-.oo-ui-progressBarWidget {
-       max-width: 50em;
-       background-color: #ffffff;
-       border: 1px solid #cccccc;
-       border-radius: 0.25em;
-       overflow: hidden;
-}
-.oo-ui-progressBarWidget-bar {
-       height: 1em;
-       border-right: 1px solid #cccccc;
-       -webkit-transition: width 250ms ease, margin-left 250ms ease;
-          -moz-transition: width 250ms ease, margin-left 250ms ease;
-               transition: width 250ms ease, margin-left 250ms ease;
-       background-color: #cde7f4;
-       background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0, #eaf4fa), color-stop(100%, #b0d9ee));
-       background-image: -webkit-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
-       background-image:    -moz-linear-gradient(top, #eaf4fa 0, #b0d9ee 100%);
-       background-image:         linear-gradient(to bottom, #eaf4fa 0, #b0d9ee 100%);
-       -ms-filter: "progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffeaf4fa', endColorstr='#ffb0d9ee' )";
-}
-.oo-ui-progressBarWidget-indeterminate .oo-ui-progressBarWidget-bar {
-       -webkit-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
-          -moz-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
-               animation: oo-ui-progressBarWidget-slide 2s infinite linear;
-       width: 40%;
-       margin-left: -10%;
-       border-left: 1px solid #a6cee1;
-}
-.oo-ui-progressBarWidget.oo-ui-widget-disabled {
-       opacity: 0.6;
-}
-@-webkit-keyframes oo-ui-progressBarWidget-slide {
-       from {
-               margin-left: -40%;
-       }
-       to {
-               margin-left: 100%;
-       }
-}
-@-moz-keyframes oo-ui-progressBarWidget-slide {
-       from {
-               margin-left: -40%;
-       }
-       to {
-               margin-left: 100%;
-       }
-}
-@keyframes oo-ui-progressBarWidget-slide {
-       from {
-               margin-left: -40%;
-       }
-       to {
-               margin-left: 100%;
-       }
-}
 .oo-ui-selectFileWidget {
        display: inline-block;
        vertical-align: middle;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
-       position: absolute;
-       top: 0;
-       bottom: 0;
-       left: 0;
-       right: 0;
-       text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
-       float: right;
-}
 .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
        position: absolute;
 }
 .oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
            -ms-user-select: none;
                user-select: none;
 }
-.oo-ui-selectFileWidget .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget-label {
+       position: absolute;
+       top: 0;
+       bottom: 0;
+       left: 0;
+       right: 0;
+       text-overflow: ellipsis;
+}
+.oo-ui-selectFileWidget-fileType {
+       display: none;
+}
+.oo-ui-selectFileWidget-clearButton {
+       position: absolute;
        z-index: 2;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-dropTarget {
+       position: relative;
        cursor: default;
-       height: 5.5em;
-       padding: 0;
+       height: 8.815em;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton,
+.oo-ui-selectFileWidget-dropTarget .oo-ui-iconElement-icon {
        display: none;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
-       height: 5.5em;
-       width: 5.5em;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
+       width: 7.815em;
        position: absolute;
-       background-size: cover;
+       top: 0.5em;
+       bottom: 0.5em;
+       left: 0.5em;
        background-position: center center;
+       background-repeat: no-repeat;
+       background-size: contain;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+       background-repeat: repeat;
        background-size: auto;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
        opacity: 0.4;
-       background-color: #cccccc;
-       height: 5.5em;
-       width: 5.5em;
+       height: 7.815em;
+       width: 7.815em;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
-       border: 0;
-       background: none;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        display: block;
        height: 100%;
        width: auto;
-       margin-left: 5.5em;
+       margin-left: 8.815em;
+       border: 0;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+       display: block;
        position: relative;
+       top: inherit;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-fileName {
        display: block;
+       padding-top: 0.5em;
        padding-right: 2.375em;
-       overflow: hidden;
-       text-overflow: ellipsis;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
-       display: block;
-       float: none;
-}
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
-       position: absolute;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-clearButton {
        right: 0.5em;
 }
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
 }
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
        display: block;
-       margin: 0.7em;
+       margin: 2.2em 1em 1em;
 }
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
 .oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
 .oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
        cursor: no-drop;
 }
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+       height: auto;
+}
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+       padding: 1em;
+}
 .oo-ui-selectFileWidget:last-child {
        margin-right: 0;
 }
        border-radius: 0.25em 0 0 0.25em;
        border-width: 1px 0 1px 1px;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-       top: 0;
-       right: 0;
-       height: 2.3em;
-       margin-right: 0.775em;
-}
 .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
        top: 0;
        left: 0;
        height: 2.3em;
        margin-left: 0.3em;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+       top: 0;
+       right: 0;
+       height: 2.3em;
+       margin-right: 0.775em;
+}
+.oo-ui-selectFileWidget-label {
+       -webkit-box-sizing: border-box;
+          -moz-box-sizing: border-box;
+               box-sizing: border-box;
+       left: 0.5em;
+       right: 2.175em;
        line-height: 2.3em;
        margin: 0;
        overflow: hidden;
        white-space: nowrap;
-       -webkit-box-sizing: border-box;
-          -moz-box-sizing: border-box;
-               box-sizing: border-box;
        text-overflow: ellipsis;
-       left: 0.5em;
-       right: 0.5em;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {
+.oo-ui-selectFileWidget-fileType {
        color: #888888;
+       display: block;
+       margin-top: 0.25em;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget-clearButton {
        top: 0;
+       right: 0;
        width: 1.875em;
        margin-right: 0;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+.oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
        height: 2.3em;
 }
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
-       color: #cccccc;
-       text-shadow: 0 1px 1px #ffffff;
-       border-color: #dddddd;
-       background-color: #f3f3f3;
-}
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-       opacity: 0.2;
-}
 .oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label {
        color: #cccccc;
 }
-.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-label {
        left: 2.475em;
 }
-.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
-       right: 2.175em;
-}
-.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
-       right: 0;
-}
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
        right: 4.2625em;
 }
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-clearButton {
        right: 2.0875em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-label {
        right: 0.5em;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
        right: 2em;
 }
 .oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
        background-color: #e1f3ff;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
-       color: #cccccc;
-       text-shadow: 0 1px 1px #ffffff;
-       border-color: #dddddd;
-       background-color: #f3f3f3;
-}
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-dropTarget {
        background-color: #ffffff;
        border: 1px solid #aaaaaa;
-       margin-bottom: 0.5em;
        vertical-align: middle;
        border-radius: 0.25em;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
        border-radius: 0.25em;
 }
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+       line-height: 1.4;
+       overflow: inherit;
+       white-space: normal;
+}
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
        border-style: dashed;
 }
+.oo-ui-selectFileWidget.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+       background-color: #f3f3f3;
+       color: #cccccc;
+       border-color: #dddddd;
+       text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info {
+       background-color: #f3f3f3;
+       color: #cccccc;
+       border-color: #dddddd;
+       text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+       opacity: 0.2;
+}
 .oo-ui-outlineOptionWidget {
        position: relative;
        cursor: pointer;
 .oo-ui-capsuleMultiselectWidget-group {
        display: inline;
 }
-.oo-ui-capsuleMultiselectWidget > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-capsuleMultiselectWidget-handle {
        background-color: #ffffff;
        cursor: text;
index 8145ef9..9632bac 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-draggableElement-handle,
 .oo-ui-draggableElement-handle.oo-ui-widget {
 .oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement {
        display: inline-block;
 }
-.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous > .oo-ui-panelLayout-scrollable {
        overflow-y: hidden;
 }
 .oo-ui-buttonSelectWidget:focus {
        outline: 0;
 }
-.oo-ui-buttonSelectWidget:focus .oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected .oo-ui-buttonElement-button {
-       border-color: #347bff;
-       box-shadow: inset 0 0 0 1px #347bff;
-       z-index: 2;
-}
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
        border-bottom-right-radius: 2px;
        border-top-right-radius: 2px;
 }
+.oo-ui-buttonSelectWidget.oo-ui-widget-enabled:focus .oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected .oo-ui-buttonElement-button {
+       border-color: #347bff;
+       box-shadow: inset 0 0 0 1px #347bff;
+}
 .oo-ui-buttonOptionWidget {
        display: inline-block;
        padding: 0;
 }
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
-       position: relative;
-}
 .oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
 .oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
        position: static;
           -moz-transform: translateZ(0);
            -ms-transform: translateZ(0);
                transform: translateZ(0);
-       height: 2em;
        width: 3.5em;
+       min-height: 26px;
+       height: 2em;
        border: 1px solid #767676;
        border-radius: 1em;
        background-color: #ffffff;
                transition: border-color 100ms;
 }
 .oo-ui-toggleSwitchWidget-grip {
-       top: 0.35em;
+       top: 0.3125em;
        min-width: 16px;
-       width: 1.2em;
+       width: 1.25em;
        min-height: 16px;
-       height: 1.2em;
-       border-radius: 1.2em;
+       height: 1.25em;
+       border-radius: 1.25em;
        -webkit-transition: left 100ms, margin-left 100ms;
           -moz-transition: left 100ms, margin-left 100ms;
                transition: left 100ms, margin-left 100ms;
 .oo-ui-toggleSwitchWidget.oo-ui-widget-disabled .oo-ui-toggleSwitchWidget-grip {
        background-color: #ffffff;
 }
-.oo-ui-progressBarWidget {
-       max-width: 50em;
-       background-color: #ffffff;
-       border: 1px solid #cccccc;
-       border-radius: 2px;
-       overflow: hidden;
-}
-.oo-ui-progressBarWidget-bar {
-       background-color: #dddddd;
-       height: 1em;
-       -webkit-transition: width 200ms, margin-left 200ms;
-          -moz-transition: width 200ms, margin-left 200ms;
-               transition: width 200ms, margin-left 200ms;
-}
-.oo-ui-progressBarWidget-indeterminate .oo-ui-progressBarWidget-bar {
-       -webkit-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
-          -moz-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
-               animation: oo-ui-progressBarWidget-slide 2s infinite linear;
-       width: 40%;
-       margin-left: -10%;
-       border-left-width: 1px;
-}
-.oo-ui-progressBarWidget.oo-ui-widget-disabled {
-       opacity: 0.6;
-}
-@-webkit-keyframes oo-ui-progressBarWidget-slide {
-       from {
-               margin-left: -40%;
-       }
-       to {
-               margin-left: 100%;
-       }
-}
-@-moz-keyframes oo-ui-progressBarWidget-slide {
-       from {
-               margin-left: -40%;
-       }
-       to {
-               margin-left: 100%;
-       }
-}
-@keyframes oo-ui-progressBarWidget-slide {
-       from {
-               margin-left: -40%;
-       }
-       to {
-               margin-left: 100%;
-       }
-}
 .oo-ui-selectFileWidget {
        display: inline-block;
        vertical-align: middle;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
-       position: absolute;
-       top: 0;
-       bottom: 0;
-       left: 0;
-       right: 0;
-       text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
-       float: right;
-}
 .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
        position: absolute;
 }
 .oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
            -ms-user-select: none;
                user-select: none;
 }
-.oo-ui-selectFileWidget .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget-label {
+       position: absolute;
+       top: 0;
+       bottom: 0;
+       left: 0;
+       right: 0;
+       text-overflow: ellipsis;
+}
+.oo-ui-selectFileWidget-fileType {
+       display: none;
+}
+.oo-ui-selectFileWidget-clearButton {
+       position: absolute;
        z-index: 2;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-dropTarget {
+       position: relative;
        cursor: default;
-       height: 5.5em;
-       padding: 0;
+       height: 8.815em;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton,
+.oo-ui-selectFileWidget-dropTarget .oo-ui-iconElement-icon {
        display: none;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
-       height: 5.5em;
-       width: 5.5em;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail {
+       width: 7.815em;
        position: absolute;
-       background-size: cover;
+       top: 0.5em;
+       bottom: 0.5em;
+       left: 0.5em;
        background-position: center center;
+       background-repeat: no-repeat;
+       background-size: contain;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail.oo-ui-pendingElement-pending {
+       background-repeat: repeat;
        background-size: auto;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail > .oo-ui-selectFileWidget-noThumbnail-icon {
        opacity: 0.4;
-       background-color: #cccccc;
-       height: 5.5em;
-       width: 5.5em;
+       height: 7.815em;
+       width: 7.815em;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
-       border: 0;
-       background: none;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info {
        display: block;
        height: 100%;
        width: auto;
-       margin-left: 5.5em;
+       margin-left: 8.815em;
+       border: 0;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+       display: block;
        position: relative;
+       top: inherit;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileName {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-fileName {
        display: block;
+       padding-top: 0.5em;
        padding-right: 2.375em;
-       overflow: hidden;
-       text-overflow: ellipsis;
-}
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-fileType {
-       display: block;
-       float: none;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
-       position: absolute;
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-clearButton {
        right: 0.5em;
 }
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-thumbnail,
 }
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton {
        display: block;
-       margin: 0.7em;
+       margin: 2.2em 1em 1em;
 }
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget,
 .oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
 .oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-buttonElement-button {
        cursor: no-drop;
 }
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+       height: auto;
+}
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+       padding: 1em;
+}
 .oo-ui-selectFileWidget:last-child {
        margin-right: 0;
 }
        height: 2.3em;
        margin-left: 0.5em;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+       top: 0;
+       right: 0;
+       height: 2.3em;
+       margin-right: 0.775em;
+}
+.oo-ui-selectFileWidget-label {
        -webkit-box-sizing: border-box;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
        display: block;
+       right: 2.375em;
        line-height: 2.3;
        margin: 0;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
-       left: 0;
-       right: 0;
        padding-left: 0.5em;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {
+.oo-ui-selectFileWidget-fileType {
        color: #888888;
+       display: block;
+       margin-top: 0.25em;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+.oo-ui-selectFileWidget-clearButton {
        top: 0;
        right: 0;
-       height: 2.3em;
-       margin-right: 0.775em;
-}
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
-       top: 0;
        min-width: 24px;
        width: 1.875em;
        margin-right: 0;
 }
-.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+.oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
        height: 2.3em;
 }
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
-       background-color: #f3f3f3;
-       color: #cccccc;
-       text-shadow: 0 1px 1px #ffffff;
-       border-color: #dddddd;
-       cursor: default;
-}
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
-.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
-       opacity: 0.2;
-}
 .oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label {
        color: #cccccc;
 }
-.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-label {
        left: 2.875em;
 }
-.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
-       right: 2.375em;
-}
-.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
-       right: 0;
-}
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
        right: 4.4625em;
        padding-left: 0;
 }
-.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-clearButton {
        right: 2.0875em;
 }
-.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
-       right: 0.5em;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
-.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-label {
        right: 2em;
-       padding-left: 0;
 }
 .oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop.oo-ui-selectFileWidget-dropTarget {
        background-color: #ebf2ff;
 }
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
-       border-color: #dddddd;
-       background-color: #f3f3f3;
-}
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info,
-.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel,
-.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-dropLabel {
-       color: #cccccc;
-       text-shadow: 0 1px 1px #ffffff;
-}
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget {
+.oo-ui-selectFileWidget-dropTarget {
        background-color: #ffffff;
        border: 1px solid #cccccc;
-       margin-bottom: 0.5em;
        vertical-align: middle;
        overflow: hidden;
        border-radius: 2px;
 }
-.oo-ui-selectFileWidget.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
        border-radius: 2px;
 }
+.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-label {
+       line-height: 1.4;
+       overflow: inherit;
+       white-space: normal;
+}
 .oo-ui-selectFileWidget-empty.oo-ui-selectFileWidget-dropTarget {
        background-color: #eeeeee;
        border-style: dashed;
 }
+.oo-ui-selectFileWidget.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled.oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported.oo-ui-selectFileWidget-dropTarget {
+       background-color: #f3f3f3;
+       border-color: #dddddd;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info {
+       background-color: #f3f3f3;
+       color: #cccccc;
+       border-color: #dddddd;
+       text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
+.oo-ui-selectFileWidget-empty.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+       opacity: 0.2;
+}
 .oo-ui-widget-disabled .oo-ui-selectFileWidget-dropLabel {
        display: none;
 }
 .oo-ui-capsuleMultiselectWidget-group {
        display: inline;
 }
-.oo-ui-capsuleMultiselectWidget > .oo-ui-menuSelectWidget {
-       z-index: 1;
-       width: 100%;
-}
 .oo-ui-capsuleMultiselectWidget-handle {
-       background-color: #ffffff;
-       cursor: text;
        min-height: 2.4em;
        margin-right: 0.5em;
        padding: 0.15em 0.25em;
        top: 0;
        margin: 0.3em;
 }
-.oo-ui-capsuleMultiselectWidget:hover .oo-ui-capsuleMultiselectWidget-handle {
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-enabled .oo-ui-capsuleMultiselectWidget-handle {
+       background-color: #ffffff;
+       cursor: text;
+       -webkit-transition: border-color 100ms;
+          -moz-transition: border-color 100ms;
+               transition: border-color 100ms;
+}
+.oo-ui-capsuleMultiselectWidget.oo-ui-widget-enabled:hover .oo-ui-capsuleMultiselectWidget-handle {
        border-color: #aaaaaa;
 }
 .oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle {
        text-shadow: 0 1px 1px #ffffff;
        border-color: #dddddd;
        background-color: #f3f3f3;
-       cursor: default;
 }
 .oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-iconElement-icon,
 .oo-ui-capsuleMultiselectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiselectWidget-handle > .oo-ui-indicatorElement-indicator {
index cd62339..7a38633 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:22Z
+ * Date: 2016-08-16T21:13:48Z
  */
 ( function ( OO ) {
 
@@ -4770,103 +4770,6 @@ OO.ui.SelectFileWidget.prototype.setDisabled = function ( disabled ) {
        return this;
 };
 
-/**
- * Progress bars visually display the status of an operation, such as a download,
- * and can be either determinate or indeterminate:
- *
- * - **determinate** process bars show the percent of an operation that is complete.
- *
- * - **indeterminate** process bars use a visual display of motion to indicate that an operation
- *   is taking place. Because the extent of an indeterminate operation is unknown, the bar does
- *   not use percentages.
- *
- * The value of the `progress` configuration determines whether the bar is determinate or indeterminate.
- *
- *     @example
- *     // Examples of determinate and indeterminate progress bars.
- *     var progressBar1 = new OO.ui.ProgressBarWidget( {
- *         progress: 33
- *     } );
- *     var progressBar2 = new OO.ui.ProgressBarWidget();
- *
- *     // Create a FieldsetLayout to layout progress bars
- *     var fieldset = new OO.ui.FieldsetLayout;
- *     fieldset.addItems( [
- *        new OO.ui.FieldLayout( progressBar1, {label: 'Determinate', align: 'top'}),
- *        new OO.ui.FieldLayout( progressBar2, {label: 'Indeterminate', align: 'top'})
- *     ] );
- *     $( 'body' ).append( fieldset.$element );
- *
- * @class
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).
- *  To create a determinate progress bar, specify a number that reflects the initial percent complete.
- *  By default, the progress bar is indeterminate.
- */
-OO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.ProgressBarWidget.parent.call( this, config );
-
-       // Properties
-       this.$bar = $( '<div>' );
-       this.progress = null;
-
-       // Initialization
-       this.setProgress( config.progress !== undefined ? config.progress : false );
-       this.$bar.addClass( 'oo-ui-progressBarWidget-bar' );
-       this.$element
-               .attr( {
-                       role: 'progressbar',
-                       'aria-valuemin': 0,
-                       'aria-valuemax': 100
-               } )
-               .addClass( 'oo-ui-progressBarWidget' )
-               .append( this.$bar );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );
-
-/* Static Properties */
-
-OO.ui.ProgressBarWidget.static.tagName = 'div';
-
-/* Methods */
-
-/**
- * Get the percent of the progress that has been completed. Indeterminate progresses will return `false`.
- *
- * @return {number|boolean} Progress percent
- */
-OO.ui.ProgressBarWidget.prototype.getProgress = function () {
-       return this.progress;
-};
-
-/**
- * Set the percent of the process completed or `false` for an indeterminate process.
- *
- * @param {number|boolean} progress Progress percent or `false` for indeterminate
- */
-OO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {
-       this.progress = progress;
-
-       if ( progress !== false ) {
-               this.$bar.css( 'width', this.progress + '%' );
-               this.$element.attr( 'aria-valuenow', this.progress );
-       } else {
-               this.$bar.css( 'width', '' );
-               this.$element.removeAttr( 'aria-valuenow' );
-       }
-       this.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', !progress );
-};
-
 /**
  * SearchWidgets combine a {@link OO.ui.TextInputWidget text input field}, where users can type a search query,
  * and a menu of search results, which is displayed beneath the query
index 55f891a..2f6c1a0 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-actionWidget.oo-ui-pendingElement-pending {
        background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
        width: 0;
        height: 0;
        overflow: hidden;
+       z-index: 4;
 }
 .oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-active {
        width: auto;
index 0d3976f..465e17b 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:27Z
+ * Date: 2016-08-16T21:13:53Z
  */
 .oo-ui-window {
        background: transparent;
        width: 0;
        height: 0;
        overflow: hidden;
+       z-index: 4;
 }
 .oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-active {
        width: auto;
index 0e9dbf1..510399d 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.7
+ * OOjs UI v0.17.8
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-08-03T16:38:22Z
+ * Date: 2016-08-16T21:13:48Z
  */
 ( function ( OO ) {
 
index 563db00..d9cdf5a 100644 (file)
@@ -254,8 +254,9 @@ div.tleft {
        margin: .5em 1.4em 1.3em 0;
 }
 
-/* Hide elements that are marked as "empty" according to legacy Tidy rules
+/* Hide elements that are marked as "empty" according to legacy Tidy rules,
+ * except if a client script removes the mw-hide-empty-elt class from the body
  */
-.mw-empty-elt, .mw-empty-li {
+body.mw-hide-empty-elt .mw-empty-elt {
        display: none;
 }
index 9b9d324..b4edc50 100644 (file)
@@ -26,6 +26,7 @@
 
 .mw-ui-icon {
        position: relative;
+       line-height: @iconSize;
        min-height: @iconSize;
        min-width: @iconSize;
 
diff --git a/resources/src/mediawiki/mediawiki.raggett.css b/resources/src/mediawiki/mediawiki.raggett.css
deleted file mode 100644 (file)
index e69de29..0000000
index 85ded44..3b2c86e 100644 (file)
                var api, title, params,
                        imageSrc = $img.attr( 'src' );
 
+               // Reject promise if there is no thumbnail image
+               if ( $img[ 0 ] === undefined ) {
+                       return $.Deferred().reject();
+               }
+
                if ( this.imageInfoCache[ imageSrc ] === undefined ) {
                        api = new mw.Api();
                        // TODO: This supports only gallery of images
index c59f5ba..b860dbd 100644 (file)
                $links.click( function ( e ) {
                        var action, api, $link;
 
-                       // Preload the notification module for mw.notify
-                       mw.loader.load( 'mediawiki.notification' );
-
                        action = mwUriGetAction( this.href );
 
                        if ( action !== 'watch' && action !== 'unwatch' ) {
 
                        updateWatchLink( $link, action, 'loading' );
 
+                       // Preload the notification module for mw.notify
+                       mw.loader.load( 'mediawiki.notification' );
+
                        api = new mw.Api();
 
                        api[ action ]( title )
diff --git a/resources/src/oojs-ui-styles-skip.js b/resources/src/oojs-ui-styles-skip.js
deleted file mode 100644 (file)
index 57c905a..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*!
- * Skip function for OOjs UI PHP style modules.
- *
- * The `<meta name="X-OOUI-PHP" />` is added to pages by OutputPage::enableOOUI().
- *
- * Looking for elements in the DOM might be expensive, but it's probably better than double-loading
- * 200 KB of CSS with embedded images because of bug T87871.
- */
-return !!jQuery( 'meta[name="X-OOUI-PHP"]' ).length;
index 35eb153..8740e5d 100644 (file)
@@ -23,12 +23,12 @@ mw-vagrant-guest:
   mediawiki_url: http://127.0.0.1/wiki/
 
 beta:
-  mediawiki_url: http://en.wikipedia.beta.wmflabs.org/wiki/
+  mediawiki_url: https://en.wikipedia.beta.wmflabs.org/wiki/
   mediawiki_user: Selenium_user
   # mediawiki_password: SET THIS IN THE ENVIRONMENT!
 
 test2:
-  mediawiki_url: http://test2.wikipedia.org/wiki/
+  mediawiki_url: https://test2.wikipedia.org/wiki/
   mediawiki_user: Selenium_user
   # mediawiki_password: SET THIS IN THE ENVIRONMENT!
 
index 9b85d3f..e965e2d 100644 (file)
@@ -174,10 +174,6 @@ class ParserTest {
                        echo "Warning: tidy is not installed, skipping some tests\n";
                }
 
-               if ( !extension_loaded( 'gd' ) ) {
-                       echo "Warning: GD extension is not present, thumbnailing tests will probably fail\n";
-               }
-
                $this->hooks = [];
                $this->functionHooks = [];
                $this->transparentHooks = [];
index 99b9029..788d304 100644 (file)
@@ -3087,7 +3087,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $actual = $this->manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN );
                $expected = [
                        $rememberReq,
-                       $makeReq( "primary-shared", AuthenticationRequest::REQUIRED ),
+                       $makeReq( "primary-shared", AuthenticationRequest::PRIMARY_REQUIRED ),
                        $makeReq( "required", AuthenticationRequest::PRIMARY_REQUIRED ),
                        $makeReq( "required2", AuthenticationRequest::PRIMARY_REQUIRED ),
                        $makeReq( "optional", AuthenticationRequest::OPTIONAL ),
@@ -3107,10 +3107,10 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $actual = $this->manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN );
                $expected = [
                        $rememberReq,
-                       $makeReq( "primary-shared", AuthenticationRequest::REQUIRED ),
-                       $makeReq( "required", AuthenticationRequest::REQUIRED ),
+                       $makeReq( "primary-shared", AuthenticationRequest::PRIMARY_REQUIRED ),
+                       $makeReq( "required", AuthenticationRequest::PRIMARY_REQUIRED ),
                        $makeReq( "optional", AuthenticationRequest::OPTIONAL ),
-                       $makeReq( "foo", AuthenticationRequest::REQUIRED ),
+                       $makeReq( "foo", AuthenticationRequest::PRIMARY_REQUIRED ),
                        $makeReq( "bar", AuthenticationRequest::REQUIRED ),
                        $makeReq( "baz", AuthenticationRequest::REQUIRED ),
                ];
index a7df221..7d2ba8d 100644 (file)
@@ -172,6 +172,7 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
                                'type' => 'string',
                                'label' => $msg,
                                'help' => $msg,
+                               'sensitive' => true,
                        ],
                        'string3' => [
                                'type' => 'string',
@@ -206,6 +207,7 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
                $expect = $req1->getFieldInfo();
                foreach ( $expect as $name => &$options ) {
                        $options['optional'] = !empty( $options['optional'] );
+                       $options['sensitive'] = !empty( $options['sensitive'] );
                }
                unset( $options );
                $this->assertEquals( $expect, $fields );
@@ -225,8 +227,10 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
 
                $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
                $expect += $req2->getFieldInfo();
+               $expect['string1']['sensitive'] = true;
                $expect['string2']['optional'] = false;
                $expect['string3']['optional'] = false;
+               $expect['string3']['sensitive'] = false;
                $expect['select']['options']['bar'] = $msg;
                $this->assertEquals( $expect, $fields );
 
@@ -237,6 +241,7 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
                $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
                $expect += $req2->getFieldInfo();
                $expect['string1']['optional'] = false;
+               $expect['string1']['sensitive'] = true;
                $expect['string3']['optional'] = false;
                $expect['select']['optional'] = false;
                $expect['select']['options']['bar'] = $msg;
@@ -246,7 +251,11 @@ class AuthenticationRequestTest extends \MediaWikiTestCase {
 
                $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
                $expect = $req1->getFieldInfo() + $req2->getFieldInfo();
+               foreach ( $expect as $name => &$options ) {
+                       $options['sensitive'] = !empty( $options['sensitive'] );
+               }
                $expect['string1']['optional'] = false;
+               $expect['string1']['sensitive'] = true;
                $expect['string2']['optional'] = true;
                $expect['string3']['optional'] = true;
                $expect['select']['optional'] = false;
index aa0e3c7..b5c8a36 100644 (file)
@@ -32,6 +32,13 @@ abstract class AuthenticationRequestTestCase extends \MediaWikiTestCase {
                        if ( isset( $data['image'] ) ) {
                                $this->assertType( 'string', $data['image'], "Field $field, image" );
                        }
+                       if ( isset( $data['sensitive'] ) ) {
+                               $this->assertType( 'bool', $data['sensitive'], "Field $field, sensitive" );
+                       }
+                       if ( $data['type'] === 'password' ) {
+                               $this->assertTrue( !empty( $data['sensitive'] ),
+                                       "Field $field, password field must be sensitive" );
+                       }
 
                        switch ( $data['type'] ) {
                                case 'string':
index bb9050f..6168182 100644 (file)
@@ -376,8 +376,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $content = new WikitextContent( 'test text' );
                $ok = ContentHandler::runLegacyHooks(
                        'testRunLegacyHooks',
-                       [ 'foo', &$content, 'bar' ],
-                       false
+                       [ 'foo', &$content, 'bar' ]
                );
 
                $this->assertTrue( $ok, "runLegacyHooks should have returned true" );
index ac83428..b4ae765 100644 (file)
@@ -102,6 +102,11 @@ class TextContentTest extends MediaWikiLangTestCase {
                                " Foo \n ",
                                ' Foo',
                        ],
+                       [
+                               # 2: newline normalization
+                               "LF\n\nCRLF\r\n\r\nCR\r\rEND",
+                               "LF\n\nCRLF\n\nCR\n\nEND",
+                       ],
                ];
        }
 
index 723f1c3..7e55a73 100644 (file)
@@ -285,8 +285,42 @@ class DatabaseTest extends MediaWikiTestCase {
                        $called = true;
                        $db->setFlag( DBO_TRX );
                } );
-               $db->rollback( __METHOD__ );
+               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
                $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
                $this->assertTrue( $called, 'Callback reached' );
        }
+
+       public function testGetScopedLock() {
+               $db = $this->db;
+
+               $db->setFlag( DBO_TRX );
+               try {
+                       $this->badLockingMethodImplicit( $db );
+               } catch ( RunTimeException $e ) {
+                       $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
+               }
+               $db->clearFlag( DBO_TRX );
+               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
+               $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
+
+               try {
+                       $this->badLockingMethodExplicit( $db );
+               } catch ( RunTimeException $e ) {
+                       $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
+               }
+               $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
+               $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
+       }
+
+       private function badLockingMethodImplicit( IDatabase $db ) {
+               $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
+               $db->query( "SELECT 1" ); // trigger DBO_TRX
+               throw new RunTimeException( "Uh oh!" );
+       }
+
+       private function badLockingMethodExplicit( IDatabase $db ) {
+               $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
+               $db->begin( __METHOD__ );
+               throw new RunTimeException( "Uh oh!" );
+       }
 }
index a4871a6..f8dda6f 100644 (file)
@@ -44,6 +44,7 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
 
        /**
         * @covers ObjectFactory::getObjectFromSpec
+        * @covers ObjectFactory::expandClosures
         */
        public function testClosureExpansionEnabled() {
                $obj = ObjectFactory::getObjectFromSpec( [
@@ -80,6 +81,44 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
                $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
        }
 
+       /**
+        * @covers ObjectFactory::getObjectFromSpec
+        */
+       public function testGetObjectFromFactory() {
+               $args = [ 'a', 'b' ];
+               $obj = ObjectFactory::getObjectFromSpec( [
+                       'factory' => function ( $a, $b ) {
+                               return new ObjectFactoryTestFixture( $a, $b );
+                       },
+                       'args' => $args,
+               ] );
+               $this->assertSame( $args, $obj->args );
+       }
+
+       /**
+        * @covers ObjectFactory::getObjectFromSpec
+        * @expectedException InvalidArgumentException
+        */
+       public function testGetObjectFromInvalid() {
+               $args = [ 'a', 'b' ];
+               $obj = ObjectFactory::getObjectFromSpec( [
+                       // Missing 'class' or 'factory'
+                       'args' => $args,
+               ] );
+       }
+
+       /**
+        * @covers ObjectFactory::getObjectFromSpec
+        * @dataProvider provideConstructClassInstance
+        */
+       public function testGetObjectFromClass( $args ) {
+               $obj = ObjectFactory::getObjectFromSpec( [
+                       'class' => 'ObjectFactoryTestFixture',
+                       'args' => $args,
+               ] );
+               $this->assertSame( $args, $obj->args );
+       }
+
        /**
         * @covers ObjectFactory::constructClassInstance
         * @dataProvider provideConstructClassInstance
@@ -91,7 +130,7 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
                $this->assertSame( $args, $obj->args );
        }
 
-       public function provideConstructClassInstance() {
+       public static function provideConstructClassInstance() {
                // These args go to 11. I thought about making 10 one louder, but 11!
                return [
                        '0 args' => [ [] ],
@@ -110,6 +149,7 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
        }
 
        /**
+        * @covers ObjectFactory::constructClassInstance
         * @expectedException InvalidArgumentException
         */
        public function testNamedArgs() {
index 081cb38..0b34b6f 100644 (file)
@@ -172,11 +172,17 @@ class SearchEngineTest extends MediaWikiLangTestCase {
                                        $name,
                                        $type
                                ] )->getMock();
+
                        $mockField->expects( $this->any() )->method( 'getMapping' )->willReturn( [
                                'testData' => 'test',
                                'name' => $name,
                                'type' => $type,
                        ] );
+
+                       $mockField->expects( $this->any() )
+                               ->method( 'merge' )
+                               ->willReturn( $mockField );
+
                        return $mockField;
                };
 
diff --git a/tests/phpunit/specials/SpecialSearchTest.php b/tests/phpunit/specials/SpecialSearchTest.php
new file mode 100644 (file)
index 0000000..20e88f5
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+class SpecialSearchText extends \PHPUnit_Framework_TestCase {
+       public function testSubPageRedirect() {
+               $ctx = new RequestContext;
+
+               SpecialPageFactory::executePath(
+                       Title::newFromText( 'Special:Search/foo_bar' ),
+                       $ctx
+               );
+               $url = $ctx->getOutput()->getRedirect();
+               // some older versions of hhvm have a bug that doesn't parse relative
+               // urls with a port, so help it out a little bit.
+               // https://github.com/facebook/hhvm/issues/7136
+               $url = wfExpandUrl( $url, PROTO_CURRENT );
+
+               $parts = parse_url( $url );
+               $this->assertEquals( '/w/index.php', $parts['path'] );
+               parse_str( $parts['query'], $query );
+               $this->assertEquals( 'Special:Search', $query['title'] );
+               $this->assertEquals( 'foo bar', $query['search'] );
+       }
+}
index 6446416..86ce53f 100644 (file)
@@ -86,6 +86,25 @@ class ResourcesTest extends MediaWikiTestCase {
                }
        }
 
+       /**
+        * Verify that all specified messages actually exist.
+        */
+       public function testMissingMessages() {
+               $data = self::getAllModules();
+               $validDeps = array_keys( $data['modules'] );
+               $lang = Language::factory( 'en' );
+
+               /** @var ResourceLoaderModule $module */
+               foreach ( $data['modules'] as $moduleName => $module ) {
+                       foreach ( $module->getMessages() as $msgKey ) {
+                               $this->assertTrue(
+                                       wfMessage( $msgKey )->useDatabase( false )->inLanguage( $lang )->exists(),
+                                       "Message '$msgKey' required by '$moduleName' must exist"
+                               );
+                       }
+               }
+       }
+
        /**
         * Verify that all dependencies of all modules are always satisfiable with the 'targets' defined
         * for the involved modules.
index 95f28c8..e30088d 100644 (file)
@@ -74,6 +74,7 @@ return [
                        'tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.template.mustache.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.test.js',
+                       'tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.html.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.toc.test.js',
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js
new file mode 100644 (file)
index 0000000..41d800a
--- /dev/null
@@ -0,0 +1,685 @@
+( function ( mw, $ ) {
+       QUnit.module( 'mediawiki (mw.loader)' );
+
+       mw.loader.addSource(
+               'testloader',
+               QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/load.mock.php' )
+       );
+
+       /**
+        * The sync style load test (for @import). This is, in a way, also an open bug for
+        * ResourceLoader ("execute js after styles are loaded"), but browsers don't offer a
+        * way to get a callback from when a stylesheet is loaded (that is, including any
+        * `@import` rules inside). To work around this, we'll have a little time loop to check
+        * if the styles apply.
+        *
+        * Note: This test originally used new Image() and onerror to get a callback
+        * when the url is loaded, but that is fragile since it doesn't monitor the
+        * same request as the css @import, and Safari 4 has issues with
+        * onerror/onload not being fired at all in weird cases like this.
+        */
+       function assertStyleAsync( assert, $element, prop, val, fn ) {
+               var styleTestStart,
+                       el = $element.get( 0 ),
+                       styleTestTimeout = ( QUnit.config.testTimeout || 5000 ) - 200;
+
+               function isCssImportApplied() {
+                       // Trigger reflow, repaint, redraw, whatever (cross-browser)
+                       var x = $element.css( 'height' );
+                       x = el.innerHTML;
+                       el.className = el.className;
+                       x = document.documentElement.clientHeight;
+
+                       return $element.css( prop ) === val;
+               }
+
+               function styleTestLoop() {
+                       var styleTestSince = new Date().getTime() - styleTestStart;
+                       // If it is passing or if we timed out, run the real test and stop the loop
+                       if ( isCssImportApplied() || styleTestSince > styleTestTimeout ) {
+                               assert.equal( $element.css( prop ), val,
+                                       'style "' + prop + ': ' + val + '" from url is applied (after ' + styleTestSince + 'ms)'
+                               );
+
+                               if ( fn ) {
+                                       fn();
+                               }
+
+                               return;
+                       }
+                       // Otherwise, keep polling
+                       setTimeout( styleTestLoop );
+               }
+
+               // Start the loop
+               styleTestStart = new Date().getTime();
+               styleTestLoop();
+       }
+
+       function urlStyleTest( selector, prop, val ) {
+               return QUnit.fixurl(
+                       mw.config.get( 'wgScriptPath' ) +
+                               '/tests/qunit/data/styleTest.css.php?' +
+                               $.param( {
+                                       selector: selector,
+                                       prop: prop,
+                                       val: val
+                               } )
+               );
+       }
+
+       QUnit.test( 'Basic', 2, function ( assert ) {
+               var isAwesomeDone;
+
+               mw.loader.testCallback = function () {
+                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module is.awesome: isAwesomeDone should still be undefined' );
+                       isAwesomeDone = true;
+               };
+
+               mw.loader.implement( 'test.callback', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' ) ] );
+
+               return mw.loader.using( 'test.callback', function () {
+                       assert.strictEqual( isAwesomeDone, true, 'test.callback module should\'ve caused isAwesomeDone to be true' );
+                       delete mw.loader.testCallback;
+
+               }, function () {
+                       assert.ok( false, 'Error callback fired while loader.using "test.callback" module' );
+               } );
+       } );
+
+       QUnit.test( 'Object method as module name', 2, function ( assert ) {
+               var isAwesomeDone;
+
+               mw.loader.testCallback = function () {
+                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module hasOwnProperty: isAwesomeDone should still be undefined' );
+                       isAwesomeDone = true;
+               };
+
+               mw.loader.implement( 'hasOwnProperty', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' ) ], {}, {} );
+
+               return mw.loader.using( 'hasOwnProperty', function () {
+                       assert.strictEqual( isAwesomeDone, true, 'hasOwnProperty module should\'ve caused isAwesomeDone to be true' );
+                       delete mw.loader.testCallback;
+
+               }, function () {
+                       assert.ok( false, 'Error callback fired while loader.using "hasOwnProperty" module' );
+               } );
+       } );
+
+       QUnit.test( '.using( .. ) Promise', 2, function ( assert ) {
+               var isAwesomeDone;
+
+               mw.loader.testCallback = function () {
+                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module is.awesome: isAwesomeDone should still be undefined' );
+                       isAwesomeDone = true;
+               };
+
+               mw.loader.implement( 'test.promise', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' ) ] );
+
+               return mw.loader.using( 'test.promise' )
+               .done( function () {
+                       assert.strictEqual( isAwesomeDone, true, 'test.promise module should\'ve caused isAwesomeDone to be true' );
+                       delete mw.loader.testCallback;
+
+               } )
+               .fail( function () {
+                       assert.ok( false, 'Error callback fired while loader.using "test.promise" module' );
+               } );
+       } );
+
+       QUnit.test( '.implement( styles={ "css": [text, ..] } )', 2, function ( assert ) {
+               var $element = $( '<div class="mw-test-implement-a"></div>' ).appendTo( '#qunit-fixture' );
+
+               assert.notEqual(
+                       $element.css( 'float' ),
+                       'right',
+                       'style is clear'
+               );
+
+               mw.loader.implement(
+                       'test.implement.a',
+                       function () {
+                               assert.equal(
+                                       $element.css( 'float' ),
+                                       'right',
+                                       'style is applied'
+                               );
+                       },
+                       {
+                               all: '.mw-test-implement-a { float: right; }'
+                       }
+               );
+
+               return mw.loader.using( 'test.implement.a' );
+       } );
+
+       QUnit.test( '.implement( styles={ "url": { <media>: [url, ..] } } )', 7, function ( assert ) {
+               var $element1 = $( '<div class="mw-test-implement-b1"></div>' ).appendTo( '#qunit-fixture' ),
+                       $element2 = $( '<div class="mw-test-implement-b2"></div>' ).appendTo( '#qunit-fixture' ),
+                       $element3 = $( '<div class="mw-test-implement-b3"></div>' ).appendTo( '#qunit-fixture' ),
+                       done = assert.async();
+
+               assert.notEqual(
+                       $element1.css( 'text-align' ),
+                       'center',
+                       'style is clear'
+               );
+               assert.notEqual(
+                       $element2.css( 'float' ),
+                       'left',
+                       'style is clear'
+               );
+               assert.notEqual(
+                       $element3.css( 'text-align' ),
+                       'right',
+                       'style is clear'
+               );
+
+               mw.loader.implement(
+                       'test.implement.b',
+                       function () {
+                               // Note: done() must only be called when the entire test is
+                               // complete. So, make sure that we don't start until *both*
+                               // assertStyleAsync calls have completed.
+                               var pending = 2;
+                               assertStyleAsync( assert, $element2, 'float', 'left', function () {
+                                       assert.notEqual( $element1.css( 'text-align' ), 'center', 'print style is not applied' );
+
+                                       pending--;
+                                       if ( pending === 0 ) {
+                                               done();
+                                       }
+                               } );
+                               assertStyleAsync( assert, $element3, 'float', 'right', function () {
+                                       assert.notEqual( $element1.css( 'text-align' ), 'center', 'print style is not applied' );
+
+                                       pending--;
+                                       if ( pending === 0 ) {
+                                               done();
+                                       }
+                               } );
+                       },
+                       {
+                               url: {
+                                       print: [ urlStyleTest( '.mw-test-implement-b1', 'text-align', 'center' ) ],
+                                       screen: [
+                                               // bug 40834: Make sure it actually works with more than 1 stylesheet reference
+                                               urlStyleTest( '.mw-test-implement-b2', 'float', 'left' ),
+                                               urlStyleTest( '.mw-test-implement-b3', 'float', 'right' )
+                                       ]
+                               }
+                       }
+               );
+
+               mw.loader.load( 'test.implement.b' );
+       } );
+
+       // Backwards compatibility
+       QUnit.test( '.implement( styles={ <media>: text } ) (back-compat)', 2, function ( assert ) {
+               var $element = $( '<div class="mw-test-implement-c"></div>' ).appendTo( '#qunit-fixture' );
+
+               assert.notEqual(
+                       $element.css( 'float' ),
+                       'right',
+                       'style is clear'
+               );
+
+               mw.loader.implement(
+                       'test.implement.c',
+                       function () {
+                               assert.equal(
+                                       $element.css( 'float' ),
+                                       'right',
+                                       'style is applied'
+                               );
+                       },
+                       {
+                               all: '.mw-test-implement-c { float: right; }'
+                       }
+               );
+
+               return mw.loader.using( 'test.implement.c' );
+       } );
+
+       // Backwards compatibility
+       QUnit.test( '.implement( styles={ <media>: [url, ..] } ) (back-compat)', 4, function ( assert ) {
+               var $element = $( '<div class="mw-test-implement-d"></div>' ).appendTo( '#qunit-fixture' ),
+                       $element2 = $( '<div class="mw-test-implement-d2"></div>' ).appendTo( '#qunit-fixture' ),
+                       done = assert.async();
+
+               assert.notEqual(
+                       $element.css( 'float' ),
+                       'right',
+                       'style is clear'
+               );
+               assert.notEqual(
+                       $element2.css( 'text-align' ),
+                       'center',
+                       'style is clear'
+               );
+
+               mw.loader.implement(
+                       'test.implement.d',
+                       function () {
+                               assertStyleAsync( assert, $element, 'float', 'right', function () {
+                                       assert.notEqual( $element2.css( 'text-align' ), 'center', 'print style is not applied (bug 40500)' );
+                                       done();
+                               } );
+                       },
+                       {
+                               all: [ urlStyleTest( '.mw-test-implement-d', 'float', 'right' ) ],
+                               print: [ urlStyleTest( '.mw-test-implement-d2', 'text-align', 'center' ) ]
+                       }
+               );
+
+               mw.loader.load( 'test.implement.d' );
+       } );
+
+       // @import (bug 31676)
+       QUnit.test( '.implement( styles has @import )', 7, function ( assert ) {
+               var isJsExecuted, $element,
+                       done = assert.async();
+
+               mw.loader.implement(
+                       'test.implement.import',
+                       function () {
+                               assert.strictEqual( isJsExecuted, undefined, 'script not executed multiple times' );
+                               isJsExecuted = true;
+
+                               assert.equal( mw.loader.getState( 'test.implement.import' ), 'executing', 'module state during implement() script execution' );
+
+                               $element = $( '<div class="mw-test-implement-import">Foo bar</div>' ).appendTo( '#qunit-fixture' );
+
+                               assert.equal( mw.msg( 'test-foobar' ), 'Hello Foobar, $1!', 'messages load before script execution' );
+
+                               assertStyleAsync( assert, $element, 'float', 'right', function () {
+                                       assert.equal( $element.css( 'text-align' ), 'center',
+                                               'CSS styles after the @import rule are working'
+                                       );
+
+                                       done();
+                               } );
+                       },
+                       {
+                               css: [
+                                       '@import url(\''
+                                               + urlStyleTest( '.mw-test-implement-import', 'float', 'right' )
+                                               + '\');\n'
+                                               + '.mw-test-implement-import { text-align: center; }'
+                               ]
+                       },
+                       {
+                               'test-foobar': 'Hello Foobar, $1!'
+                       }
+               );
+
+               mw.loader.using( 'test.implement.import' ).always( function () {
+                       assert.strictEqual( isJsExecuted, true, 'script executed' );
+                       assert.equal( mw.loader.getState( 'test.implement.import' ), 'ready', 'module state after script execution' );
+               } );
+       } );
+
+       QUnit.test( '.implement( dependency with styles )', 4, function ( assert ) {
+               var $element = $( '<div class="mw-test-implement-e"></div>' ).appendTo( '#qunit-fixture' ),
+                       $element2 = $( '<div class="mw-test-implement-e2"></div>' ).appendTo( '#qunit-fixture' );
+
+               assert.notEqual(
+                       $element.css( 'float' ),
+                       'right',
+                       'style is clear'
+               );
+               assert.notEqual(
+                       $element2.css( 'float' ),
+                       'left',
+                       'style is clear'
+               );
+
+               mw.loader.register( [
+                       [ 'test.implement.e', '0', [ 'test.implement.e2' ] ],
+                       [ 'test.implement.e2', '0' ]
+               ] );
+
+               mw.loader.implement(
+                       'test.implement.e',
+                       function () {
+                               assert.equal(
+                                       $element.css( 'float' ),
+                                       'right',
+                                       'Depending module\'s style is applied'
+                               );
+                       },
+                       {
+                               all: '.mw-test-implement-e { float: right; }'
+                       }
+               );
+
+               mw.loader.implement(
+                       'test.implement.e2',
+                       function () {
+                               assert.equal(
+                                       $element2.css( 'float' ),
+                                       'left',
+                                       'Dependency\'s style is applied'
+                               );
+                       },
+                       {
+                               all: '.mw-test-implement-e2 { float: left; }'
+                       }
+               );
+
+               return mw.loader.using( 'test.implement.e' );
+       } );
+
+       QUnit.test( '.implement( only scripts )', 1, function ( assert ) {
+               mw.loader.implement( 'test.onlyscripts', function () {} );
+               assert.strictEqual( mw.loader.getState( 'test.onlyscripts' ), 'ready' );
+       } );
+
+       QUnit.test( '.implement( only messages )', 2, function ( assert ) {
+               assert.assertFalse( mw.messages.exists( 'bug_29107' ), 'Verify that the test message doesn\'t exist yet' );
+
+               // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
+               mw.loader.implement( 'test.implement.msgs', [], {}, { bug_29107: 'loaded' } );
+               // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
+
+               return mw.loader.using( 'test.implement.msgs', function () {
+                       assert.ok( mw.messages.exists( 'bug_29107' ), 'Bug 29107: messages-only module should implement ok' );
+               }, function () {
+                       assert.ok( false, 'Error callback fired while implementing "test.implement.msgs" module' );
+               } );
+       } );
+
+       QUnit.test( '.implement( empty )', 1, function ( assert ) {
+               mw.loader.implement( 'test.empty' );
+               assert.strictEqual( mw.loader.getState( 'test.empty' ), 'ready' );
+       } );
+
+       QUnit.test( 'Broken indirect dependency', 4, function ( assert ) {
+               // don't emit an error event
+               this.sandbox.stub( mw, 'track' );
+
+               mw.loader.register( [
+                       [ 'test.module1', '0' ],
+                       [ 'test.module2', '0', [ 'test.module1' ] ],
+                       [ 'test.module3', '0', [ 'test.module2' ] ]
+               ] );
+               mw.loader.implement( 'test.module1', function () {
+                       throw new Error( 'expected' );
+               }, {}, {} );
+               assert.strictEqual( mw.loader.getState( 'test.module1' ), 'error', 'Expected "error" state for test.module1' );
+               assert.strictEqual( mw.loader.getState( 'test.module2' ), 'error', 'Expected "error" state for test.module2' );
+               assert.strictEqual( mw.loader.getState( 'test.module3' ), 'error', 'Expected "error" state for test.module3' );
+
+               assert.strictEqual( mw.track.callCount, 1 );
+       } );
+
+       QUnit.test( 'Circular dependency', 1, function ( assert ) {
+               mw.loader.register( [
+                       [ 'test.circle1', '0', [ 'test.circle2' ] ],
+                       [ 'test.circle2', '0', [ 'test.circle3' ] ],
+                       [ 'test.circle3', '0', [ 'test.circle1' ] ]
+               ] );
+               assert.throws( function () {
+                       mw.loader.using( 'test.circle3' );
+               }, /Circular/, 'Detect circular dependency' );
+       } );
+
+       QUnit.test( 'Out-of-order implementation', 9, function ( assert ) {
+               mw.loader.register( [
+                       [ 'test.module4', '0' ],
+                       [ 'test.module5', '0', [ 'test.module4' ] ],
+                       [ 'test.module6', '0', [ 'test.module5' ] ]
+               ] );
+               mw.loader.implement( 'test.module4', function () {} );
+               assert.strictEqual( mw.loader.getState( 'test.module4' ), 'ready', 'Expected "ready" state for test.module4' );
+               assert.strictEqual( mw.loader.getState( 'test.module5' ), 'registered', 'Expected "registered" state for test.module5' );
+               assert.strictEqual( mw.loader.getState( 'test.module6' ), 'registered', 'Expected "registered" state for test.module6' );
+               mw.loader.implement( 'test.module6', function () {} );
+               assert.strictEqual( mw.loader.getState( 'test.module4' ), 'ready', 'Expected "ready" state for test.module4' );
+               assert.strictEqual( mw.loader.getState( 'test.module5' ), 'registered', 'Expected "registered" state for test.module5' );
+               assert.strictEqual( mw.loader.getState( 'test.module6' ), 'loaded', 'Expected "loaded" state for test.module6' );
+               mw.loader.implement( 'test.module5', function () {} );
+               assert.strictEqual( mw.loader.getState( 'test.module4' ), 'ready', 'Expected "ready" state for test.module4' );
+               assert.strictEqual( mw.loader.getState( 'test.module5' ), 'ready', 'Expected "ready" state for test.module5' );
+               assert.strictEqual( mw.loader.getState( 'test.module6' ), 'ready', 'Expected "ready" state for test.module6' );
+       } );
+
+       QUnit.test( 'Missing dependency', 13, function ( assert ) {
+               mw.loader.register( [
+                       [ 'test.module7', '0' ],
+                       [ 'test.module8', '0', [ 'test.module7' ] ],
+                       [ 'test.module9', '0', [ 'test.module8' ] ]
+               ] );
+               mw.loader.implement( 'test.module8', function () {} );
+               assert.strictEqual( mw.loader.getState( 'test.module7' ), 'registered', 'Expected "registered" state for test.module7' );
+               assert.strictEqual( mw.loader.getState( 'test.module8' ), 'loaded', 'Expected "loaded" state for test.module8' );
+               assert.strictEqual( mw.loader.getState( 'test.module9' ), 'registered', 'Expected "registered" state for test.module9' );
+               mw.loader.state( 'test.module7', 'missing' );
+               assert.strictEqual( mw.loader.getState( 'test.module7' ), 'missing', 'Expected "missing" state for test.module7' );
+               assert.strictEqual( mw.loader.getState( 'test.module8' ), 'error', 'Expected "error" state for test.module8' );
+               assert.strictEqual( mw.loader.getState( 'test.module9' ), 'error', 'Expected "error" state for test.module9' );
+               mw.loader.implement( 'test.module9', function () {} );
+               assert.strictEqual( mw.loader.getState( 'test.module7' ), 'missing', 'Expected "missing" state for test.module7' );
+               assert.strictEqual( mw.loader.getState( 'test.module8' ), 'error', 'Expected "error" state for test.module8' );
+               assert.strictEqual( mw.loader.getState( 'test.module9' ), 'error', 'Expected "error" state for test.module9' );
+               mw.loader.using(
+                       [ 'test.module7' ],
+                       function () {
+                               assert.ok( false, 'Success fired despite missing dependency' );
+                               assert.ok( true, 'QUnit expected() count dummy' );
+                       },
+                       function ( e, dependencies ) {
+                               assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
+                               assert.deepEqual( dependencies, [ 'test.module7' ], 'Error callback called with module test.module7' );
+                       }
+               );
+               mw.loader.using(
+                       [ 'test.module9' ],
+                       function () {
+                               assert.ok( false, 'Success fired despite missing dependency' );
+                               assert.ok( true, 'QUnit expected() count dummy' );
+                       },
+                       function ( e, dependencies ) {
+                               assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
+                               dependencies.sort();
+                               assert.deepEqual(
+                                       dependencies,
+                                       [ 'test.module7', 'test.module8', 'test.module9' ],
+                                       'Error callback called with all three modules as dependencies'
+                               );
+                       }
+               );
+       } );
+
+       QUnit.test( 'Dependency handling', 5, function ( assert ) {
+               var done = assert.async();
+               mw.loader.register( [
+                       // [module, version, dependencies, group, source]
+                       [ 'testMissing', '1', [], null, 'testloader' ],
+                       [ 'testUsesMissing', '1', [ 'testMissing' ], null, 'testloader' ],
+                       [ 'testUsesNestedMissing', '1', [ 'testUsesMissing' ], null, 'testloader' ]
+               ] );
+
+               function verifyModuleStates() {
+                       assert.equal( mw.loader.getState( 'testMissing' ), 'missing', 'Module not known to server must have state "missing"' );
+                       assert.equal( mw.loader.getState( 'testUsesMissing' ), 'error', 'Module with missing dependency must have state "error"' );
+                       assert.equal( mw.loader.getState( 'testUsesNestedMissing' ), 'error', 'Module with indirect missing dependency must have state "error"' );
+               }
+
+               mw.loader.using( [ 'testUsesNestedMissing' ],
+                       function () {
+                               assert.ok( false, 'Error handler should be invoked.' );
+                               assert.ok( true ); // Dummy to reach QUnit expect()
+
+                               verifyModuleStates();
+
+                               done();
+                       },
+                       function ( e, badmodules ) {
+                               assert.ok( true, 'Error handler should be invoked.' );
+                               // As soon as server spits out state('testMissing', 'missing');
+                               // it will bubble up and trigger the error callback.
+                               // Therefor the badmodules array is not testUsesMissing or testUsesNestedMissing.
+                               assert.deepEqual( badmodules, [ 'testMissing' ], 'Bad modules as expected.' );
+
+                               verifyModuleStates();
+
+                               done();
+                       }
+               );
+       } );
+
+       QUnit.test( 'Skip-function handling', 5, function ( assert ) {
+               mw.loader.register( [
+                       // [module, version, dependencies, group, source, skip]
+                       [ 'testSkipped', '1', [], null, 'testloader', 'return true;' ],
+                       [ 'testNotSkipped', '1', [], null, 'testloader', 'return false;' ],
+                       [ 'testUsesSkippable', '1', [ 'testSkipped', 'testNotSkipped' ], null, 'testloader' ]
+               ] );
+
+               function verifyModuleStates() {
+                       assert.equal( mw.loader.getState( 'testSkipped' ), 'ready', 'Module is ready when skipped' );
+                       assert.equal( mw.loader.getState( 'testNotSkipped' ), 'ready', 'Module is ready when not skipped but loaded' );
+                       assert.equal( mw.loader.getState( 'testUsesSkippable' ), 'ready', 'Module is ready when skippable dependencies are ready' );
+               }
+
+               return mw.loader.using( [ 'testUsesSkippable' ],
+                       function () {
+                               assert.ok( true, 'Success handler should be invoked.' );
+                               assert.ok( true ); // Dummy to match error handler and reach QUnit expect()
+
+                               verifyModuleStates();
+                       },
+                       function ( e, badmodules ) {
+                               assert.ok( false, 'Error handler should not be invoked.' );
+                               assert.deepEqual( badmodules, [], 'Bad modules as expected.' );
+
+                               verifyModuleStates();
+                       }
+               );
+       } );
+
+       QUnit.asyncTest( '.load( "//protocol-relative" ) - T32825', 2, function ( assert ) {
+               // This bug was actually already fixed in 1.18 and later when discovered in 1.17.
+               // Test is for regressions!
+
+               // Forge a URL to the test callback script
+               var target = QUnit.fixurl(
+                       mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/qunitOkCall.js'
+               );
+
+               // Confirm that mw.loader.load() works with protocol-relative URLs
+               target = target.replace( /https?:/, '' );
+
+               assert.equal( target.slice( 0, 2 ), '//',
+                       'URL must be relative to test relative URLs!'
+               );
+
+               // Async!
+               // The target calls QUnit.start
+               mw.loader.load( target );
+       } );
+
+       QUnit.asyncTest( '.load( "/absolute-path" )', 2, function ( assert ) {
+               // Forge a URL to the test callback script
+               var target = QUnit.fixurl(
+                       mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/qunitOkCall.js'
+               );
+
+               // Confirm that mw.loader.load() works with absolute-paths (relative to current hostname)
+               assert.equal( target.slice( 0, 1 ), '/', 'URL is relative to document root' );
+
+               // Async!
+               // The target calls QUnit.start
+               mw.loader.load( target );
+       } );
+
+       QUnit.test( 'Executing race - T112232', 2, function ( assert ) {
+               var done = false;
+
+               // The red herring schedules its CSS buffer first. In T112232, a bug in the
+               // state machine would cause the job for testRaceLoadMe to run with an earlier job.
+               mw.loader.implement(
+                       'testRaceRedHerring',
+                       function () {},
+                       { css: [ '.mw-testRaceRedHerring {}' ] }
+               );
+               mw.loader.implement(
+                       'testRaceLoadMe',
+                       function () {
+                               done = true;
+                       },
+                       { css: [ '.mw-testRaceLoadMe { float: left; }' ] }
+               );
+
+               mw.loader.load( [ 'testRaceRedHerring', 'testRaceLoadMe' ] );
+               return mw.loader.using( 'testRaceLoadMe', function () {
+                       assert.strictEqual( done, true, 'script ran' );
+                       assert.strictEqual( mw.loader.getState( 'testRaceLoadMe' ), 'ready', 'state' );
+               } );
+       } );
+
+       QUnit.test( 'require()', 6, function ( assert ) {
+               mw.loader.register( [
+                       [ 'test.require1', '0' ],
+                       [ 'test.require2', '0' ],
+                       [ 'test.require3', '0' ],
+                       [ 'test.require4', '0', [ 'test.require3' ] ]
+               ] );
+               mw.loader.implement( 'test.require1', function () {} );
+               mw.loader.implement( 'test.require2', function ( $, jQuery, require, module ) {
+                       module.exports = 1;
+               } );
+               mw.loader.implement( 'test.require3', function ( $, jQuery, require, module ) {
+                       module.exports = function () {
+                               return 'hello world';
+                       };
+               } );
+               mw.loader.implement( 'test.require4', function ( $, jQuery, require, module ) {
+                       var other = require( 'test.require3' );
+                       module.exports = {
+                               pizza: function () {
+                                       return other();
+                               }
+                       };
+               } );
+               return mw.loader.using( [ 'test.require1', 'test.require2', 'test.require3', 'test.require4' ] )
+               .then( function ( require ) {
+                       var module1, module2, module3, module4;
+
+                       module1 = require( 'test.require1' );
+                       module2 = require( 'test.require2' );
+                       module3 = require( 'test.require3' );
+                       module4 = require( 'test.require4' );
+
+                       assert.strictEqual( typeof module1, 'object', 'export of module with no export' );
+                       assert.strictEqual( module2, 1, 'export a number' );
+                       assert.strictEqual( module3(), 'hello world', 'export a function' );
+                       assert.strictEqual( typeof module4.pizza, 'function', 'export an object' );
+                       assert.strictEqual( module4.pizza(), 'hello world', 'module can require other modules' );
+
+                       assert.throws( function () {
+                               require( '_badmodule' );
+                       }, /is not loaded/, 'Requesting non-existent modules throws error.' );
+               } );
+       } );
+
+       QUnit.test( 'require() in debug mode', 1, function ( assert ) {
+               var path = mw.config.get( 'wgScriptPath' );
+               mw.loader.register( [
+                       [ 'test.require.define', '0' ],
+                       [ 'test.require.callback', '0', [ 'test.require.define' ] ]
+               ] );
+               mw.loader.implement( 'test.require.callback', [ QUnit.fixurl( path + '/tests/qunit/data/requireCallMwLoaderTestCallback.js' ) ] );
+               mw.loader.implement( 'test.require.define', [ QUnit.fixurl( path + '/tests/qunit/data/defineCallMwLoaderTestCallback.js' ) ] );
+
+               return mw.loader.using( 'test.require.callback' ).then( function ( require ) {
+                       var exported = require( 'test.require.callback' );
+                       assert.strictEqual( exported, 'Require worked.Define worked.',
+                               'module.exports worked in debug mode' );
+               }, function () {
+                       assert.ok( false, 'Error callback fired while loader.using "test.require.callback" module' );
+               } );
+       } );
+
+}( mediaWiki, jQuery ) );
index baec37c..ab463a9 100644 (file)
@@ -1,5 +1,5 @@
 /*jshint -W024 */
-( function ( mw, $ ) {
+( function ( mw ) {
        var specialCharactersPageName,
                // Can't mock SITENAME since jqueryMsg caches it at load
                siteName = mw.config.get( 'wgSiteName' );
                }
        } ) );
 
-       mw.loader.addSource(
-               'testloader',
-               QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/load.mock.php' )
-       );
-
        QUnit.test( 'Initial check', 8, function ( assert ) {
                assert.ok( window.jQuery, 'jQuery defined' );
                assert.ok( window.$, '$ defined' );
                assert.equal( mw.msg( 'int-msg' ), 'Some Other Message', 'int is resolved' );
        } );
 
-       /**
-        * The sync style load test (for @import). This is, in a way, also an open bug for
-        * ResourceLoader ("execute js after styles are loaded"), but browsers don't offer a
-        * way to get a callback from when a stylesheet is loaded (that is, including any
-        * `@import` rules inside). To work around this, we'll have a little time loop to check
-        * if the styles apply.
-        *
-        * Note: This test originally used new Image() and onerror to get a callback
-        * when the url is loaded, but that is fragile since it doesn't monitor the
-        * same request as the css @import, and Safari 4 has issues with
-        * onerror/onload not being fired at all in weird cases like this.
-        */
-       function assertStyleAsync( assert, $element, prop, val, fn ) {
-               var styleTestStart,
-                       el = $element.get( 0 ),
-                       styleTestTimeout = ( QUnit.config.testTimeout || 5000 ) - 200;
-
-               function isCssImportApplied() {
-                       // Trigger reflow, repaint, redraw, whatever (cross-browser)
-                       var x = $element.css( 'height' );
-                       x = el.innerHTML;
-                       el.className = el.className;
-                       x = document.documentElement.clientHeight;
-
-                       return $element.css( prop ) === val;
-               }
-
-               function styleTestLoop() {
-                       var styleTestSince = new Date().getTime() - styleTestStart;
-                       // If it is passing or if we timed out, run the real test and stop the loop
-                       if ( isCssImportApplied() || styleTestSince > styleTestTimeout ) {
-                               assert.equal( $element.css( prop ), val,
-                                       'style "' + prop + ': ' + val + '" from url is applied (after ' + styleTestSince + 'ms)'
-                               );
-
-                               if ( fn ) {
-                                       fn();
-                               }
-
-                               return;
-                       }
-                       // Otherwise, keep polling
-                       setTimeout( styleTestLoop );
-               }
-
-               // Start the loop
-               styleTestStart = new Date().getTime();
-               styleTestLoop();
-       }
-
-       function urlStyleTest( selector, prop, val ) {
-               return QUnit.fixurl(
-                       mw.config.get( 'wgScriptPath' ) +
-                               '/tests/qunit/data/styleTest.css.php?' +
-                               $.param( {
-                                       selector: selector,
-                                       prop: prop,
-                                       val: val
-                               } )
-               );
-       }
-
-       QUnit.test( 'mw.loader', 2, function ( assert ) {
-               var isAwesomeDone;
-
-               mw.loader.testCallback = function () {
-                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module is.awesome: isAwesomeDone should still be undefined' );
-                       isAwesomeDone = true;
-               };
-
-               mw.loader.implement( 'test.callback', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' ) ] );
-
-               return mw.loader.using( 'test.callback', function () {
-                       assert.strictEqual( isAwesomeDone, true, 'test.callback module should\'ve caused isAwesomeDone to be true' );
-                       delete mw.loader.testCallback;
-
-               }, function () {
-                       assert.ok( false, 'Error callback fired while loader.using "test.callback" module' );
-               } );
-       } );
-
-       QUnit.test( 'mw.loader with Object method as module name', 2, function ( assert ) {
-               var isAwesomeDone;
-
-               mw.loader.testCallback = function () {
-                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module hasOwnProperty: isAwesomeDone should still be undefined' );
-                       isAwesomeDone = true;
-               };
-
-               mw.loader.implement( 'hasOwnProperty', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' ) ], {}, {} );
-
-               return mw.loader.using( 'hasOwnProperty', function () {
-                       assert.strictEqual( isAwesomeDone, true, 'hasOwnProperty module should\'ve caused isAwesomeDone to be true' );
-                       delete mw.loader.testCallback;
-
-               }, function () {
-                       assert.ok( false, 'Error callback fired while loader.using "hasOwnProperty" module' );
-               } );
-       } );
-
-       QUnit.test( 'mw.loader.using( .. ) Promise', 2, function ( assert ) {
-               var isAwesomeDone;
-
-               mw.loader.testCallback = function () {
-                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module is.awesome: isAwesomeDone should still be undefined' );
-                       isAwesomeDone = true;
-               };
-
-               mw.loader.implement( 'test.promise', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' ) ] );
-
-               return mw.loader.using( 'test.promise' )
-               .done( function () {
-                       assert.strictEqual( isAwesomeDone, true, 'test.promise module should\'ve caused isAwesomeDone to be true' );
-                       delete mw.loader.testCallback;
-
-               } )
-               .fail( function () {
-                       assert.ok( false, 'Error callback fired while loader.using "test.promise" module' );
-               } );
-       } );
-
-       QUnit.test( 'mw.loader.implement( styles={ "css": [text, ..] } )', 2, function ( assert ) {
-               var $element = $( '<div class="mw-test-implement-a"></div>' ).appendTo( '#qunit-fixture' );
-
-               assert.notEqual(
-                       $element.css( 'float' ),
-                       'right',
-                       'style is clear'
-               );
-
-               mw.loader.implement(
-                       'test.implement.a',
-                       function () {
-                               assert.equal(
-                                       $element.css( 'float' ),
-                                       'right',
-                                       'style is applied'
-                               );
-                       },
-                       {
-                               all: '.mw-test-implement-a { float: right; }'
-                       }
-               );
-
-               return mw.loader.using( 'test.implement.a' );
-       } );
-
-       QUnit.test( 'mw.loader.implement( styles={ "url": { <media>: [url, ..] } } )', 7, function ( assert ) {
-               var $element1 = $( '<div class="mw-test-implement-b1"></div>' ).appendTo( '#qunit-fixture' ),
-                       $element2 = $( '<div class="mw-test-implement-b2"></div>' ).appendTo( '#qunit-fixture' ),
-                       $element3 = $( '<div class="mw-test-implement-b3"></div>' ).appendTo( '#qunit-fixture' ),
-                       done = assert.async();
-
-               assert.notEqual(
-                       $element1.css( 'text-align' ),
-                       'center',
-                       'style is clear'
-               );
-               assert.notEqual(
-                       $element2.css( 'float' ),
-                       'left',
-                       'style is clear'
-               );
-               assert.notEqual(
-                       $element3.css( 'text-align' ),
-                       'right',
-                       'style is clear'
-               );
-
-               mw.loader.implement(
-                       'test.implement.b',
-                       function () {
-                               // Note: done() must only be called when the entire test is
-                               // complete. So, make sure that we don't start until *both*
-                               // assertStyleAsync calls have completed.
-                               var pending = 2;
-                               assertStyleAsync( assert, $element2, 'float', 'left', function () {
-                                       assert.notEqual( $element1.css( 'text-align' ), 'center', 'print style is not applied' );
-
-                                       pending--;
-                                       if ( pending === 0 ) {
-                                               done();
-                                       }
-                               } );
-                               assertStyleAsync( assert, $element3, 'float', 'right', function () {
-                                       assert.notEqual( $element1.css( 'text-align' ), 'center', 'print style is not applied' );
-
-                                       pending--;
-                                       if ( pending === 0 ) {
-                                               done();
-                                       }
-                               } );
-                       },
-                       {
-                               url: {
-                                       print: [ urlStyleTest( '.mw-test-implement-b1', 'text-align', 'center' ) ],
-                                       screen: [
-                                               // bug 40834: Make sure it actually works with more than 1 stylesheet reference
-                                               urlStyleTest( '.mw-test-implement-b2', 'float', 'left' ),
-                                               urlStyleTest( '.mw-test-implement-b3', 'float', 'right' )
-                                       ]
-                               }
-                       }
-               );
-
-               mw.loader.load( 'test.implement.b' );
-       } );
-
-       // Backwards compatibility
-       QUnit.test( 'mw.loader.implement( styles={ <media>: text } ) (back-compat)', 2, function ( assert ) {
-               var $element = $( '<div class="mw-test-implement-c"></div>' ).appendTo( '#qunit-fixture' );
-
-               assert.notEqual(
-                       $element.css( 'float' ),
-                       'right',
-                       'style is clear'
-               );
-
-               mw.loader.implement(
-                       'test.implement.c',
-                       function () {
-                               assert.equal(
-                                       $element.css( 'float' ),
-                                       'right',
-                                       'style is applied'
-                               );
-                       },
-                       {
-                               all: '.mw-test-implement-c { float: right; }'
-                       }
-               );
-
-               return mw.loader.using( 'test.implement.c' );
-       } );
-
-       // Backwards compatibility
-       QUnit.test( 'mw.loader.implement( styles={ <media>: [url, ..] } ) (back-compat)', 4, function ( assert ) {
-               var $element = $( '<div class="mw-test-implement-d"></div>' ).appendTo( '#qunit-fixture' ),
-                       $element2 = $( '<div class="mw-test-implement-d2"></div>' ).appendTo( '#qunit-fixture' ),
-                       done = assert.async();
-
-               assert.notEqual(
-                       $element.css( 'float' ),
-                       'right',
-                       'style is clear'
-               );
-               assert.notEqual(
-                       $element2.css( 'text-align' ),
-                       'center',
-                       'style is clear'
-               );
-
-               mw.loader.implement(
-                       'test.implement.d',
-                       function () {
-                               assertStyleAsync( assert, $element, 'float', 'right', function () {
-                                       assert.notEqual( $element2.css( 'text-align' ), 'center', 'print style is not applied (bug 40500)' );
-                                       done();
-                               } );
-                       },
-                       {
-                               all: [ urlStyleTest( '.mw-test-implement-d', 'float', 'right' ) ],
-                               print: [ urlStyleTest( '.mw-test-implement-d2', 'text-align', 'center' ) ]
-                       }
-               );
-
-               mw.loader.load( 'test.implement.d' );
-       } );
-
-       // @import (bug 31676)
-       QUnit.test( 'mw.loader.implement( styles has @import )', 7, function ( assert ) {
-               var isJsExecuted, $element,
-                       done = assert.async();
-
-               mw.loader.implement(
-                       'test.implement.import',
-                       function () {
-                               assert.strictEqual( isJsExecuted, undefined, 'script not executed multiple times' );
-                               isJsExecuted = true;
-
-                               assert.equal( mw.loader.getState( 'test.implement.import' ), 'executing', 'module state during implement() script execution' );
-
-                               $element = $( '<div class="mw-test-implement-import">Foo bar</div>' ).appendTo( '#qunit-fixture' );
-
-                               assert.equal( mw.msg( 'test-foobar' ), 'Hello Foobar, $1!', 'messages load before script execution' );
-
-                               assertStyleAsync( assert, $element, 'float', 'right', function () {
-                                       assert.equal( $element.css( 'text-align' ), 'center',
-                                               'CSS styles after the @import rule are working'
-                                       );
-
-                                       done();
-                               } );
-                       },
-                       {
-                               css: [
-                                       '@import url(\''
-                                               + urlStyleTest( '.mw-test-implement-import', 'float', 'right' )
-                                               + '\');\n'
-                                               + '.mw-test-implement-import { text-align: center; }'
-                               ]
-                       },
-                       {
-                               'test-foobar': 'Hello Foobar, $1!'
-                       }
-               );
-
-               mw.loader.using( 'test.implement.import' ).always( function () {
-                       assert.strictEqual( isJsExecuted, true, 'script executed' );
-                       assert.equal( mw.loader.getState( 'test.implement.import' ), 'ready', 'module state after script execution' );
-               } );
-       } );
-
-       QUnit.test( 'mw.loader.implement( dependency with styles )', 4, function ( assert ) {
-               var $element = $( '<div class="mw-test-implement-e"></div>' ).appendTo( '#qunit-fixture' ),
-                       $element2 = $( '<div class="mw-test-implement-e2"></div>' ).appendTo( '#qunit-fixture' );
-
-               assert.notEqual(
-                       $element.css( 'float' ),
-                       'right',
-                       'style is clear'
-               );
-               assert.notEqual(
-                       $element2.css( 'float' ),
-                       'left',
-                       'style is clear'
-               );
-
-               mw.loader.register( [
-                       [ 'test.implement.e', '0', [ 'test.implement.e2' ] ],
-                       [ 'test.implement.e2', '0' ]
-               ] );
-
-               mw.loader.implement(
-                       'test.implement.e',
-                       function () {
-                               assert.equal(
-                                       $element.css( 'float' ),
-                                       'right',
-                                       'Depending module\'s style is applied'
-                               );
-                       },
-                       {
-                               all: '.mw-test-implement-e { float: right; }'
-                       }
-               );
-
-               mw.loader.implement(
-                       'test.implement.e2',
-                       function () {
-                               assert.equal(
-                                       $element2.css( 'float' ),
-                                       'left',
-                                       'Dependency\'s style is applied'
-                               );
-                       },
-                       {
-                               all: '.mw-test-implement-e2 { float: left; }'
-                       }
-               );
-
-               return mw.loader.using( 'test.implement.e' );
-       } );
-
-       QUnit.test( 'mw.loader.implement( only scripts )', 1, function ( assert ) {
-               mw.loader.implement( 'test.onlyscripts', function () {} );
-               assert.strictEqual( mw.loader.getState( 'test.onlyscripts' ), 'ready' );
-       } );
-
-       QUnit.test( 'mw.loader.implement( only messages )', 2, function ( assert ) {
-               assert.assertFalse( mw.messages.exists( 'bug_29107' ), 'Verify that the test message doesn\'t exist yet' );
-
-               // jscs: disable requireCamelCaseOrUpperCaseIdentifiers
-               mw.loader.implement( 'test.implement.msgs', [], {}, { bug_29107: 'loaded' } );
-               // jscs: enable requireCamelCaseOrUpperCaseIdentifiers
-
-               return mw.loader.using( 'test.implement.msgs', function () {
-                       assert.ok( mw.messages.exists( 'bug_29107' ), 'Bug 29107: messages-only module should implement ok' );
-               }, function () {
-                       assert.ok( false, 'Error callback fired while implementing "test.implement.msgs" module' );
-               } );
-       } );
-
-       QUnit.test( 'mw.loader.implement( empty )', 1, function ( assert ) {
-               mw.loader.implement( 'test.empty' );
-               assert.strictEqual( mw.loader.getState( 'test.empty' ), 'ready' );
-       } );
-
-       QUnit.test( 'mw.loader with broken indirect dependency', 4, function ( assert ) {
-               // don't emit an error event
-               this.sandbox.stub( mw, 'track' );
-
-               mw.loader.register( [
-                       [ 'test.module1', '0' ],
-                       [ 'test.module2', '0', [ 'test.module1' ] ],
-                       [ 'test.module3', '0', [ 'test.module2' ] ]
-               ] );
-               mw.loader.implement( 'test.module1', function () {
-                       throw new Error( 'expected' );
-               }, {}, {} );
-               assert.strictEqual( mw.loader.getState( 'test.module1' ), 'error', 'Expected "error" state for test.module1' );
-               assert.strictEqual( mw.loader.getState( 'test.module2' ), 'error', 'Expected "error" state for test.module2' );
-               assert.strictEqual( mw.loader.getState( 'test.module3' ), 'error', 'Expected "error" state for test.module3' );
-
-               assert.strictEqual( mw.track.callCount, 1 );
-       } );
-
-       QUnit.test( 'mw.loader with circular dependency', 1, function ( assert ) {
-               mw.loader.register( [
-                       [ 'test.circle1', '0', [ 'test.circle2' ] ],
-                       [ 'test.circle2', '0', [ 'test.circle3' ] ],
-                       [ 'test.circle3', '0', [ 'test.circle1' ] ]
-               ] );
-               assert.throws( function () {
-                       mw.loader.using( 'test.circle3' );
-               }, /Circular/, 'Detect circular dependency' );
-       } );
-
-       QUnit.test( 'mw.loader out-of-order implementation', 9, function ( assert ) {
-               mw.loader.register( [
-                       [ 'test.module4', '0' ],
-                       [ 'test.module5', '0', [ 'test.module4' ] ],
-                       [ 'test.module6', '0', [ 'test.module5' ] ]
-               ] );
-               mw.loader.implement( 'test.module4', function () {} );
-               assert.strictEqual( mw.loader.getState( 'test.module4' ), 'ready', 'Expected "ready" state for test.module4' );
-               assert.strictEqual( mw.loader.getState( 'test.module5' ), 'registered', 'Expected "registered" state for test.module5' );
-               assert.strictEqual( mw.loader.getState( 'test.module6' ), 'registered', 'Expected "registered" state for test.module6' );
-               mw.loader.implement( 'test.module6', function () {} );
-               assert.strictEqual( mw.loader.getState( 'test.module4' ), 'ready', 'Expected "ready" state for test.module4' );
-               assert.strictEqual( mw.loader.getState( 'test.module5' ), 'registered', 'Expected "registered" state for test.module5' );
-               assert.strictEqual( mw.loader.getState( 'test.module6' ), 'loaded', 'Expected "loaded" state for test.module6' );
-               mw.loader.implement( 'test.module5', function () {} );
-               assert.strictEqual( mw.loader.getState( 'test.module4' ), 'ready', 'Expected "ready" state for test.module4' );
-               assert.strictEqual( mw.loader.getState( 'test.module5' ), 'ready', 'Expected "ready" state for test.module5' );
-               assert.strictEqual( mw.loader.getState( 'test.module6' ), 'ready', 'Expected "ready" state for test.module6' );
-       } );
-
-       QUnit.test( 'mw.loader missing dependency', 13, function ( assert ) {
-               mw.loader.register( [
-                       [ 'test.module7', '0' ],
-                       [ 'test.module8', '0', [ 'test.module7' ] ],
-                       [ 'test.module9', '0', [ 'test.module8' ] ]
-               ] );
-               mw.loader.implement( 'test.module8', function () {} );
-               assert.strictEqual( mw.loader.getState( 'test.module7' ), 'registered', 'Expected "registered" state for test.module7' );
-               assert.strictEqual( mw.loader.getState( 'test.module8' ), 'loaded', 'Expected "loaded" state for test.module8' );
-               assert.strictEqual( mw.loader.getState( 'test.module9' ), 'registered', 'Expected "registered" state for test.module9' );
-               mw.loader.state( 'test.module7', 'missing' );
-               assert.strictEqual( mw.loader.getState( 'test.module7' ), 'missing', 'Expected "missing" state for test.module7' );
-               assert.strictEqual( mw.loader.getState( 'test.module8' ), 'error', 'Expected "error" state for test.module8' );
-               assert.strictEqual( mw.loader.getState( 'test.module9' ), 'error', 'Expected "error" state for test.module9' );
-               mw.loader.implement( 'test.module9', function () {} );
-               assert.strictEqual( mw.loader.getState( 'test.module7' ), 'missing', 'Expected "missing" state for test.module7' );
-               assert.strictEqual( mw.loader.getState( 'test.module8' ), 'error', 'Expected "error" state for test.module8' );
-               assert.strictEqual( mw.loader.getState( 'test.module9' ), 'error', 'Expected "error" state for test.module9' );
-               mw.loader.using(
-                       [ 'test.module7' ],
-                       function () {
-                               assert.ok( false, 'Success fired despite missing dependency' );
-                               assert.ok( true, 'QUnit expected() count dummy' );
-                       },
-                       function ( e, dependencies ) {
-                               assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
-                               assert.deepEqual( dependencies, [ 'test.module7' ], 'Error callback called with module test.module7' );
-                       }
-               );
-               mw.loader.using(
-                       [ 'test.module9' ],
-                       function () {
-                               assert.ok( false, 'Success fired despite missing dependency' );
-                               assert.ok( true, 'QUnit expected() count dummy' );
-                       },
-                       function ( e, dependencies ) {
-                               assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
-                               dependencies.sort();
-                               assert.deepEqual(
-                                       dependencies,
-                                       [ 'test.module7', 'test.module8', 'test.module9' ],
-                                       'Error callback called with all three modules as dependencies'
-                               );
-                       }
-               );
-       } );
-
-       QUnit.test( 'mw.loader dependency handling', 5, function ( assert ) {
-               var done = assert.async();
-               mw.loader.register( [
-                       // [module, version, dependencies, group, source]
-                       [ 'testMissing', '1', [], null, 'testloader' ],
-                       [ 'testUsesMissing', '1', [ 'testMissing' ], null, 'testloader' ],
-                       [ 'testUsesNestedMissing', '1', [ 'testUsesMissing' ], null, 'testloader' ]
-               ] );
-
-               function verifyModuleStates() {
-                       assert.equal( mw.loader.getState( 'testMissing' ), 'missing', 'Module not known to server must have state "missing"' );
-                       assert.equal( mw.loader.getState( 'testUsesMissing' ), 'error', 'Module with missing dependency must have state "error"' );
-                       assert.equal( mw.loader.getState( 'testUsesNestedMissing' ), 'error', 'Module with indirect missing dependency must have state "error"' );
-               }
-
-               mw.loader.using( [ 'testUsesNestedMissing' ],
-                       function () {
-                               assert.ok( false, 'Error handler should be invoked.' );
-                               assert.ok( true ); // Dummy to reach QUnit expect()
-
-                               verifyModuleStates();
-
-                               done();
-                       },
-                       function ( e, badmodules ) {
-                               assert.ok( true, 'Error handler should be invoked.' );
-                               // As soon as server spits out state('testMissing', 'missing');
-                               // it will bubble up and trigger the error callback.
-                               // Therefor the badmodules array is not testUsesMissing or testUsesNestedMissing.
-                               assert.deepEqual( badmodules, [ 'testMissing' ], 'Bad modules as expected.' );
-
-                               verifyModuleStates();
-
-                               done();
-                       }
-               );
-       } );
-
-       QUnit.test( 'mw.loader skin-function handling', 5, function ( assert ) {
-               mw.loader.register( [
-                       // [module, version, dependencies, group, source, skip]
-                       [ 'testSkipped', '1', [], null, 'testloader', 'return true;' ],
-                       [ 'testNotSkipped', '1', [], null, 'testloader', 'return false;' ],
-                       [ 'testUsesSkippable', '1', [ 'testSkipped', 'testNotSkipped' ], null, 'testloader' ]
-               ] );
-
-               function verifyModuleStates() {
-                       assert.equal( mw.loader.getState( 'testSkipped' ), 'ready', 'Module is ready when skipped' );
-                       assert.equal( mw.loader.getState( 'testNotSkipped' ), 'ready', 'Module is ready when not skipped but loaded' );
-                       assert.equal( mw.loader.getState( 'testUsesSkippable' ), 'ready', 'Module is ready when skippable dependencies are ready' );
-               }
-
-               return mw.loader.using( [ 'testUsesSkippable' ],
-                       function () {
-                               assert.ok( true, 'Success handler should be invoked.' );
-                               assert.ok( true ); // Dummy to match error handler and reach QUnit expect()
-
-                               verifyModuleStates();
-                       },
-                       function ( e, badmodules ) {
-                               assert.ok( false, 'Error handler should not be invoked.' );
-                               assert.deepEqual( badmodules, [], 'Bad modules as expected.' );
-
-                               verifyModuleStates();
-                       }
-               );
-       } );
-
-       QUnit.asyncTest( 'mw.loader( "//protocol-relative" ) (bug 30825)', 2, function ( assert ) {
-               // This bug was actually already fixed in 1.18 and later when discovered in 1.17.
-               // Test is for regressions!
-
-               // Forge a URL to the test callback script
-               var target = QUnit.fixurl(
-                       mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/qunitOkCall.js'
-               );
-
-               // Confirm that mw.loader.load() works with protocol-relative URLs
-               target = target.replace( /https?:/, '' );
-
-               assert.equal( target.slice( 0, 2 ), '//',
-                       'URL must be relative to test relative URLs!'
-               );
-
-               // Async!
-               // The target calls QUnit.start
-               mw.loader.load( target );
-       } );
-
-       QUnit.asyncTest( 'mw.loader( "/absolute-path" )', 2, function ( assert ) {
-               // Forge a URL to the test callback script
-               var target = QUnit.fixurl(
-                       mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/qunitOkCall.js'
-               );
-
-               // Confirm that mw.loader.load() works with absolute-paths (relative to current hostname)
-               assert.equal( target.slice( 0, 1 ), '/', 'URL is relative to document root' );
-
-               // Async!
-               // The target calls QUnit.start
-               mw.loader.load( target );
-       } );
-
-       QUnit.test( 'mw.loader() executing race (T112232)', 2, function ( assert ) {
-               var done = false;
-
-               // The red herring schedules its CSS buffer first. In T112232, a bug in the
-               // state machine would cause the job for testRaceLoadMe to run with an earlier job.
-               mw.loader.implement(
-                       'testRaceRedHerring',
-                       function () {},
-                       { css: [ '.mw-testRaceRedHerring {}' ] }
-               );
-               mw.loader.implement(
-                       'testRaceLoadMe',
-                       function () {
-                               done = true;
-                       },
-                       { css: [ '.mw-testRaceLoadMe { float: left; }' ] }
-               );
-
-               mw.loader.load( [ 'testRaceRedHerring', 'testRaceLoadMe' ] );
-               return mw.loader.using( 'testRaceLoadMe', function () {
-                       assert.strictEqual( done, true, 'script ran' );
-                       assert.strictEqual( mw.loader.getState( 'testRaceLoadMe' ), 'ready', 'state' );
-               } );
-       } );
-
        QUnit.test( 'mw.hook', 13, function ( assert ) {
                var hook, add, fire, chars, callback;
 
                );
        } );
 
-       QUnit.test( 'mw.loader require()', 6, function ( assert ) {
-               mw.loader.register( [
-                       [ 'test.require1', '0' ],
-                       [ 'test.require2', '0' ],
-                       [ 'test.require3', '0' ],
-                       [ 'test.require4', '0', [ 'test.require3' ] ]
-               ] );
-               mw.loader.implement( 'test.require1', function () {} );
-               mw.loader.implement( 'test.require2', function ( $, jQuery, require, module ) {
-                       module.exports = 1;
-               } );
-               mw.loader.implement( 'test.require3', function ( $, jQuery, require, module ) {
-                       module.exports = function () {
-                               return 'hello world';
-                       };
-               } );
-               mw.loader.implement( 'test.require4', function ( $, jQuery, require, module ) {
-                       var other = require( 'test.require3' );
-                       module.exports = {
-                               pizza: function () {
-                                       return other();
-                               }
-                       };
-               } );
-               return mw.loader.using( [ 'test.require1', 'test.require2', 'test.require3', 'test.require4' ] )
-               .then( function ( require ) {
-                       var module1, module2, module3, module4;
-
-                       module1 = require( 'test.require1' );
-                       module2 = require( 'test.require2' );
-                       module3 = require( 'test.require3' );
-                       module4 = require( 'test.require4' );
-
-                       assert.strictEqual( typeof module1, 'object', 'export of module with no export' );
-                       assert.strictEqual( module2, 1, 'export a number' );
-                       assert.strictEqual( module3(), 'hello world', 'export a function' );
-                       assert.strictEqual( typeof module4.pizza, 'function', 'export an object' );
-                       assert.strictEqual( module4.pizza(), 'hello world', 'module can require other modules' );
-
-                       assert.throws( function () {
-                               require( '_badmodule' );
-                       }, /is not loaded/, 'Requesting non-existent modules throws error.' );
-               } );
-       } );
-
-       QUnit.test( 'mw.loader require() in debug mode', 1, function ( assert ) {
-               var path = mw.config.get( 'wgScriptPath' );
-               mw.loader.register( [
-                       [ 'test.require.define', '0' ],
-                       [ 'test.require.callback', '0', [ 'test.require.define' ] ]
-               ] );
-               mw.loader.implement( 'test.require.callback', [ QUnit.fixurl( path + '/tests/qunit/data/requireCallMwLoaderTestCallback.js' ) ] );
-               mw.loader.implement( 'test.require.define', [ QUnit.fixurl( path + '/tests/qunit/data/defineCallMwLoaderTestCallback.js' ) ] );
-
-               return mw.loader.using( 'test.require.callback' ).then( function ( require ) {
-                       var exported = require( 'test.require.callback' );
-                       assert.strictEqual( exported, 'Require worked.Define worked.',
-                               'module.exports worked in debug mode' );
-               }, function () {
-                       assert.ok( false, 'Error callback fired while loader.using "test.require.callback" module' );
-               } );
-       } );
-
-}( mediaWiki, jQuery ) );
+}( mediaWiki ) );